Menu

ggplot2 w R: przewodnik po gramatyce grafiki dla początkujących

Jak działa ggplot2: model dane + aes() + geom, mapowanie a ustawianie estetyk, labs(), facet_wrap(), motywy i zapisywanie wykresów przez ggsave().

ggplot2 buduje wykresy z warstw

ggplot2 to najczęściej używany pakiet R do wykresów, a ludzie przysięgają na niego z powodu jednego pomysłu projektowego: gramatyki grafiki (grammar of graphics). Bazowy R daje jedną funkcję na wykres (plot(), hist(), barplot()), każdą z własnymi argumentami. ggplot2 daje zamiast tego mały zestaw łączonych elementów (zbiór danych, mapowanie kolumn na właściwości wizualne i warstwy rysujące), które przez + składają się w dowolny wykres. Naucz się gramatyki raz, a każdy nowy typ wykresu to to samo zdanie z jednym zmienionym słowem. W dodatku wartości domyślne (szary panel, rozsądne osie, automatyczne legendy) wyglądają przyzwoicie bez żadnej stylizacji.

To pakiet dodatkowy, więc wymaga jednorazowej instalacji i wczytania w każdej sesji:

install.packages("ggplot2")   # once, on your machine
library(ggplot2)              # at the top of every script that uses it

Jedno oczekiwanie warto znać od początku: ggplot2 chce ramki danych (a nie luźnych wektorów), najlepiej w uporządkowanym długim formacie: jeden wiersz na obserwację, jedna kolumna na zmienną. Jeśli dane są szerokie, przekształcenie ich do formatu długiego zwykle rozwiązuje coś, co wyglądało na problem z wykresem.

Model myślowy: dane, mapowanie, geometria

Każdy ggplot odpowiada na trzy pytania, po jednym na część:

  1. Dane: która ramka danych? ggplot(mtcars, ...)
  2. Mapowanie: które kolumny sterują którymi właściwościami wizualnymi? aes(x = wt, y = hp)
  3. Geometria: jak narysować obserwacje? + geom_point()

Oto anatomia, element po elemencie:

ggplot(mtcars, aes(x = wt, y = hp)) +
    geom_point()
  • ggplot(mtcars, ...) zaczyna wykres, którego domyślne dane to mtcars. Sam w sobie rysuje pusty szary panel, bo nie ma jeszcze warstw.
  • aes(x = wt, y = hp) to mapowanie estetyk: pozycja pozioma pochodzi z kolumny wt, pionowa z hp. Zwróć uwagę, że piszesz gołe nazwy kolumn, a nie mtcars$wt, bo mapowanie jest obliczane wewnątrz podanych danych.
  • + geom_point() dodaje warstwę, która rysuje każdy wiersz jako punkt. + to naprawdę dodawanie warstw: wykres to obiekt, który budujesz, i możesz dalej dodawać kolejny geom, etykiety czy motyw, każdy przez kolejny +.

Po uruchomieniu dostaniesz ten sam wykres punktowy masy względem mocy co wersja w bazowym R z przewodnika po wykresie punktowym, na szarym panelu z białą siatką. Zamień geom_point() na geom_line(), a to samo mapowanie stanie się wykresem liniowym. Tak właśnie działa gramatyka.

Geomy, których naprawdę będziesz używać

Kilkanaście geomów pokrywa prawie całą codzienną pracę:

geom_point()       # scatter plot: two numeric variables
geom_line()        # line chart: trends over an ordered variable
geom_col()         # bar chart from pre-computed heights (needs y)
geom_bar()         # bar chart that counts raw rows for you (no y)
geom_histogram()   # distribution of one numeric variable (set binwidth)
geom_boxplot()     # distributions compared across groups
geom_smooth()      # fitted trend line; method = "lm" for straight

Warstwy się nakładają i tu ggplot2 zaczyna wygrywać z bazowym R pod względem ekspresji: geom_point() + geom_smooth(method = "lm") to wykres punktowy z linią regresji i pasmem ufności w jednej czytelnej linii. Ponieważ wykresy to obiekty, możesz też zapisać bazę i rozgałęziać się od niej:

p <- ggplot(mtcars, aes(x = wt, y = hp)) + geom_point()

p + geom_smooth(method = "lm")   # one variant
p + geom_smooth()                # another (loess curve)

Mapowanie a ustawianie: klasyczne zamieszanie z aes()

Jeden błąd, który popełnia każdy początkujący w ggplot2, zwykle w pierwszym tygodniu: wstawienie dosłownego koloru do wnętrza aes(). Zasada jest krótka: wewnątrz aes() oznacza "zmienia się z danymi"; na zewnątrz oznacza "stałe ustawienie", a oba miejsca robią zupełnie różne rzeczy:

# MAPPING: color varies by a column - each cylinder count gets its own
# color, and a legend appears automatically
ggplot(mtcars, aes(x = wt, y = hp, color = factor(cyl))) +
    geom_point(size = 2)

# SETTING: every point is literally steelblue - no legend, no mapping
ggplot(mtcars, aes(x = wt, y = hp)) +
    geom_point(color = "steelblue", size = 2)

A sama pułapka:

# WRONG: "blue" inside aes() is treated as data, not as a color
ggplot(mtcars, aes(x = wt, y = hp, color = "blue")) +
    geom_point()

To rysuje punkty w kolorze łososiowym z legendą, której jedyny wpis nazywa się "blue". Dlaczego: aes() mapuje kolumny na właściwości, więc color = "blue" tworzy sztuczną jednokategoryjną kolumnę, w której wszędzie jest słowo "blue", a ggplot przypisuje tej kategorii swój pierwszy domyślny kolor, który akurat jest czerwonawym łososiowym. Jeśli chodziło o "zrób punkty niebieskie", kolor trafia poza mapowanie: geom_point(color = "blue"). Ta sama zasada dotyczy size, shape, fill i alpha. (Zwróć też uwagę na factor(cyl) w przykładzie z mapowaniem: cyl jest liczbowe, a owinięcie go w factor() prosi o osobne kolory dla grup zamiast ciągłego gradientu.)

Etykiety, panele i motywy

labs() nazywa wszystko w jednym miejscu, a wykres nie jest gotowy, dopóki nie ma prawdziwych etykiet:

ggplot(mtcars, aes(x = wt, y = hp, color = factor(cyl))) +
    geom_point(size = 2) +
    labs(title = "Horsepower vs. weight",
         x     = "Weight (1000 lbs)",
         y     = "Horsepower",
         color = "Cylinders")

Panele (facets) to sztandarowa funkcja ggplot2: dzielą jeden wykres na małe wielokrotności, po jednym panelu na grupę, ze wspólnymi osiami, żeby panele dało się uczciwie porównywać:

ggplot(mtcars, aes(x = wt, y = hp)) +
    geom_point() +
    facet_wrap(~ cyl)

Pojawiają się trzy panele, po jednym dla samochodów 4-, 6- i 8-cylindrowych, ułożone w siatkę z wartością grupy podpisaną nad każdym panelem. W bazowym R to żonglowanie par(mfrow) z ręcznie ustawianymi wspólnymi zakresami; tutaj to jedna linia. Panele nagradzają uporządkowane dane, dlatego ggplot2 tak naturalnie łączy się z potokiem dplyr: przefiltruj i podsumuj, a potem przekaż wynik prosto do ggplot().

Motywy zmieniają styl wszystkiego, co nie jest danymi, jednym wywołaniem: + theme_minimal() (czyste białe tło), + theme_bw(), + theme_classic() (tylko osie, bez siatki) albo domyślny szary. Wybierz jeden na projekt i trzymaj się go: raport, w którym każdy wykres ma ten sam motyw, czyta się jak jeden dokument, a nie jak album z wycinkami.

Zapisywanie przez ggsave() i kiedy bazowy R wciąż wystarcza

ggsave() zapisuje ostatni wykres na dysk i rozpoznaje format po rozszerzeniu pliku:

ggsave("hp-vs-weight.png", width = 8, height = 5)          # last plot shown
ggsave("hp-vs-weight.pdf", plot = p, width = 8, height = 5) # a saved object

width i height są domyślnie w calach; ustawiaj je jawnie, bo rozmiar czcionki skaluje się z wymiarami wyjścia, a wartości domyślne rzadko pasują do miejsca docelowego wykresu.

A kiedy w ogóle warto: na pięciosekundowe spojrzenie na jedną zmienną w trakcie analizy plot() i pokrewne funkcje bazowego R wymagają mniej pisania i żadnych zależności. Nie ma nagrody za używanie ggplot2 wszędzie. ggplot2 pokazuje swoją wartość, gdy tylko wykres obejmuje grupy, legendy, panele albo odbiorców: gramatyka skaluje się do złożoności, z którą wykresy bazowe radzą sobie tylko z wysiłkiem.

Co warto zapamiętać

  • ggplot2 składa każdy wykres z danych + mapowania aes() + warstw geom połączonych przez +; naucz się gramatyki raz i używaj jej dla każdego typu wykresu.
  • aes() mapuje kolumny na właściwości wizualne: gołe nazwy kolumn, obliczane w twojej ramce danych.
  • Wewnątrz aes() = zmienia się z danymi (i dostaje legendę); na zewnątrz = stałe ustawienie. aes(color = "blue") to klasyczny błąd.
  • labs() do tytułów, facet_wrap(~ group) do małych wielokrotności, theme_minimal() i pokrewne do stylu, ggsave() z jawnymi wymiarami do eksportu.
  • Szybki podgląd dla siebie: bazowy R. Grupy, panele albo odbiorcy: ggplot2.

To zamyka rozdział o wykresach. Naturalnym następnym krokiem są statystyki opisowe, czyli liczby opisujące kształty, które pokazują te wykresy.

Najczęściej zadawane pytania

Czym jest ggplot2 w R?

ggplot2 to najpopularniejszy pakiet R do tworzenia wykresów. Zamiast jednej funkcji na każdy typ wykresu składasz każdy wykres z tych samych trzech elementów: ramki danych, mapowania aes() kolumn na właściwości wizualne i jednej lub więcej warstw geom_*(), połączonych przez +. Jest częścią tidyverse.

Jak zainstalować ggplot2?

Uruchom raz install.packages("ggplot2"), a potem library(ggplot2) na początku każdego skryptu, który z niego korzysta. Instalacja umieszcza pakiet na komputerze; library() wczytuje go do bieżącej sesji.

Co robi aes() w ggplot2?

aes() mapuje kolumny danych na właściwości wizualne: aes(x = wt, y = hp, color = factor(cyl)) mówi, że pozycja pozioma pochodzi z wt, pionowa z hp, a kolor punktu z liczby cylindrów. Wszystko wewnątrz aes() zmienia się razem z danymi; wszystko poza nim to stałe ustawienie.

Dlaczego punkty w ggplot nie mają koloru, o który proszę?

Kolor trafił do wnętrza aes(): aes(color = "blue") nie ustawia koloru, tylko mapuje zmyśloną kategorię o nazwie "blue", więc ggplot wybiera własny domyślny kolor i dodaje legendę. Żeby ustawić dosłowny kolor, umieść go poza mapowaniem: geom_point(color = "blue").

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ