ggplot2
jest jednym z najczęściej wykorzystywanych
pakietów do tworzenia grafiki w R. Pozwala tworzyć w łatwy sposób dość
skomplikowane wykresy, posiada również dość rozsądne ustawienia
standardowe, dzieki którym możemy uzyskać estetycznie wyglądające
ilustracje małym nakładem pracy.
Nie jest on dołączy do podstawowej dystrybucji R i należy
zainstalować go za pomocą polecenia install.packages
.
# install.packages('ggplot2') # instalacja ggplot2
library(ggplot2)
Praca z ggplot2
różni się od pracy z grafiką w
standardowym R. Podstawowe różnice to:
ggplot2
raczej definiujemy wykres, nie przejmujemy się
najczęściej niskopoziomowymi szczegółami.+
- ggplot2
przeciąża operator dodawania) do siebie obiekty reprezentujące “warstwy”
albo “mapowania” w specyficznej “gramatyce grafiki” implementowanej
przez ggplot2
.ggsave
.Co będziemy omawiać:
qplot
oraz gramatyki
grafiki (mapowanie).Co nie będzie omawiane, ale jest ważną czescią pakietu
ggplot2
:
Innymi słowy - w ggplot2
możemy zmieniać detale
tworzonych przez nas wykresów, ale nie będziemy omawiać każdej służącej
do tego funkcji i jej argumentu. Informacje można łatwo znaleźć w
Internecie, dokumentacja rozmaitych funkcji bogata jest też w
przykłady.
qplot
- funkcja do szybkiego tworzenia wykresów
(quickplot)qplot
jest wrapperem (można myśleć: skrótem) na
inne funkcje ggplot2
, który pozwala nam bardzo szybko i bez
potrzeby żmudnego definiowania mapowan tworzyć proste wykresy. Z
założenia funkcja qplot
nie ma generować bardzo złożonych
wykresów, lecz estetycznie wyglądające bardzo podstawowe typy wykresów.
Przypomnijmy sobie jak wyglądały dane ze zbioru beaver1
-
będziemy na nich pracować.
head(beaver1)
## day time temp activ
## 1 346 840 36.33 0
## 2 346 850 36.34 0
## 3 346 900 36.35 0
## 4 346 910 36.42 0
## 5 346 920 36.55 0
## 6 346 930 36.69 0
W przypadku, gdy w funkcji qplot
podamy tylko jedną
zmienną (x
), ggplot2
wyprodukuje domyślnie
histogram. Zmienne przekazujemy bez cudzysłowiów i są
nimi nazwy kolumn w naszej ramce danych. Podajemy
również argument data
, w którym przekazujemy zmienną, w
której znajduje się ramka danych, której chcemy używać.
qplot(x = temp, data = beaver1)
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Gdy podamy dwie zmienne - x
oraz y
-
domyślnym rodzajem wykresu będzie wykres punktowy
(scatterplot).
qplot(x = time, y = temp, data = beaver1[beaver1$day == 346,])
Przekazując kolumnę z wektorem typu factor
jako argument
color
możemy ustalić inne kolory ze względu na wartość tej
kolumny. W poniższym przypadku punkty dotyczące obserwacji w obu dniach
oznaczone są innymi kolorami. Warto zauważyć, że ggplot2
automatycznie stworzył legendę (czego nie robią funkcje wbudowane w
R!).
beaver1$dzien <- as.factor(beaver1$day)
qplot(x = time, y = temp, color = dzien, data = beaver1)
Za pomocą argumentu geom
możemy zmienić typ wykresu.
Listę wszystkich możliwości z łatwością znajdą Państwo w internecie.
Pokażemy sobie jednak kilka z nich. Ustawiając argument
geom
na "line"
możemy stworzyć wykres
liniowy.
qplot(x = time, y = temp, geom = 'line', data = beaver1[beaver1$day == 346,])
"step"
stworzy wykres schodkowy.
qplot(x = time, y = temp, geom = 'step', data = beaver1[beaver1$day == 346,])
Jeśli do funkcji plot
przekażemy dwie zmienne, z których
jedna będzie kategorialna (factor
), to ggplot2
stworzy jeden ze znanych Państwu typów wykresów - na przykład wykres
budełkowy. Jak jednak widzimy w przypadku wykresu pudełkowego argument
color
nie zadziałał tak, jak byśmy chcieli - pokolorował
tylko linie na wykresie.
qplot(x=dzien, y = temp, color = dzien, geom = 'boxplot', data = beaver1)
Jeżeli chcielibyśmy pokolorować również wypełnienie, musielibyśmy
użyć argumentu fill
.
qplot(x=dzien, y = temp, fill = dzien, geom = 'violin', data = beaver1)
ggplot2
qplot
przydaje się przede wszystkim wtedy, kiedy chcemy
stworzyć wykres szybko lub nie jest skomplikowany. Nie
pozwala jednak wykorzystać wszystkich możliwości, jakie ma ten pakiet.
Spróbujmy więc stworzyć wykres za pomocą “gramatyki grafiki” jaki
implementuje ggplot2
.
Spróbujmy na początku stworzyć obiekt reprezentujący nasz wykres.
Robimy to za pomocą funkcji ggplot
.
ggplot(data = beaver1)
Otrzymaliśmy puste płótno. Dlaczego? Oczywiście nie ustaliliśmy co ma
być na osi rzędnych, co na odciętych. Stwórzmy więc obiekt, w którym
przekażemy nasze mapowanie. Odpowiada za to argument
mapping
(będziemy go dalej pomijać i przekazywać wartości
pozycyjnie), w którym przekazujemy obiekt stworzomy za pomocą funkcji
aes
.
ggplot(data = beaver1, mapping = aes(x = temp))
Mamy już wykres, mamy już mapowanie - nawet dostaliśmy odpowiednie
oznaczenia na osi. Nie mamy jednak na nim żadnego kształtu! Spróbujmy
dodać do naszego wykresu jakiś kształt. Robimy to za pomocą funkcji
geom_rodzaj_kształtu
, którą “dodajemy” do już istniejącego
obiektu.
ggplot(data = beaver1, aes(x = temp)) +
geom_histogram()
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Stworzyliśmy histogram! Jak Państwo widzą wygląda chyba troszkę ładniej niż standardowy histogram w R.
No dobrze, ale czy możemy dodać jakiś inny kształt? Spróbujmy dodać
małe kreseczki reprezentujące poszczególne obserwacje za pomocą
geom_rug
.
ggplot(data = beaver1, aes(x = temp)) +
geom_histogram() +
geom_rug()
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Wygląda to całkiem nieźle!
Mogą się Państwo zastanawiać skąd ggplot2
wie, co i
gdzie powinien narysować wówczas, gdy “dodajemy” kolejne kształty?
ggplot2
uwzględnia dorysowując do wykresu kolejne kształte
mapowanie (aes
) odziedziczone z głównego wykresu (= obiektu
stworzonego przez funckję ggplot
). Dlatego właśnie możemy
po prostu dodawać kolejne kształty.
Nie musimy godzić się na mapowanie “odziedziczone” z głównego
wykresu. Dla każdego kształtu (geoma) możemy mapowanie zmienić
lub uzupełnić o dodatkowe elementy. W tym celu używamy funkcji
aes
. W poniższym przykładzie użyliśmy wbudowanego w
ggplot2
słowa kluczowego ..density..
za pomocą
którego zmieniliśmy wartości na osi y.
ggplot(data = beaver1, aes(x = temp)) +
geom_histogram(aes(y = ..density..)) +
geom_rug()
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Chociaż kolejne geomy dziedziczą mapowanie po pierwszym obiekcie, to
możemy je oczywiście nadpisać. W tym przypadku podobnie jak w
poprzednich dodaliśmy do naszego histogramu kreseczki za pomocą
geom_rug
, tym razem jednak dodaliśmy dodatkowe mapowanie -
zmienna dzien
ma być mapowana na kolor kreseczek.
ggplot(data = beaver1, aes(x = temp)) +
geom_histogram(aes(y = ..density..)) +
geom_rug(aes(color = dzien))
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Bez trudu możemy dodać jądrowy estymator gęstości dodając po prostu
kolejny geom - tym razem geom_density
. Proszę
zwrócić uwagę, że zmieniliśmy jeszcze mapowanie kreseczek w
geom_rug
. time
jest zmienną ciągłą (w miarę),
więc ggplot2
automatycznie dobrał ciągłą skalę kolorów i
stworzył odpowiednią legendę.
ggplot(data = beaver1, aes(x = temp)) +
geom_histogram(aes(y = ..density..)) +
geom_rug(aes(color = time)) +
geom_density()
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
ggplot2
udostępnia oczywiście również rodzaje geomów
bardziej wymyślne niż zwykłe histogramy. Na poniższym wykresie mają
Państwo inny geom - geom_dotplot
, który zamiast prostokątów
rysuje kropki.
ggplot(data = beaver1, aes(x = temp)) +
geom_dotplot() +
geom_rug()
## Bin width defaults to 1/30 of the range of the data. Pick better value with `binwidth`.
Zwróćmy teraz uwagę na to, że w naszym zbiorze danych mamy dane z
okresów aktywności i braku aktywności. Chcielibyśmy je rozdzielić, żeby
lepiej zobrazować różnicę między nimi. Użyjemy do tego funkcji
facet_grid
, która w sposób automatyczny dzieli nasz wykres
na panele według zadanego czynnika.
beaver1['aktywnosc'] <- as.factor(beaver1$'activ')
ggplot(data = beaver1, aes(x = temp, fill = aktywnosc)) +
geom_dotplot() +
geom_rug() +
facet_grid(.~aktywnosc) # możemy wybrać dwie zmienne, składnia to `zmienna1 ~ zmienna2`
## Bin width defaults to 1/30 of the range of the data. Pick better value with `binwidth`.
Możemy próbować uatrakcyjnić nasz wykres. Proszę zauważyć, że każdy
geom ma tutaj inne mapowanie - wysokosc słupków kropek
reprezentuje liczbe zliczeń w danym “koszyku” hisgoramu, kolor kropek -
aktywność bobra, kreseczki - dokładna wartość każdej obserwacji. Z kolei
kolor kreseczek reprezentuje dzień, w którym ich dokonywaliśmy. Każda z
tych rzeczy była osobną “warstwą”, którą definiowaliśmy w gramatyce
grafiki ggplot2
.
ggplot(data = beaver1, aes(x = temp)) +
geom_dotplot(aes(fill = aktywnosc, color = aktywnosc),
binpositions="all", stackgroups = TRUE) +
geom_rug(aes(color=dzien, fill = dzien))
## Warning: Ignoring unknown aesthetics: fill
## Bin width defaults to 1/30 of the range of the data. Pick better value with `binwidth`.
Jeżeli chodzi o inne geomy w stylu histogramów to mamy
jeszcze geom_freqpoly
.
ggplot(data = beaver1, aes(x = temp, fill = dzien, color = dzien)) +
geom_freqpoly()
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Oraz geom_area
(ten jest szczególnie efektowny).
ggplot(data = beaver1, aes(x = temp, fill = dzien, color = dzien)) +
geom_area(stat='bin')
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Jeżeli chodzi o wykresy słupkowe, to podobnie jak w standardowym R sami musimy policzyć wartości mające odpowiadać wysokości słupków. Jeśli mają to być zliczenia postąpimy więc tak:
ggplot(data = beaver1, aes(x = dzien, fill = aktywnosc)) +
geom_bar()
Domyślnym zachowaniem jest ustawianie słupków na sobie, ale możemy je zmienić tak, by ustawiane były obok siebie.
ggplot(data = beaver1, aes(x = dzien, fill = aktywnosc)) +
geom_bar(position= 'dodge')
Czasami jednak nie chcemy reprezentować na wykresie słupkowym liczby
zliczeń czegoś, ale np. średnią, odchylenie standardowe, medianę.
Wówczas chyba najprościej jest stworzyć sobie nową ramkę danych, w
której będą obliczone te wartości i przekazać jako argument
stat
funkcji geom_bar
wartość
"identity"
.
df <- data.frame(sd = tapply(beaver1$temp, beaver1$dzien, sd), dzien = levels(beaver1$dzien))
df
## sd dzien
## 346 0.2098782 346
## 347 0.1038336 347
ggplot(data = df, aes(y = sd, x = dzien, fill = dzien)) +
geom_bar(stat = 'identity')
Biblioteka ggplot2
daje możliwość łączenia ze sobą kilka
rodzajów wykresów. Na poniższym rysunku połączyliśmy wykres punktowy (z
jitterm dla większej przejrzystosci) z wykresem skrzypcowym.
Dodaliśmy również podpisy pod osiami oraz tytuł wykresu, zmieniliśmy też
domyślne kolory (żeby mniej się zlewały).
ggplot(data = beaver1) +
geom_violin(aes(x = dzien, y = temp, fill = dzien), draw_quantiles = c(0.25, 0.5, 0.75)) +
geom_jitter(aes(x = dzien, y = temp, color = aktywnosc)) +
scale_fill_brewer(palette='Set1') +
ggtitle('Wykres skrzypcowy') +
labs(x='Dzień pomiarów', y='Temperatura')
W przypadku sytuacji, w której mamy dwie zmienne ciągłe postępujemy
dokładnie tak samo. Do ilustracji posłużymy się zbiorem
iris
, który dotyczy kwiatków.
head(iris)
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1 5.1 3.5 1.4 0.2 setosa
## 2 4.9 3.0 1.4 0.2 setosa
## 3 4.7 3.2 1.3 0.2 setosa
## 4 4.6 3.1 1.5 0.2 setosa
## 5 5.0 3.6 1.4 0.2 setosa
## 6 5.4 3.9 1.7 0.4 setosa
Znów, samo wywołanie funkcji ggplot
nic nie daje.
ggplot(data = iris)
Nawet ustawienie mapowania nic nie daje, chociaż ustala nam osie i siatkę.
ggplot(data = iris) +
aes(x = Petal.Length, y = Petal.Width)
Pierwszy geom jaki omowimy to geom_point
odpowiadający znanemu już nam wykresowy punktowemu.
ggplot(data = iris) +
geom_point(aes(x = Sepal.Width, y = Sepal.Length))
Kstzałt punktów jest jedną z możliwościa mapowania zmiennej dyskretnej.
ggplot(data = iris) +
geom_point(aes(x = Sepal.Width, y = Sepal.Length, shape = Species))
Podobnie jak poprzednio możemy dodać dodatkowe mapowanie, które
trzecią zmienną - gatunek - mapuje jako kolor. Dodatkowo zmieniliśmy
wygląd całego wykresu dodając jeden z kilku wbudowanych motywów
(theme_minimal
)
ggplot(data = iris) +
geom_point(aes(x = Sepal.Width, y = Sepal.Length, col = Species)) +
theme_minimal()
Możemy oczywiście umieścić nasze punkty na trzech osobnych panelach w znany nam już sposób.
ggplot(data = iris) +
geom_point(aes(x = Sepal.Width, y = Sepal.Length, col = Species)) +
facet_grid(. ~ Species) +
theme_bw()
Panele możemy umieścić w innej orientacji zmieniając kolejnośc
zmiennych w funkcji facet_grid
. Warto zwrócić uwagę, że
podpisy pod kategoriami są prawidłowo w pozycji poziomej. Pokazuję
również inny motyw (theme_dark
)
ggplot(data = iris) +
geom_point(aes(x = Sepal.Width, y = Sepal.Length, col = Species)) +
facet_grid(Species~.) +
theme_dark()
Bardzo przydatne może być dla Państwa dodawanie linii regresji do
wykresu punktowego. Pokazuje więc jak zrobić to za pomocą
stat_smooth
. Dopasowuje ona model liniowy do danych.
Zacienione pole do przedział ufności (domyślnie 95%) dla linii
regresji.
ggplot(data = iris) +
facet_grid(.~Species) +
stat_smooth(aes(x = Sepal.Width, y = Sepal.Length, col = Species), method = "lm", fullrange= TRUE)+
geom_point(aes(x = Sepal.Width, y = Sepal.Length, col = Species))
## `geom_smooth()` using formula 'y ~ x'
Należy jednak pamiętać, że domyślnie dopasowywane jest nie model liniowy, ale ten: https://en.wikipedia.org/wiki/Local_regression Linia jest więc pogięta, podobnie przedziały ufności.
ggplot(data = iris, aes(x = Sepal.Width, y = Sepal.Length, col = Species)) +
geom_point() +
geom_smooth() +
facet_grid(.~Species)
## `geom_smooth()` using method = 'loess' and formula 'y ~ x'
Oczywiście nic nie stoi na przeszkodzie dodawać znane już nam geomy
takie jak geom_rug
.
ggplot(data = iris, aes(x = Sepal.Width, y = Sepal.Length, col = Species)) +
geom_point() +
geom_smooth() +
geom_rug() +
facet_grid(.~Species)
## `geom_smooth()` using method = 'loess' and formula 'y ~ x'
W kolejnym przykładzie tworzymy bardziej skomplikowany wykres
dotyczący rozmaitych parametrów diamentów. Dane znajdują się w zbiorze
diamonds
, który wbudowany jest w R.
head(diamonds)
## # A tibble: 6 × 10
## carat cut color clarity depth table price x y z
## <dbl> <ord> <ord> <ord> <dbl> <dbl> <int> <dbl> <dbl> <dbl>
## 1 0.23 Ideal E SI2 61.5 55 326 3.95 3.98 2.43
## 2 0.21 Premium E SI1 59.8 61 326 3.89 3.84 2.31
## 3 0.23 Good E VS1 56.9 65 327 4.05 4.07 2.31
## 4 0.29 Premium I VS2 62.4 58 334 4.2 4.23 2.63
## 5 0.31 Good J SI2 63.3 58 335 4.34 4.35 2.75
## 6 0.24 Very Good J VVS2 62.8 57 336 3.94 3.96 2.48
ggplot(data = diamonds, aes(y=carat, x = cut, size = price, color = cut)) +
geom_jitter()
ggplot(data = diamonds, aes(x=carat, y = price)) + # podstawowe mapowanie
geom_point(aes(color = color)) + # mapowanie dla punktów: kolor diamentów -> kolor punktów
facet_grid(clarity~cut) + # dzielimy na panele ze względu na przejrzystość i szlif
stat_smooth(method = 'lm') + # dopasowujemy do danych linię regresji
ggtitle('Diamenty przyjacielem studenta') +
theme_minimal()
## `geom_smooth()` using formula 'y ~ x'
ggplot2
= wygryw: https://plot.ly/ggplot2/ggplot2
: http://motioninsocial.com/tufte/