1  Een introductie in ggplot2

1.1 ggplot2 en de tidyverse

ggplot2 is een R-package speciaal gecreëerd voor datavisualisatie. ggplot2 maakt deel uit van een grotere verzameling R-packages: de tidyverse. De tidyverse is een verzameling van R-pakketten dat speciaal ontworpen is om je codeeRweRk een pak intuïtiever, efficiënter en dus ook eenvoudiger te maken. Hoewel deze website zich focust op datavisualisatie met ggplot2, introduceren we ook enkele functies uit onder meer het dplyr-package. Dit is een pakket dat ontworpen is om datamanipulatie piece of cake te maken voor de gebruiker. Als er functies uit dplyr worden gebruikt, dan worden deze kort toegelicht in de code zelf. Wil je een uitgebreidere introductie van dplyr, dan vind je hier een korte tutorial. Wil je meer weten over de tidyverse en de verschillende packages die er deel van uit maken, dan is het boek R for data science een goed vertrekpunt! Maar nu genoeg over de tidyverse over naar ggplot2!

1.2 De plotfuncties in R?

Wie een beetje vertrouwd is met R weet dat R verschillende plotfuncties aanbiedt. Voorbeelden daarvan zijn hist(), boxplot() en uiteraard ook plot(). Hieronder vind je een voorbeeld van een histogram, een boxplot en een scatterplot gecreëerd met deze functies.

Klik hier voor code
hist(data$x, xlab = "x") 

Klik hier voor code
boxplot(data$y, xlab = "y") 

Klik hier voor code
plot(data$x, data$y, xlab = "x", ylab = "y")

De plot()-functie is bijzonder omdat de output van deze functie zich aanpast aan de input die het krijgen. Geef je plot() twee kwantitatieve variabelen mee? Dan tovert plot() een scatterplot te voorschijn (zoals in het voorbeeld hierboven). Krijgt plot() een tabel als input? Dan wordt er een staafdiagram gecreëerd. Er zitten dus best al wel plot-functies in R. Je vraagt je nu misschien af waarom er dan nood is aan een bijkomend R-pakket dat zich specifiek richt op visualisatie?

De plot-functies die standaard in R zitten, zijn niet zo flexibel. De functies hist() of boxplot() laten bijvoorbeeld alleen maar toe om een specifiek soort grafiek te creëren. Je kan wel zaken aanpassen (bv. de kleur van een histogram) of toevoegen aan de plots (bv. een titel), maar deze mogelijkheden zijn vrij beperkt en vooral niet zo intuïtief in het gebruik ervan.

1.3 Grammar of graphics

Het package ggplot2 volgt de principes van de Grammar of Graphics. De Grammar of Graphics is een ‘taal’ ontworpen door Leland Wilkinson om grafieken te creëren. Wilkinson was een Amerikaanse statisticus en expert op het gebied van data visualisatie. Hij introduceerde het concept in zijn boek “The Grammar of Graphics” (1999). Volgens de Grammar of Graphics kan elke visualisatie worden opgesplitst in dezelfde componenten (layers in Grammar of Graphics-taal). Voorbeelden van zulke layers zijn data, geometrische objecten en facetten. De Grammar of Graphics is dus een universeel systeem om visualisaties te creëren dat de basis vormt voor verschillende moderne visualisatietools (waaronder dus ook ggplot2).

Het basisidee achter ggplot2 is dat je een plot in laagjes opbouwt. Elke laag voegt een nieuw element toe aan de plot, zoals punten, lijnen of tekst. De animatie hieronder illustreert hoe je een ggplot opbouwt aan de hand van zeven verschillende layers:

  • data
  • aesthetics
  • geometries
  • facets
  • statistics
  • coordinates
  • themes

(Animatie overgenomen van Thomas de Beus)

Een visualisatie maken in ggplot2 doe je dus laagje per laagje, een beetje zoals je een cake bakt. Op de figuur hieronder zie je hoe elk onderdeel van de cake overeenkomt met een layer in ggplot2.

(Figuur overgenomen van Tanya Shapiro)

Als je een cake bakt, start je met het leggen van de basis. In ggplot2 doe je dat met de functie ggplot(). Elke visualisatie start dus met deze functie. Vervolgens specificeer je de ingrediënten met behulp van de aesthetics en de smaken met scales. Dan voeg je laagjes toe aan je cake in de vorm van geoms. Ten slotte kan je de cake naar eigen believen afwerken door middel van de functie theme. Genoeg gepraat over het maken van visualisaties, tijd om zelf aan de slag te gaan!

1.4 ggplot2 in een notendop

Om zelf een visualisatie te maken, hebben we uiteraard data nodig. Een leuke dataset om mee aan de slag te gaan, is de Palmer Penguin data. Deze dataset is afkomstig van onderzoek uitgevoerd door Kristen Gorman op het Palmer Station (Antarctica). De data bevat metingen en observaties over drie pinguïnsoorten (Adélie, Kinband en Gentoo) verzameld in 2007, 2008 en 2009:

  • snavellengte (bill_length_mm)
  • snaveldiepte (bill_depth_mm)
  • vleugellengte (flipper_length_mm)
  • lichaamsgewicht (body_mass_g)
  • geslacht (sex)
  • soort (species)
  • kolonielocatie (island)
  • jaar van observatie (year) Meer info over de Palmer Penguins data vind je hier.

Om met de pinguïndata aan de slag te gaan, dien je eerst de packages tidyverse en palmerpenguins te installeren en laden. Vervolgens kan je de data zelf in RStudio laden via de functie data.

Klik hier voor code
install.packages("tidyverse")
install.packages("palmerpenguins")

library(tidyverse)
library(palmerpenguins)
data("penguins")

Bekijk vervolgens 10 random rijen uit de dataset met behulp van de functie slice_sample() (functie uit dplyr).

Klik hier voor code
# Sample 10 random rijden (n = 10) uit de data `penguins`
slice_sample(penguins, n = 10)
# A tibble: 10 × 8
   species   island   bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
   <fct>     <fct>             <dbl>         <dbl>             <int>       <int>
 1 Gentoo    Biscoe             44.9          13.8               212        4750
 2 Adelie    Biscoe             35.7          16.9               185        3150
 3 Gentoo    Biscoe             50.4          15.7               222        5750
 4 Chinstrap Dream              58            17.8               181        3700
 5 Adelie    Biscoe             40.6          18.6               183        3550
 6 Adelie    Torgers…           36.2          17.2               187        3150
 7 Gentoo    Biscoe             45.1          14.4               210        4400
 8 Adelie    Biscoe             39.6          17.7               186        3500
 9 Chinstrap Dream              45.2          16.6               191        3250
10 Gentoo    Biscoe             44.9          13.3               213        5100
# ℹ 2 more variables: sex <fct>, year <int>

Check via glimpse() ook welke variabelen allemaal in de dataset zitten en hoe deze gedefineerd zijn (als factor, …).

Klik hier voor code
glimpse(penguins)
Rows: 344
Columns: 8
$ species           <fct> Adelie, Adelie, Adelie, Adelie, Adelie, Adelie, Adel…
$ island            <fct> Torgersen, Torgersen, Torgersen, Torgersen, Torgerse…
$ bill_length_mm    <dbl> 39.1, 39.5, 40.3, NA, 36.7, 39.3, 38.9, 39.2, 34.1, …
$ bill_depth_mm     <dbl> 18.7, 17.4, 18.0, NA, 19.3, 20.6, 17.8, 19.6, 18.1, …
$ flipper_length_mm <int> 181, 186, 195, NA, 193, 190, 181, 195, 193, 190, 186…
$ body_mass_g       <int> 3750, 3800, 3250, NA, 3450, 3650, 3625, 4675, 3475, …
$ sex               <fct> male, female, female, NA, female, male, female, male…
$ year              <int> 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007…

Nu je een beetje vertrouwd bent met de data kunnen we aan de slag met ggplot2.

1.4.1 Data en aesthetics

Je start in ggplot2 steeds met de functie ggplot(). In deze functie geef je aan welke data je wil gebruiken (data = penguins) en je specificeert ook de aesthetics. De aesthetics vormen de ingrediënten van je plot. Het zijn m.a.w. de variabelen die je wil plotten. De aesthetics specificeren doe je aan de hand van de functie aes(). In dit geval willen we de variabele flipper_length_mm op de x-as en de variabele body_mass_g op de y-as.

Kopieer de code hieronder naar RStudio op je eigen laptop en probeer deze uit. Zorg dat de packages tidyverse en palmerpenguins geladen zijn. Door hieronder op ‘Plot’ te klikken, vind je het verwachte resultaat terug.

Klik hier voor code
Plot <- ggplot(

  ## Stap 1: data
  data = penguins,
  
  ## Stap 2: aesthetics specificeren (mapping)
  aes(
    x = flipper_length_mm,
    y = body_mass_g)
)

Plot

1.4.2 Geometries

De vorige code levert een lege plot op! Dit komt omdat je alleen de basis voor je plot hebt gelegd (met de functie ggplot()), maar niet hebt aangegeven welk geometrisch object (geom in ggplot2-taal) je wilt gebruiken. Een geom representeert de visuele elementen die worden gebruikt om gegevens weer te geven in de plot. Elke geom komt overeen met een specifiek type grafische representatie, zoals punten, lijnen, balken of gebieden. Geoms bepalen dus hoe de gegevens visueel worden weergegeven. In ons voorbeeld voegen we de geom_point() functie toe. Deze functie geeft elk datapunt weer als een punt op de plot? Vul je code aan en evalueer het resultaat. Je krijgt een warning. Wat betekent deze warning?

Kopieer de code hieronder naar RStudio op je eigen laptop en probeer deze uit. Door hieronder op ‘Plot’ te klikken, vind je het verwachte resultaat terug.

Klik hier voor code
Plot <- ggplot(

  ## Stap 1: data
  data = penguins,
  
  ## Stap 2: aesthetics specificeren (mapping)
  aes(
    x = flipper_length_mm,
    y = body_mass_g)
) +
  ## Stap 3: voeg geometry toe
  geom_point()

Plot
Warning: Removed 2 rows containing missing values or values outside the scale range
(`geom_point()`).

De warning wijst erop dat er twee ontbrekende observaties zijn (en dat deze uiteraard niet geplot zijn).

1.4.3 Facets

Stel dat we het verband tussen het lichaamsgewicht en vleugellengte per pinguïnsoort willen plotten. We willen m.a.w een aparte scatterplot per soort (small multiples). Dit kan je heel eenvoudig realiseren met behulp van de functie facet_wrap(). Tussen de haakjes geef je aan op basis van welke variabele de facets moeten worden gecreëerd (in dit geval species). Deze variabele dient vooraf gegaan te worden door een tilde (~).

Kopieer de code hieronder naar RStudio op je eigen laptop en probeer deze uit. Door hieronder op ‘Plot’ te klikken, vind je het verwachte resultaat terug.

Klik hier voor code
Plot <- ggplot(

  ## Stap 1: data
  data = penguins,
  
  ## Stap 2: aesthetics specificeren (mapping)
  aes(
    x = flipper_length_mm,
    y = body_mass_g)
) +
  ## Stap 3: voeg geometry toe
  geom_point() +
  
  ## Stap 4: definieer facets
  facet_wrap(~species)

Plot
Warning: Removed 2 rows containing missing values or values outside the scale range
(`geom_point()`).

1.4.4 Theme

In een laatste stap passen we het plot-thema aan. Als je geen plot-thema meegeeft, dan gebruikt deze het default plot-thema. Dit plot-thema heeft echter een grijze achtergrond die verder niets bijdraagt aan de plot (chart junk!). Verander daarom het plot-thema naar theme_minimal(). Voeg dit plot-thema standaard toe aan alle plots die je creëert!

Kopieer de code hieronder naar RStudio op je eigen laptop en probeer deze uit. Door hieronder op ‘Plot’ te klikken, vind je het verwachte resultaat terug.

Klik hier voor code
Plot <- ggplot(

  ## Stap 1: data
  data = penguins,
  
  ## Stap 2: aesthetics specificeren (mapping)
  aes(
    x = flipper_length_mm,
    y = body_mass_g)
) +
  ## Stap 3: voeg geometry toe
  geom_point() +
  
  ## Stap 4: definieer facets
  facet_wrap(~species) +
  
  ## Stap 5: pas thema aan
  theme_minimal()

Plot
Warning: Removed 2 rows containing missing values or values outside the scale range
(`geom_point()`).

1.4.5 Plot opbouwen

Je bouwde net je allereerste visualisatie in ggplot2laagje voor laagje op! Uiteraard kan je nog veel meer zaken toevoegen. Hieronder vind je een uitgebreider voorbeeld terug.

We leggen stap per stap uit wat er precies wordt toegevoegd aan de plot. Daarbij wordt ook de nodige code meegegeven. Je zal merken dat er in de code gebruik gemaakt wordt van functies uit dplyr (het datamanipulatie pakket uit de tidyverse). Je vindt twee manieren terug om code aan elkaar te rijgen. In ggplot2 gebeurt dit met een +. dplyr maakt echter gebruik van de pipe (%>%).

  1. De basis van de plot wordt gelegd met de functie ggplot(). Er wordt aangegeven dat de variabele flipper_length_mm op de x-as dient te komen en de variabele body_mass_g op de y-as. De plot wordt weggeschreven naar een object met de naam ‘P1’.
Klik hier voor code
P1 <- 
  ## Gebruik de dataset penguins
  penguins %>%
  ## Gebruik alleen rijen waarin sex NIET NA is 
  filter(!is.na(sex)) %>%
  ggplot(aes(x = flipper_length_mm, y = body_mass_g )) 
  1. Er wordt een geom toegevoegd aan de plot P1 (geom_point()).
Klik hier voor code
P2 <- 
  P1 + 
  geom_point() 
  1. Om de datapunten een andere vorm en kleur te geven naar geslacht, worden in geom_point() nieuwe ingrediënten (aesthetics) toegevoegd d.m.v. aes(color = sex, shape = sex). Omdat de datapunten soms overlappen, wordt er transparantie toegevoegd aan de punten (alpha = .8) en ook de grootte van de punten wordt aangepast (size = 3). Tenslotte wordt er ook aangegeven welke kleuren er gebruikt dienen te worden via scale_color_manual(values = c("darkorange", "purple")).
Klik hier voor code
P3 <- 
  P2 +
  geom_point(
    aes(color = sex, shape = sex), 
    alpha = .8, 
    size = 3    
    ) +
  scale_color_manual(
    values = c("darkorange","purple")
    ) 
  1. In de vierde stap wordt een trendlijn toegevoegd aan de plot. Hiervoor wordt een tweede geom gebruikt: geom_smooth(). Met het argument method = "lm" geven we aan dat we een lineaire trendlijn willen.
Klik hier voor code
P4 <- P3 + geom_smooth(method = "lm") 
  1. We willen graag een aparte trendlijn voor de mannelijke en vrouwelijke pinguïns. Dit wordt aangegeven door aes(color = sex) toe te voegen aan de functie geom_smooth(). Het argument se = F geeft aan dat we GEEN betrouwbaarheidsinterval rond de trendlijnen willen.
Klik hier voor code
P5 <- P3 +
  geom_smooth(
    aes(color = sex),
    se = F,
    method = "lm"
    )
  1. De labels van de x- en y-as krijgen een andere naam via de functies scale_x_continuous() en scale_y_continuous().
Klik hier voor code
P6 <- 
  P5 +
  scale_x_continuous("Flipper length (mm)") +
  scale_y_continuous("Body Mass (g)")
  1. In de zevende stap wordt het plot-thema aangepast naar theme_minimal().
Klik hier voor code
P7 <- P6 + theme_minimal()
  1. De laatste stap bestaat uit het toevoegen van een titel en subtitel. Hiervoor wordt de labs()-functie gebruikt (via de argumenten title en subtitle.
Klik hier voor code
P8 <- P7 +
  labs(
    title = "Palmer penguins",
    subtitle = "Flipper length and body mass for both sexes"
    )

Na deze korte introductie duiken we verder de wereld van ggplot2 in.