Dzisiaj pokażę jak powstawał jeden z wykresów z poprzedniego wpisu n.t. otyłości. Ponieważ ma być bardziej warsztatowo to opowiem też jak wybierałem kolory i dlaczego wykres jest w poziomie.
Do wczytania danych wykorzystamy pakiet SmarterPoland
dla programu R. Funkcją getEurostatRCV()
wczytujemy tabelę z danymi o grupach BMI o nazwie hlth_ehis_de1
.
1 2 3 4 5 6 7 8 9 10 11 12 | library(Cairo) library(SmarterPoland) summary(tmp1 <- getEurostatRCV("hlth_ehis_de1")) ## time bmi sex age geo isced97 value ## 2008:9335 18P5-25:2375 F:3145 TOTAL :1080 AT : 540 TOTAL :1867 Min. : 0.10 ## 25-30 :2375 M:3015 Y18-24 :1080 BE : 540 ED0-2 :1867 1st Qu.: 7.80 ## GE30 :2370 T:3175 Y25-34 :1075 DE : 540 ED3_4 :1867 Median :24.80 ## LT18P5 :2215 Y45-54 :1075 ES : 540 ED5_6 :1867 Mean :26.38 ## Y35-44 :1060 FR : 540 UNK :1867 3rd Qu.:41.30 ## Y65-74 :1055 HU : 540 Max. :92.20 ## (Other):2910 (Other):6095 NA's :2685 |
Kolejne kolumny wczytanych danych informują o time
roku badania, bmi
grupie BMI (niedowaga, prawidłowa waga, nadwaga i otyłość), sex
płci (T
oznacza bez podziału na płeć), age
wieku (TOTAL
oznacza bez podziału na grupy wiekowe), geo
czyli kraj, isced97
czyli wykształcenie i value
czyli procent osób w danej grupie BMI wśród podpopulacji określonej przez pozostałe zmienne. Dane są w postaci luźnej, zwanej też rzadką, więc na zwykłą tabelę zamienimy je funkcją cast
.
Poniższa instrukcja buduje tablicę krzyżową dla rozkładu bmi w grupach określonych przez płeć i wiek, bez podziału na wykształcenie i tylko dla Polski.
13 14 15 16 17 18 19 20 21 22 | wskR2008 <- na.omit(cast(tmp1, sex + age ~ bmi, mean, subset = isced97 == "TOTAL " & sex != "T" & age != "TOTAL" & geo == "PL")) head(wskR2008) ## sex age 18P5-25 25-30 GE30 LT18P5 ## 1 F Y_GE85 44.0 36.2 17.0 2.8 ## 2 F Y18-24 74.5 10.9 2.1 12.6 ## 3 F Y25-34 70.9 17.2 5.3 6.7 ## 4 F Y35-44 59.5 28.1 10.1 2.3 ## 5 F Y45-54 44.0 36.5 17.9 1.7 ## 6 F Y55-64 31.3 39.1 28.4 1.2 |
Mamy tabelę krzyżową, zabieramy się do jej wizualizacji. Chcę do tego wykorzystać wykres paskowy, czyli funkcję barplot()
. Każdy wiersz obiektu wskR2008
opisuje procentowy udział osób z BMI 18.5-25, 25-30, >30, <18.5 w grupie o określonej płci i wieku.
Więc aby użyć funkcji barplot()
muszę ten obiekt transponować. Ponieważ na wykresie chciałbym mieć i wiersze i kolumny w innej kolejności więc muszę je przeindeksować (kolumny chciałbym od niedowagi do otyłości a wiersze od najmłodszej do najstarszej grupy wiekowej i najpierw mężczyźni a później kobiety). Obie te transformację mogę osiągnąć instrukcją t(wskR2008[c(10:16, 9, 2:8, 1), c(6, 3, 4, 5)])
.
Nie wiedzieć czemu funkcja barplot() rysuje domyślnie wykres pionowo, choć znacznie czytelniejszy jest gdy jest rysowany poziomo. Zmianę kierunku osiągnąć można argumentem horiz = T
.
Z technicznych przyczyn potrzebuję usunąć etykiety z osi OX a etykiety na osi OY wpisać poziomo, obie te rzeczy wymagają dodania argumentów las = 1, xaxt = "n"
.
I najciekawsze, czyli kolory.
Potrzebuję kolorów do określenia niedowagi, wagi prawidłowej, nadwagi i otyłości. Szukając kolorów wygodnie jest korzystać z nazw kolorów a nie z kodów RBG. Pisząc książkę ,,Przewodnik po pakiecie R” opracowałem mapę kolorów dostępną tutaj. Z niej wybierałem kolory do tej wizualizacji.
Waga prawidłowa kojarzy się z kolorem zielonym, poprawnym. Jaki odcień? Zbyt ciemny wygląda mało ciekawie, zbyt jaskrawy razi oczy i nie pozwala się skupić. Koniec końców wybrałem kolor "chartreuse2"
.
Dla otyłości chciałem wybrać któryś z odcieni czerwieni. Ciemne odcienie nie podobały mi się, bo były za mało alarmujące, a otyłość powinna być alarmująca. Po kilku eksperymentach wybór zawęziłem do "orangered1", "red1" i "firebrick1"
a ostatecznie wybór padł na "red1"
choć nie potrafię tego uzasadnić, po prostu podobał mi się najbardziej.
Z nadwagą poszło najłatwiej, pomiędzy zielenią a czerwienią powinien być kolor ostrzegawczy, żółty. A kolor "yellow1"
jest wyrazisty więc był jedynym kandydatem (ok, tak naprawdę próbowałem też "gold"
ale to była pomyłka).
Dla niedowagi potrzebne było coś kontrastujące z otyłością, więc jakiś odcień niebieskiego. Oko ludzkie z rozróżnianiem odcieni niebieskiego marnie sobie radzi. Ale R w palecie nazw kolorów ma wiele różnych odcieni błękitu więc wybierać trzeba. Zwykły niebieski "blue"
jest zbyt dominujący, psuł kolor zielony sąsiedniego paska. Koniec końców z serii "lightskyblue"
i "slategray"
wybrałem "slategray2"
.
Drobnym, ale myślę że potrzebnym dodatkiem były pomocnicze pionowe linie siatki. Aby były widoczne ale nie narzucające się użyłem koloru szarego z włączonym kanałem alfa, czyli kolor o kodzie RGB "#77777730"
.
Ostatnie detale dla wykresu to zmiana marginesów (funkcja par), dodanie legendy (funkcja legend) i osi OX (funkcja axis) na której chciałbym by były procenty. I pierwsza wersja wykresu gotowa.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | nazwy <- c("Kobiety/ >85", "Kobiety/18-24", "Kobiety/25-34", "Kobiety/35-44", "Kobiety/45-54", "Kobiety/55-64", "Kobiety/65-74", "Kobiety/75-84", "Mężczyźni/ >85", "Mężczyźni/18-24", "Mężczyźni/25-34", "Mężczyźni/35-44", "Mężczyźni/45-54", "Mężczyźni/55-64", "Mężczyźni/65-74", "Mężczyźni/75-84") par(mar = c(5, 10, 3, 3)) barplot(t(wskR2008[c(10:16, 9, 2:8, 1), c(6, 3, 4, 5)]), names.arg = nazwy[c(10:16, 9, 2:8, 1)], horiz = T, las = 1, col = c("slategray2", "chartreuse2", "yellow1", "red1"), xaxt = "n", main = "BMI a wiek, Polacy w 2008 roku") axis(1, at = seq(0, 100, 10), paste(seq(0, 100, 10), "%", sep = "")) abline(v = seq(0, 100, 10), col = "#77777730") par(xpd = NA) legend(17, 20.8, c("niedowaga", "prawidłowa waga", "nadwaga", "otyłość"), bty = "n", fill = c("slategray2", "chartreuse2", "yellow1", "red1"), ncol = 4) |