--- title: "Podstawy grafiki w R" author: "Bartosz Maćkiewicz" subtitle: Statystyka I z R output: pdf_document: default html_document: default --- # Metafora płótna W R dostępnych jest wiele bibliotek do tworzenia wykresów. My w tej części kursu zajmiemy się podstawową, wbudowaną w R biblioteką nazwaną `graphics`. O rysowaniu wykresów w R możemy myśleć jak o rysowaniu wykresów na płótnie. Płótno podzielone jest na kilka obszarów. Obszary rysowania wyglądają mniej więcej tak: ![Obszary rysowania](custombase-baseregions1fig.png) Zwykle rysować będziemy na środkowym polu, a martwienie o pozostałe pola, takie zostawimy R. Funkcje służące do rysowania w R możemy podzielić z grubsza na dwa typy. Pierwszy to funkcje wysokiego poziomu, drugi to funkcje niskiego poziomu. ## Funkcje wysokiego poziomu. Funkcje wysokiego poziomu co do zasady rysują cały wykres, to znaczy zarówno same kształty na wykresie jak i legendę, podpisy, ramki, osie, oznaczenia osi, tytuły, podtytuły itp. Przykładami funkcji wysokiego poziomu są funkcje `plot` (rysuje różne wykresy w zależności od przekazanych do funkcji danych) i `hist` (rysuje histogram). ## Funkcje niskiego poziomu. Funkcje nieskiego poziomu rysują określone kształty, najczęściej na już narysowanych wykresach. Przydają się do ulepszania i modyfikowania wykresów już stworzonych za pomoca funkcji wysokiego poziomu, ale mogą też służyć do narysowania czegoś "od zera". Przykłady takich funkcji to `abline` (nakłada na wykres linię), `points` (nakłada na wykres punkty) lub `text` (nakłada na wykres tekst). # Funkcja `plot` Spróbujmy stworzyć najprostszy wykres punktowy (*scatterplot*, czasami po polsku również *wykres rozrzutu*). Użyjemy do tego znanego już z ćwiczeń domowych zbioru danych z bobrami i spróbujemy na wykresie zilustrować to, jak zmieniała się temperatura bobra w czasie. Zobaczymy również różne rodzaje wykresów (argument `type` - za pomocą `?plot` można dowiedzieć się, jakie inne wartości może przyjmować) oraz jak określić tytuł wykresu (argument `main`). W tym ćwiczeniu skorzystamy jedynie z podzbioru ramki danych `beaver1`. Chcemy użyć obserwacji pochodzącego z pierwszego dnia pomiarów. ```{r} data(beavers) beav <- beaver1[beaver1$day == 346, ] # wybieramy tylko dzień 346 # Zobaczymy jak wyglądają dane, które przekazujemy funkcji `plot` head(beav) ``` Funkcja `plot` w podstawowej formie przyjmuje dwa argumenty. Pierwszy to wektor ze współrzędnymi punktów na osi X, drugi to wektor ze współrzednymi punktów na osi Y. Poniżej znajdują się przykłady różnych typów wykresów. ```{r} plot(beav$time, beav$temp, main = "Typ domyślny") plot(beav$time, beav$temp, type='b', main = "Typ 'b'") plot(beav$time, beav$temp, type='l', main = "Typ 'l'") plot(beav$time, beav$temp, type='o', main = "Typ 'o'") plot(beav$time, beav$temp, type='o', axes = F, main = "Typ 'o' bez osi") ``` Spróbujmy nałożyć oba bobry na jeden wykres. Zrobimy to tworząc pierwszy z nich za pomocą funkcji wysokiego `plot`, a drugi za pomocą funkcji niskiego poziomu `points`. Funkcja `points` przyjmuje w zasadzie te same argumenty co `plot` ale rysuje wyłącznie punkty (a nie np. osie, podpisy itp.). W przypadku danych ze zbioru `beaver2` również skorzystamy z jednego dnia pomiarów. ```{r} # wybieramy dane drugiego bobra z jednego dnia pomiarów beav2 <- beaver2[beaver2$day == 307, ] plot(beav$time, beav$temp, type='o', main='Temperatura bobrów', # główny tytuł wykresu sub='Bóbr 1 dzień 346 vs bóbr 2 dzień 307', # podtytuł wykresu col='Red', # kolor punktów ) points(beav2$time, beav2$temp, type='o', col='Blue') ``` Niestety, niebieski bóbr wychodzi poza marginesy rysunku. Aby temu zapobiec, musimy ustawić skalę na osi Y tak, by obejmowała minimalne i maksymalne wartości obu bobór. W naszym przypadku R automatycznie dobiera wartości na Y tak, by mieścił się tylko pierwszy rysowany bóbr. Spróbujemy zmienić to zachowanie za pomocą argumenty `ylim`. ```{r} plot(beav$time, beav$temp, type='o', main='Temperatura bobrów', sub='Bóbr 1 dzień 346 vs bóbr 2 dzień 307', col='Red', ylim = c(min(c(beav$temp, beav2$temp)), # najmniejsza obserwacja dla obu bobrów max(c(beav$temp, beav2$temp))) # największa obserwacja dla obu bobrów ) points(beav2$time, beav2$temp, type='o', col='Blue') ``` Funkcja `points` to nie jedyna funkcja niskiego poziomu, której możemy użyć. Za pomocą funkcji niskiego poziomu `abline` dodajmy na rysunku średnią temperatury obu bobrów. Zmienimy także podpisy osi na bardziej adekwatne. ```{r} plot(beav$time, beav$temp, type='o', main='Temperatura bobrów', col='Red', ylim = c(min(c(beav$temp, beav2$temp)), max(c(beav$temp, beav2$temp))), # podpisy osi ustawia się za pomocą argumentów ylab i xlab ylab = 'Temperatura', xlab = 'Godzina') points(beav2$time, beav2$temp, type='o', col='Blue') # abline przyjmuje różne argumenty # z argumentem `h` rysuje linię poziomą (horizontal) na określonej wysokości abline(h = mean(beav$temp), col = 'Red') abline(h = mean(beav2$temp), col = 'Blue') ``` ## Graficzne funkcje niskiego poziomu Poniżej znajduje się lista funkcji niskiego poziomu. Nie jest wyczerpująca, ale są to najbardziej przydatne funkcje. O każdej z tych funkcji można doczytać w dokumentacji. * `abline` - rysuje prostą * `arrows` - dodaje strzałkę * `axis` - dodaje dodatkowe osie * `legend` - dodaje legendę * `points` - rysuje punkty * `lines` - rysuje linie * `poly` - rysuje wielokąt * `rect` - rysuje prostokąt * `segments` - rysuje odcinki * `text` - dodaje tekst * `title` - dodaje tytuł # Parametry graficzne Możliwości personalizacji wykresów w R są niemal nieograniczone. Parametry graficzne rysowania można zmienić za pomocą funkcji `par`. Kilka przykładowych widzimy niżej. Uwaga! Należy pamiętać, że bardzo dużo rzeczy, które możemy ustawić w funkcji `par` możemy także przekazać jako argument naszej funkcji rysującej. ```{r} par(adj = 1, # 0 - tekst wyrównany do lewej, 0.5 - wycentrowany, 1 - tekst wyrównany do prawej bg = 'skyblue', # kolor tła cex = 1.2, # powiększenie tekstu col = 'Green', # kolor wykresu i ramek family = 'serif', # rodzina czcionki lty=3, # typ linii lwd=1.3, # szerokość linii pch = 8) # symbol używany do oznaczania punktów plot(beav$time, beav$temp, type='o', pch = 7) # symbol numer 8 to gwiazdki, ale my daliśmy 7 przy wywoływaniu funkcji ``` # `hist` - histogram Histogram to typ wykresu, który bardzo często jest wykorzystywany do obrazowania rozkładu danych. Możemy go stworzyć za pomocą funkcji wysokiego poziomu `hist`. ```{r} hist(beav$temp) ``` Spróbujmy wykonać trick polegający na naniesieniu dwóch histogramów na jeden wykres. Proszę uważnie prześledzić kod z komentarzami. ```{r} # Tutaj stworzymy swoje "przezroczyste" kolory za pomocą funkcji adjustcolor. # Bierzemy domyślne kolory R i ustawiamy kanał alfa (przezroczystosć) na 0.5 # Dzięki czemu stają się półprzezroczyste t_red = adjustcolor('Red', alpha.f=0.5) t_blue = adjustcolor('Blue', alpha.f=0.5) # Tak jak przy wykresach punktowych musieliśmy ustawić skalę na osi Y, # tak tutaj musimy zrobić to na osi X hist(beav2$temp, col = t_blue, xlim = c(min(c(beav$temp, beav2$temp)), max(c(beav$temp, beav2$temp)))) # Przekazując argumentowi `add` wartość TRUE mówimy Rowi, # żeby drugi histogram narysował na pierwszym. hist(beav$temp, col = t_red, add = TRUE) ``` W kolejnym przykładzie robimy w zasadzie to samo, ale musimy sobie dodatkowo poradzić z jeszcze jednym problemem, polegajacym na doborze szerokości "koszyków" histogramu. W tym celu tworzymy zmienną `bins`, w której ustawiamy takie wartości koszyków, żeby oba wykresy mieściły się. Przekazujemy ją w argumencie `breaks`. ```{r} bins <- seq(min(beav2$temp)-0.2, # początek pierwszego koszyka max(beav2$temp)+0.2, # koniec ostatniego koszyka by=0.2 # szerokość koszyka ) bins hist(beav2$temp[beav2$activ == 1], # tylko okresy aktywne col = t_blue, xlim = c(min(beav2$temp), max(beav2$temp)), breaks = bins) hist(beav2$temp[beav2$activ == 0], # tylko okresy nieaktywne col = t_red, breaks = bins, add = TRUE ) ``` # `barplot` - wykres słupkowy Wykres słupkowy to chyba najczęściej wykorzystywany w praktyce typ wykresu. Nie przekazuje za dużo informacji, ale często może się przydać. Często można go spotkać w mediach, na plakatach, na infografikach itp. Jest zdecydowanie lepszy, niż wykres kołowy, którego w zasadzie nigdy nie powinniśmy używać. ```{r} df <- read.csv('student-por.csv', sep=";", header = TRUE) table(df$Mjob) # tabela z której tworzymy wykres # wykres, jako argument przyjmuje twór "macierzopodobny" - w tym wypadku tabelę barplot(table(df$Mjob)) ``` Wykres możemy upiększać ustawiając mu kolory oraz przerzucając go na drugi bok. ```{r} df <- read.csv('student-por.csv', sep=";", header = TRUE) # za pomocą prop.table możemy stworzyć wykres procentowy prop.table(table(df$Mjob)) barplot(prop.table(table(df$Mjob)), col = c('Red', 'Blue', 'Green', 'Yellow', 'Grey'), # kolory horiz = TRUE) # orientacja pozioma ``` Jak działają wykresy procentowe z nakładającymi się kolumnami? 1. Musimy mieć tabelę procentową. Uzyskujemy taką za pomocą funkcji `prop.table`. Musimy pamiętać, by przekazać odpowiedni wymiar (`margin`) 2. Funkcja barplot kiedy przekażemy jej argument w postaci dwuwymiarowej tabeli, traktowac będzie kolumny jako kolumny na wykresie, a poszczególne wiersze jako kolejne segmenty. 3. Jeżeli ustawili Państwo dobrze wymiary, to wykresy powinny mieć tę samą wysokość. ```{r} # za pomocą prop.table możemy stworzyć wykres procentowy prop.table(table(df$studytime, df$Mjob), 2 # proporcje sumują się do 1 w kolumnach ) barplot(prop.table(table(df$studytime, df$Mjob), 2), col = c('Red', 'Blue', 'Green', 'Yellow'), # kolory horiz = TRUE, # orientacja pozioma legend = TRUE) # legenda ``` Tutaj szybki sposób na naniesienie na wykres jakiegoś parametru naszych danych za pomocą funkcji `tapply` i `barplot`. ```{r} barplot(tapply(df$G3, df$Mjob, mean)) ``` # `boxplot` - wykres pudełkowy Wykres pudełkowy został wymyślony przez Johna Tukeya jako prosta metoda wizualizacji danych. O ile wiem, po raz pierwszy został on opisany w książce *Exploratory Data Analysis*. Prawie każdy widział w swoim życiu wykres pudełkowy, niewiele osób potrafi jednak powiedzieć, co oznaczają jego poszczególne elementy i do czego się tak naprawdę odnoszą. Proszę nauczyć się odczytywać informacje z wykresów pudełkowych. ![Boxplot](Box-Plot-MTB_01.png) Oraz przeczytać dowolny artykuł gdziekolwiek na ten temat. Moze być ten: http://onlinestatbook.com/2/graphing_distributions/boxplots.html W R możemy stworzyć wykres pudełkowy za pomocą funkcji `boxplot`. Poniższy kod rysuje dwupanelowy wykres. Na pierwszym panelu jest wykres pudełkowy ocen chłopców, na drugim - dziewcząt. ```{r} par(mfrow = c(1,2)) boxplot(split(df, df$sex)[[2]]$G3, main = 'Chłopcy') boxplot(split(df, df$sex)[[1]]$G3, main = 'Dziewczynki') ``` # `vioplot` - wykres skrzypcowy Wykres skrzypcowy to bardziej nowoczesny odpowiednik wykresu pudełkowego. Można o nim myśleć jako o połączeniu histogramu (lub wykresu ilustrującego estymowaną z rozkładu empirycznego gęstość prawdopodobieństwa) oraz wykresu pudełkowego. Niektórym jego wygląd się kojarzy: ![Obrazek z XKCD, https://xkcd.com/1967/](violin_plots_xkcd.png) Poniżej znajduje się wyjaśnienie, co oznaczają poszczególne elementy wykresu skrzypcowego: ![Wykres skrzypcowy](violin_plot.png) Więcej o wykresie skrzypcowym można przeczytać na przykład na Wikipedii: https://en.wikipedia.org/wiki/Violin_plot ```{r warning=FALSE, message=FALSE} # musimy zainstalować pakiet `vioplot` tworzący wykres skrzypcowy # install.packages("vioplot") library(vioplot) par(mfrow = c(1,2)) vioplot(split(df, df$sex)[[2]]$G3) vioplot(split(df, df$sex)[[1]]$G3) ```