Verwacht hier niet een uitputtende beschrijving en uitleg te vinden. In 80% van de gevallen zul je echter heel goed uit de voeten kunnen met wat je op deze website kunt vinden.
Data wordt makkelijker geconsumeerd als visualisaties. Het is veelal
de beste methode om de informatie uit de data te communiceren. Alle
inspanningen kunnen voor niks zijn geweest als je de inzichten uit data
en bijbehorende analyses niet goed over kunt over kunt brengen.
Ondanks het feit dat het maken van visualisaties ongelofelijk eenvoudig
kan zijn in R, speelt ggplot2 een zeer belangrijke rol als dé standaard
in visualisaties voor R.
Het is mij opgevallen dat er maar weinig documentatie over het
ggplot2 is in het Nederlands is. Zodoende ben ik begonnen een naslagwerk
voor mezelf te maken. In de open source geest van R en ggplot2, lijkt
het me niet meer dan logisch om dit openbaar te delen met iedereen die
het wil lezen.
Wat er wel is, is een Nederlandstalige versie van het ggplot2
cheatsheet. Ik gebruik dit spiekbriefje (met dank aan rstudio rstudio
spiekbriefjes) bij de uitleg en houd de volgorde van het
spiekbriefje aan.
ggplot2 is een package voor R https://www.r-project.org/about.html. Met ggplot2 is er
gepoogd een structuur te ontwikkelen voor het maken van visualisaties.
Daarom wordt er ook wel gesproken over de gramatica van
visualisaties.
Er is uitstekende (Engelstalige) informatie beschikbaar over ggplot2,
waaruit ik mede mijn inspiratie op heb gedaan.
Uiteraard zijn er nog veel andere (gratis) online bronnen.
Veel van de voorbeelden die je aan zult treffen komen uit, of zijn
geïnspireerd op bovenstaande bronnen. Waar mogelijk zal ik naar bronnen
verwijzen.
Je kunt alleen met ggplot2 werken als je het package geïnstalleerd en
geladen hebt. Installeren doe je eenmalig met de opdracht
install.packages("ggplot2"). Het laden van het package in
de R-sessie doe je middels library(ggplot2).
Overige benodigde packages zijn:
Als je de onderstaande code altijd aan je script toevoegt, dan zijn alle tools die je nodig hebt voor het maken van visualisaties beschikbaar.
# Package names
packages <- c("ggplot2",
"maps", # maken van kaarten als input voor ggplot
"patchwork", # grafieken naast elkaar kunnen tonen
"tidyverse")
# Install packages not yet installed
installed_packages <- packages %in% rownames(installed.packages())
if (any(installed_packages == FALSE)) {
install.packages(packages[!installed_packages])
}
# Packages loading
lapply(packages, library, character.only = TRUE)In de basis heb je voor een visualisatie maar een paar dingen nodig, namelijk:
Conform het voorbeeld (in het blok met de witte achtergrond) op dit gedeelte van het spiekbriefje:
# data
mpg %>%
# canvas / globale toewijzingen
ggplot(aes(x = hwy, y = cty)) + # data toewijzen x- en y-as
# weergavelagen
geom_point(aes(color = cyl)) + # spreidingsdiagram, kleur per aantal cylinders
geom_smooth(method = "lm") # lineare regressielijn door de data puntenMet qplot kun je exact dezelfde grafiek maken. Deze sla ik echter over, omdat ik qplot vrijwel nooit gebruik.
Uitleg:
mpg is de datasetggplot(aes(x=hwy, y=cty)) wijst de variabele
hwy toe aan de x-as en cty aan de y-as+ toevoeging van een laag of een elementgeom_point(aes(color = cyl)) voegt een weergavelaag toe
van het type spreidingsdiagram (laat de data in puunten zien) en maakt
dat de kleur afhankelijk is van de waarde van de variabele
cyl.+ toevoeging van een laag of een elementgeom_smooth(method = "lm") voegt een lineaire
regressielijn toe inclusief het betrouwbaarheidsinterval.Dit is vrij eenvoudig uit te breiden met bijvoorbeeld kleur, doorzichtigheid en titels:
# data
mpg %>%
mutate(cyl = as.factor(cyl)) %>% # categorische variabele van cyl maken
# canvas / globale toewijzingen
ggplot(aes(x = hwy, y = cty)) + # data toewijzen x- en y-as
# weergavelagen
geom_point(
aes(color = cyl), # spreidingsdiagram, kleur per aantal cylinders
alpha = 0.25 # mate van ondoorzichtigheid
) +
geom_smooth(method = "lm") + # lijn voor lineare regressie door de data punten
# opmaak
labs(
title = "Verbruik op snelweg t.o.v in de stad", # grafiektitel
subtitle = "Verbruiken hangen sterk met elkaar samen", # subtitel
color = "aantal\ncylinders", # legenda titel (\n = nieuwe regel)
x = "Afstand per gallon op de snelweg", # titel x-as
y = "Afstand per gallon in de stad", # titel y-as
caption = "dataset: mpg" # bijschrift
) +
theme_minimal() # thema met minimale opmaakMet elke + wordt een element of laag toegevoegd.
Daarnaast wordt alles wat je in de opdracht ggplot()
meegeeft door de onderliggende elementen overerfd. Zo kun je de
toewijzing van variabelen aan de x- en/of y-as, een vulkleur enzovoort
ook al in deze opdracht meegeven.
Uitleg:
mpg is de datasetmutate(cyl = as.factor(cyl)) zorgt ervoor dat de
waarden in de variabele cyl als categorieën gezien
wordenggplot(aes(x=hwy, y=cty)) wijst de variabele
hwy toe aan de x-as en cty aan de y-asgeom_point(aes(color = cyl)) voegt een weergavelaag toe
van het type spreidingsdiagram (laat de data in puunten zien) en maakt
dat de kleur afhankelijk is van de waarde/categorie van de variabele
cyl.geom_smooth(method = "lm") voegt een lineaire
regressielijn toe inclusief het betrouwbaarheidsinterval.De titel (title)
De subtitel (subtitle)
Voor de legenda (color)
Voor de x-as (x)
Voor de y-as (y)
Het bijschrift (caption)
theme_minimal()).Hierdoor ziet de grafiek er al een heel stuk beter, leesbaarder en informatiever uit dan enkel met de minimale inspanning.
Van de onderdelen in het spiekbriefje, zullen de volgende soorten weergavelagen aan bod komen:
In alle gevallen ligt de focus op de meest gebruikte weergavelagen.
Hier heb je het meeste aan en als je deze onder de knie hebt, lukt het
waarschijnlijk ook goed om met de andere een goede visualisatie te
maken.
De geoms zullen in de genoemde volgorde behandeld worden, waarbij eerst
een eenvoudig voorbeeld getoond wordt (het voorbeeld op het
spiekbriefje) en vervolgens een vergelijkbare visualisatie met
uitgebreidere opmaak en opties.
Van de weegavelagen zullen de volgende behandeld worden:
|
Geom_density resulteert in een dichtheidsgrafiek. De totale oppervlakte onder de lijn (of van het ingekleurde vlak) = 1. Daarmee wordt de verdeling van een variabele inzichtelijk gemaakt. Voordeel ten opzichte van een histogram is dat er geen risico op vertekening is door de keuze van het aantal staven dat getoond wordt. De x-as heeft een continue verdeling.
# data
mpg %>%
# globale toewijzingen
ggplot(aes(x = hwy)) +
# weergavelagen
geom_density() +
# titel
labs(title = "basisgrafiek")# data
mpg %>%
# globale toewijzingen
ggplot(aes(x = hwy)) +
# weergavelagen
geom_density(
aes(
fill = drv, # vulkleur, soort aandrijving
color = drv # kleur van de rand, soort aandrijving
),
alpha = 0.25
) +
# verder opmaak
labs(title = "Verdeling van Verbruik op de snelweg", # titel
x = "verbruik op de snelweg", # titel x-as
y = NULL, # geen titel y-as
caption = "mpg dataset",
fill = "type\naandrijving" # legenda-titel (obv vulkleur)
) +
theme_minimal() + # thema vrijwel zonder opsmuk
theme(
panel.grid.major = element_blank(), # geen primaire rasterlijnen
panel.grid.minor = element_blank() # geen secundaire rasterlijnen
) +
guides(color=FALSE) # geen legenda voor randkleurVoor een uitgebreide dichtheidsgrafiek voeg je elementen toe aan de eerder genoemde basis-elementen. Bijvoorbeeld:
fill = drv
(vulkleur) en colour = drv (lijnkleur) en het vrijwel
doorzichtig maken van de vulkleur alpha = 0.25. Dit laatste
moet buiten de aes() omdat dit niet een toewijzing van een
variabele uit de data is, maar een globale aanduiding dat de vulkleuren
25% ondoorzichtig moeten zijn;labs();theme_minimal();theme();color. Als deze
niet weggelaten wordt, krijg je zowel een legenda voor fill
als voor color, omdat deze beide gespecificeerd zijn in de
aes() van geom_density().Het histogram is een bekende grafiek en toont de verdeling van een variabele door de de waarden te groeperen en de telling van het aantal waarnemingen te tonen middels balken.
De belangrijkste eigenschap van het histogram is het aantal groepen of de groepsbreedte. Een foute keuze hierin kan leiden tot een vertekend beeld van de verdeling. Ga hier dus voorzichtig mee om.
Dit type grafiek is niet erg geschikt om meerdere verdelingen in 1 grafiek te tonen. Door de grafieken naast elkaar te tonen, kan dit wel. Verderop zal uitgelegd worden hoe je dit doet.
# data
mpg %>%
# globale toewijzingen
ggplot(aes(x = hwy)) + # hwy toewijzen aan de x-as
# weergavelagen
geom_histogram() # histogram met standaardinstelling# data
mpg %>%
# globale toewijzingen
ggplot(aes(x = hwy)) + # hwy toewijzen aan de x-as
# weergavelagen
geom_histogram(
aes(fill = drv),
bins = 25, # aantal balken in het histogram
fill = "Darkblue", # opvulkleur
color = "white" # kleur van de rand
) +
stat_bin(
aes(y = ..count.., label = ..count..), # waarden voor y en de labels
bins = 25, # aantal balken
geom = "text", # is als geom_text
vjust = 1, # aanpassing positie van de tekst
color = "white" # kleur van de tekst
) +
# overige opmaak
labs(
# titels, assen en dergelijke
title = "Telling van auto modellen naar verbruik op de snelweg",
x = "verbruik op de snelweg",
y = "aantal modellen",
caption = "dataset: mpg"
) +
theme_minimal() + # minimale opmaak als thema
scale_x_continuous(
breaks = seq(from = 10, to = 45, by = 5) # aangepaste x-as labels
)Het eenvoudige voorbeeld is een stuk aantrekkelijker te maken door de volgende wijzigingen toe te passen:
Het aantal balken iets lager te zetten dan de standaard 30 met
bins = 25
De kleurstelling aan te passen, zodat de balken blauw zijn
fill = "Darkblue" en de verschillende balken goed van
elkaar te onderscheiden zijn color = "white"
De aantallen in wit toe te voegen binnenin de balken met
stat_bin()
Titels en dergelijke toevoegen in het labs() argument
Minimale opmaak toepassen theme_minimal()
De schaalverdeling op de x-as aan te passen met
scale_x_continuous().
Minimum: 10, maximum: 45, in stappen van 5.
Het staafdiagram is vergelijkbaar met het histogram. Echter de variabele op de x-as hoeft niet in groepen of balken ingedeeld te worden voordat de het aantal observaties weergegeven kan worden.
Het staafdiagram komt ook nog terug bij de combinatie van een
categorische variabele met een continue variabele. Dan gebruik je
geom_col. Bij geom_bar() is het uitgangspunt
dat het (gewogen) aantal observaties getoond wordt.
# data
mpg %>%
# globale toewijzingen
ggplot(aes(x = fl)) +
# weergavelagen
geom_bar()mpg %>% # dataset
ggplot(aes(x = fl)) + # brandstoftype op de x-as
geom_bar( # staafdiagram
aes(fill = fl) # kleurvulling --> brandstoftype
, colour = "black" # kleur van de buitenrand van de staven
) +
geom_text( # labels voor de staven
stat='count', # stat='count' geeft het aantal van de x-variabele
aes(label=..count..), # aantal als label
# label = verwijst naar 'count' in stat='count'
colour = "white", # tekstkleur voor het label
vjust=1 # aanpassing van het label --> in de staaf
) +
labs(title = "MPG dataset", # grafiektitel
subtitle = "Aantal modellen naar brandstoftype", # subtitel
x = "brandstof type", # titel x-as
y = "aantal") + # titel y-as
theme_minimal() + # thema vrijwel zonder opsmuk
theme(
panel.grid.major = element_blank(), # geen primaire rasterlijnen
panel.grid.minor = element_blank(), # geen secundaire rasterlijnen
legend.position='none' # geen legenda
)Voor een uitgebreid staafdiagram voeg je elementen toe aan de eerder genoemde basis-elementen. Bijvoorbeeld:
Een kleur die aan de staaf toegewezen wordt op basis van het
brandstoftype (fl). Dit doordat fill = fl is
opgenomen in de aes van geom_bar;
Het aantal waarnemingen in het wit in de staaf weergeven.
geom_text (tekst);stat='count' (geeft het aantal waarnemingen) en
label=..count.. (geeft het aantal waarnemingen door aan het
tekstlabel);colour = "white" (label in het wit);vjust=1 (kleine verticale aanpassing, standaard wordt
het label boven de staaf geprojecteerd).(Aangepaste) titel, subtitel en as-titels door middel van
labs();
Een hele basic / schone weergave door gebruik van
theme_minimal();
Het niet weergeven van rasterlijnen en legenda met de opdrachten
binnen theme().
Van de weergavelagen op het spiekbriefje zal ik aandacht besteden aan:
|
geom_jitter() en geom_point() lijken erg op
elkaar. Het zijn beide spreidingsgrafieken.
Daar waar geom_point() de punten in de grafiek exact op de
plek plaats die de data aangeeft, voegt geom_jitter() en
wat ruis aan toe, zodat de punten niet/minder overlappen.
Als je veel datapunten hebt, dan kan geom_jitter() een
betere keuze zijn, maar ook het gebruik van de doorzichtigheid
(alpha) kan hier erg nuttig bij zijn.
Bekijk de grafieken en zie de verschillen die exact dezelfde code met alleen een andere geom veroorzaakt.
# data
mpg %>%
# canvas / globale toewijzingen
ggplot(aes(x=hwy, y=cty)) + # data toewijzen x- en y-as
# weergavelagen
geom_jitter()Je ziet duidelijk dat met geom_jitter() de individuele
waarnemingen beter te zien zijn dan de grafiek met
geom_point().
# data
mpg %>%
# canvas / globale toewijzingen
ggplot(aes(x=hwy, y=cty)) + # data toewijzen x- en y-as
# weergavelagen
geom_point()# data
mpg %>%
mutate(cyl = as.factor(cyl)) %>% # categorische variabele van cyl maken
# canvas / globale toewijzingen
ggplot(aes(x=hwy, y=cty)) + # data toewijzen x- en y-as
# weergavelagen
geom_jitter(aes(color = cyl),
alpha = 0.5) +
geom_hline(yintercept = mean(mpg$cty)) +
geom_vline(xintercept = mean(mpg$hwy)) +
# opmaak
labs(
title = "Stad vs snelweg verbruik",
subtitle = "Modellen met 4 cilinders doen het bovengemiddeld goed",
x = "Mijlen per gallon op de snelweg", # titel x-as
y = "Mijlen per gallon in de stad", # titel y-as
caption = "data set: mpg"
) +
theme_minimal()De volgende aanpassingen laten de grafieken er aantrekkelijker uitzien:
Kleur en doorzichtigheid van de de punten via
aes(color = cyl), alpha = 0.5.
Een horzontale
(geom_hline(yintercept = mean(mpg$cty))) en verticale
referentielijn (geom_hline(yintercept = mean(mpg$cty))) om
het gemiddelde daan te geven
Wijzigen van de titel, de as-titels en toevoegen van de bron van
de data via labs();
Een hele basic / schone weergave door gebruik van
theme_minimal().
# data
mpg %>%
mutate(cyl = as.factor(cyl)) %>% # categorische variabele van cyl maken
# canvas / globale toewijzingen
ggplot(aes(x = hwy, y = cty)) + # data toewijzen x- en y-as
# weergavelagen
geom_point(
aes(color = cyl), # spreidingsdiagram, kleur per aantal cylinders
alpha = 0.25 # mate van ondoorzichtigheid
) +
geom_hline(yintercept = mean(mpg$cty)) +
geom_vline(xintercept = mean(mpg$hwy)) +
# opmaak
labs(
title = "Verbruik op snelweg t.o.v in de stad", # grafiektitel
subtitle = "Meer cilinders betekent kleinere afstand per gallon",
color = "aantal\ncylinders", # legenda titel
x = "Mijlen per gallon op de snelweg", # titel x-as
y = "Mijlen per gallon in de stad", # titel y-as
caption = "dataset: mpg" # bijschrift
) +
theme_minimal() # thema met minimale opmaakDe volgende aanpassingen laten de grafieken er aantrekkelijker uitzien:
Kleur en doorzichtigheid van de de punten via
aes(color = cyl), alpha = 0.5.
Een horzontale
(geom_hline(yintercept = mean(mpg$cty))) en verticale
referentielijn (geom_hline(yintercept = mean(mpg$cty))) om
het gemiddelde daan te geven
Wijzigen van de titel, de as-titels en toevoegen van de bron van
de data via labs();
Een hele basic / schone weergave door gebruik van
theme_minimal().
Ook met deze 2 grafieken is het verschil uitermate duidelijk. Ook in
dit geval geeft geom_jitter() meer informatie. Bij veel
datapunten is geom_jitter() dus de betere keuze.
geom_smooth geeft een gemodelleerde lijn weer door de dataset met onzekerheidsmarges (standaard een gebied om de lijn dat ingekleurd wordt). Als je geen argumenten meegeeft, wordt er een standaard methode en formule voor de schattingslijn gekozen op basis van de data.
# data
mpg %>%
# canvas / globale toewijzingen
ggplot(aes(x=hwy, y=cty)) + # data toewijzen x- en y-as
# weergavelagen
geom_smooth(method = "lm") # trendlijn linear model (= lineaire regressie)# data
mpg %>%
mutate(cyl = as.factor(cyl)) %>% # categorische variabele van cyl maken
# canvas / globale toewijzingen
ggplot(aes(x=hwy, y=cty)) + # data toewijzen x- en y-as
# weergavelagen
geom_jitter(aes(color = cyl),
alpha = 0.5) +
geom_hline(yintercept = mean(mpg$cty)) +
geom_vline(xintercept = mean(mpg$hwy)) +
geom_smooth(method = "lm") +
# opmaak
labs(
title = "Stad vs snelweg verbruik",
subtitle = "Modellen met 4 cilinders doen het bovengemiddeld goed",
x = "Mijlen per gallon op de snelweg", # titel x-as
y = "Mijlen per gallon in de stad", # titel y-as
caption = "data set: mpg"
) +
theme_minimal()Als uitgebreid voorbeeld hier geom_smooth() toegevoegd
aan het uitgebreide voorbeeld voor geom_jitter(). Veelal
zul je geom_smooth() in combinatie met een
spreidingsgrafiek gebruiken. Het aanroepen van
geom_smooth() hierin niet anders dan in het eenvoudige
voorbeeld. De overige delen komen uit het uitgebreide voorbeeld rondom
geom_jitter().
Tekst in een grafiek kan heel verhelderend zijn. Bijvoorbeeld door waardes of labels in een grafiek toe te voegen. Maar ook door specifieke waardes uit te lichten of een zogenaamde wordcloud (die wordt hier niet behandeld).
Tekst in een grafiek zul je vaak, maar niet altijd combineren met andere weergavelagen. Dat hebben we bijvoorbeeld al gezien bij het uitgebreide staafdiagram. De waardes in de balken/staven zijn tekstwaardes. Een ander voorbeeld waarin labels vaak gebruikt worden is een lollipop-diagram. Daarvan is een voorbeeld opgenomen in Lollipop-diagram.
# data
mpg %>%
# canvas / globale toewijzingen
ggplot(aes(x=hwy, y=cty)) + # data toewijzen x- en y-as
# weergavelagen
geom_text(aes(label = cty))# data
mpg %>%
# samenvatten per type aandrijving
group_by(drv) %>%
summarise(cty = mean(cty),
hwy = mean(hwy)) %>%
ungroup() %>%
# drv in leesbare termen
mutate(drv = recode(drv,
f = "voorwielaandrijving",
r = "achterwielaandrijving",
"4" = "vierwielaandrijving",
.default = NA_character_)) %>%
# canvas / globale toewijzingen
ggplot(
aes(x = cty, y = hwy, color = drv) # data toewijzen x-as, y-as en kleur
) +
# weergavelagen
# laag met punten voor waardes
geom_point() +
# laag met tekst
geom_text(
aes(label = drv), # tekst toewijzen aan drv variabele
hjust = 0.5, # horizontale aanpassing positie tekst
vjust = -0.5 # verticale aanpassing positie tekst
) +
# opmaak
labs(
title = "Stad vs snelweg verbruik",
subtitle = "Modellen met Voorwielaandrijving zijn het zuinigst",
x = "Mijlen per gallon op de snelweg", # titel x-as
y = "Mijlen per gallon in de stad", # titel y-as
caption = "data set: mpg"
) +
theme_minimal() +
expand_limits(x = c(5, 25), # x-as uitbreiden om de tekst volledig te tonen
y = c(15, 30)) + # y-as uitbreiden om de tekst volledig te tonen
theme(legend.position = "none")Voor het uitgebreide voorbeeld zijn de volgende stappen genomen:
De data voorbereiden voor de grafiek;
cty aan de x-as en hwy aan de y-as
toewijzen, de kleur wordt bepaald door de waarde van
drv;
Tekst toevoegen geom_text(), waarbij de tekst
bepaald wordt door de variabele drv en de positie zowel horizontaal als
verticaal aangepast wordt (daarover later meer;
Titels en dergelijke toevoegen labs();
Minimale opmaak voor het thema
theme_minimal();
De boven- en ondergrens van de x- en y-as vastleggen via
expand_limits();
De legenda verwijderen via theme();
Van de weergavelagen op het spiekbriefje zal ik aandacht besteden aan:
|
We hebben het staafdiagram al eerder gezien, namelijk in de paragraaf
1 categorische variabele.
Daar werd het staafdiagram getoond met 1 categorische variabele en een
telling van het aantal waarnemingen. Net als een histogram dus.
Nu dus een staafdiagram met 1 categorische variabele en 1 continue. Het voorbeeld van het spiekbriefje is een weinig betekenisvol voorbeeld. Het toont de som van het aantal mijlen per gallon als waarde van de class (type) auto. De continue variabele kun je echter niet zo op een betekenisvolle manier optellen. Voor het voorbeeld heb ik dus eerst het gemiddelde berekend, zodat de gemiddelde afstand per model per gallon getoond wordt.
geom_bar() verwacht eigenlijk geen y-waarde. Het
gedraagt zich standaard als een histogram (telt het aantal waarnemingen
en toont die waardes). Als je de gegevens wil tonen zoals ze in de
dataset voorkomen (of hoe jij ze zelf samenvat), dan moet je
stat = "identity" gebruiken.
Je zou ook geom_col() kunnen gebruiken. Standaard toont
deze de waardes die je aanlevert. Hieronder zie je dat beide varianten
exact dezelfde grafiek opleveren.
In deze categorie gaat mijn voorkeur daarom uit naar
geom_col().
# data
mpg %>%
# 1 modeljaar laten zien
filter(year == 2008) %>%
# gemiddelde per `class` uitrekenen
group_by(class) %>%
summarise(hwy = mean(hwy)) %>%
# canvas / globale toewijzingen
ggplot(aes(x=class, y=hwy)) + # data toewijzen x- en y-as
# weergavelagen
geom_bar(stat = "identity") +
labs(title = "geom_bar(stat = 'identity')")# data
mpg %>%
# 1 modeljaar laten zien
filter(year == 2008) %>%
# gemiddelde per `class` uitrekenen
group_by(class) %>%
summarise(hwy = mean(hwy)) %>%
# canvas / globale toewijzingen
ggplot(aes(x=class, y=hwy)) + # data toewijzen x- en y-as
# weergavelagen
geom_col() +
labs(title = "geom_col()")# data
mpg %>%
# 1 modeljaar laten zien
filter(year == 2008) %>%
# gemiddelde per `class` uitrekenen
group_by(class) %>%
summarise(hwy = mean(hwy)) %>%
arrange(desc(hwy)) %>%
mutate(class = as_factor(class) %>% fct_rev()) %>%
# canvas / globale toewijzingen
ggplot(aes(x=class, y=hwy, fill = class)) + # data toewijzen x- en y-as
# weergavelagen
geom_col() +
# opmaak
coord_flip() +
labs(
title = "Gemiddelde afstand op de snelweg", # grafiek titel
subtitle = "naar type auto", # subtitel
x = NULL, # titel x-as
y = "Mijlen per gallon op de snelweg", # titel y-as
caption = "data set: mpg" # toelichting
) +
theme_minimal() +
theme(legend.position = "none")Aanpassingen voor het uitgebreide voorbeeld:
De data bewerken zodat er gesorteerd wordt op de waarde in
hwy;
Opvulkleur per categorie van class via fill = class
in aes();
Uitgebreide titels via labs();
Minimale thema toepassen via
theme_minimal();
De legenda verwijderen via theme().
De boxplot geeft inzicht in de verdeling van de waarnemingen van de variabele. Voor uitleg zie boxplot op wikipedia.
# data
mpg %>%
# canvas / globale toewijzingen
ggplot(aes(x=class, y=hwy)) + # data toewijzen x- en y-as
# weergavelagen
geom_boxplot()# data
mpg %>%
# sorteren op mediaan van hwy
group_by(class) %>%
mutate(hwy_median = median(hwy)) %>%
ungroup() %>%
arrange(desc(hwy_median)) %>%
mutate(class = as_factor(class) %>% fct_rev()) %>%
# canvas / globale toewijzingen
# data toewijzen x- en y-as & kleur toewijzen obv class
ggplot(aes(x=class, y=hwy, fill = class)) +
# weergavelagen
stat_boxplot(geom = "errorbar") + # voegt de dwarsliggende lijnen toe
geom_boxplot(notch = TRUE) + # inkeping bij de mediaan (90% vd waarn.)
# opmaak
coord_flip() + # grafiek kantelen, zodat class op de y-as komt
labs(
title = "Verdeling afstand per gallon", # grafiektitel
subtitle = "naar type auto", # subtitel
x = NULL, # titel x-as
y = "Mijlen per gallon op de snelweg", # titel y-as
caption = "data set: mpg" # toelichting
) +
theme_minimal() +
theme(legend.position = "none")Aanpassingen voor de uitgebreide versie:
hwy;fill = class in
aes();stat_boxplot(geom = "errorbar");notch = TRUE te
gebruiken;labs();theme_minimal();theme().Het viooldiagram is een bewerking van de boxplot, die de verdeling wat beter laat zien. Daar waar het diagram smal is, zijn weinig waarnemingen en waar het breed is, veel.
# data
mpg %>%
# canvas / globale toewijzingen
ggplot(aes(x=class, y=hwy)) + # data toewijzen x- en y-as
# weergavelagen
geom_violin()# data
mpg %>%
# sorteren op mediaan van hwy
group_by(class) %>%
mutate(hwy_median = median(hwy)) %>%
ungroup() %>%
arrange(desc(hwy_median)) %>%
mutate(class = as_factor(class) %>% fct_rev()) %>%
# canvas / globale toewijzingen
# data toewijzen x- en y-as & kleur toewijzen obv class
ggplot(aes(x=class, y=hwy, fill = class, color = class)) +
# weergavelagen
geom_boxplot(notch = TRUE, alpha = 0.5) +
geom_jitter(alpha = 0.25) +
geom_violin(alpha = 0.5) +
# opmaak
coord_flip() +
labs(
title = "Verdeling afstand per gallon",
subtitle = "naar type auto",
x = NULL, # titel x-as
y = "Mijlen per gallon op de snelweg", # titel y-as
caption = "data set: mpg"
) +
theme_minimal() +
theme(legend.position = "none")Aanpassingen voor de uitgebreide versie:
hwy;fill = class, color = class in aes();geom_boxplot();geom_jitter();geom_violin() gedeeltelijk doorzichtig maken via
alpha = 0.5;labs();theme_minimal();theme().Van de weergavelagen op het spiekbriefje zal ik aandacht besteden aan:
|
# data
diamonds %>%
# canvas / globale toewijzingen
ggplot(aes(x=cut, y=color, color = clarity)) + # data toewijzen x- en y-as
# weergavelagen
geom_jitter()Persoonlijk vind ik het bovenstaande geen goed voorbeeld. Ik heb al
de clarity toegevoegd om het aangenamer te maken voor het
oog. Wat goed te zien is, is waar er veel en waar er weinig waarnemingen
zijn.
# data
msleep %>%
select(conservation, order, vore) %>%
drop_na() %>%
arrange(order, conservation) %>%
mutate(order = as_factor(order) %>% fct_rev()) %>%
# canvas / globale toewijzingen
ggplot(aes(x=conservation, y=order, color = vore)) + # data toewijzen x- en y-as
# weergavelagen
geom_count() +
# opmaak
labs(
title = "Mammals in sleep dataset",
y = "Mammal order",
color = "diet"
) +
theme_minimal() Dit voorbeeld is gemaakt met geom_count().
Er zijn nog wel andere mogelijkheden, maar die worden hier niet behandeld.
Van de weergavelagen op het spiekbriefje zal ik aandacht besteden aan:
|
Met deze geom teken je rechthoeken, die met de z-variabele een kleur of tint. Dit maakt deze visualisatie erg geschikt om heatmaps te maken.
De dataset die in het spiekbriefje gebruikt wordt, spreekt niet erg
aan. Er is voor de dataset diamonds gekozen, omdat ik deze
beter/duidelijk vind voor het voorbeeld.
diamonds %>%
group_by(color, cut) %>%
summarise(price = median(price)) %>%
ungroup() %>%
ggplot(aes(x = color, y = cut, z = price)) +
geom_tile(aes(fill = price))# data
# welke categorie heeft de hoogste prijs
best_cat <-
diamonds %>%
group_by(color, cut) %>%
summarise(price = median(price)) %>%
ungroup() %>%
slice_max(order_by = price, n = 1)
# levels voor variabelen om een rand toe te voegen aan de cel met de hoogste prijs
color_list <- levels(diamonds$color)
cut_list <- levels(diamonds$cut)
# grafiek opbouwen
# data
diamonds %>%
group_by(color, cut) %>%
summarise(price = median(price)) %>%
ungroup() %>%
# ggplot
ggplot(aes(x = color, y = cut, z = price)) +
# weergavelagen
# - tegeldiagram
geom_tile(aes(fill = price)) +
# - waarden in cellen
geom_text(aes(label = scales::dollar(price, accuracy = 100)),
color = "white") +
# - rand toevoegen aan de hoogste waarde
geom_rect(size = 2, fill = NA, colour="white",
aes(xmin=which((color_list %>% fct_rev()) %in% best_cat$color) - 0.5,
xmax=which(color_list %in% best_cat$color) + 0.5,
ymin=which(cut_list %in% best_cat$cut) - 0.5,
ymax=which(cut_list %in% best_cat$cut) + 0.5)) +
# opmaak
labs(
title = "Prijs van diamanten",
subtitle = "Mediane prijs per groep",
x = "kleur",
y = "slijpvorm",
color = "prijs"
) +
theme_minimal() Voor het uitgebreide voorbeeld zijn de volgende stappen genomen:
De data voorbereiden voor de grafiek;
Vulkleur op basis van price;
de waarde van price weergeven in elke
“tegel”;
Een rand rondom de tegel met de hoogste prijs met
geom_rect();
Titels en dergelijke toevoegen labs();
Minimale opmaak voor het thema
theme_minimal().
Als je serieus met geografische informatie aan de slag gaat, dan raad ik je aan om kaarten te maken met packages die daar erg geschikt voor zijn, zoals leaflet en mapview. Deze tools vragen wel om data met een geografische component
Eenvoudige kaarten kunnen ook in ggplot gemaakt worden met het
maps package.
data <-
data.frame(murder = USArrests$Murder,
state = tolower(rownames(USArrests)))
map <- map_data("state")
data %>%
ggplot(aes(fill = murder)) +
geom_map(aes(map_id = state), map = map) +
expand_limits(x = map$long, y = map$lat)# data
data <-
data.frame(murder = USArrests$Murder,
state = tolower(rownames(USArrests)))
map <- map_data("state")
data %>%
ggplot(aes(fill = murder)) +
# weergavelagen
geom_map(aes(map_id = state), map = map) +
expand_limits(x = map$long, y = map$lat) + #
# opmaak
labs(
title = "Hoe gevaarlijk is een 'US state?'",
x = "",
y = "",
fill = paste0("aantal\nmoorden")
) +
theme_minimal() +
theme(axis.text = element_blank(),
panel.grid = element_blank())Voor het uitgebreide voorbeeld zijn de volgende stappen genomen:
Titels en dergelijke toevoegen labs();
Minimale opmaak voor het thema
theme_minimal();
Verwijderen van de waardes op de x- en y-as met
theme(axis.text = element_blank());
Het raster verwijderen met
theme(panel.grid = element_blank()).
Tijdreeksen zijn vaak lijndiagrammen, maar kunnen ook bijvoorbeeld boxplots zijn. De overeenkomst is dat er altijd een tijd, datum of periode op de x-as staat. Je kunt deze grafieken/diagrammen helemaal met ggplot2 maken. Als je hier serieus mee aan de slag wil, dan zou ik je aanraden om het timetk package te gebruiken, waarin mooie plot-functies opgenomen zijn.
# data
economics %>%
# basis grafiek
ggplot(aes(date, unemploy)) +
geom_line()# data
economics %>%
# basis grafiek
ggplot(aes(date, unemploy)) +
# weergavelagen
geom_line() +
geom_smooth(se = FALSE) +
# opmaak
labs(
title = "Werkloosheid in de VS",
x = "",
y = "x 1000 personen",
caption = "bron: https://fred.stlouisfed.org/series/UNEMPLOY"
) +
theme_minimal() +
scale_y_continuous(labels = scales::comma)Voor het uitgebreide voorbeeld zijn de volgende stappen genomen:
Toevoegen van een trendlijn middels
geom_smooth(se = FALSE) (zonder bandbreedte);
Titels en dergelijke toevoegen labs();
Minimale opmaak voor het thema
theme_minimal();
Waardes op de y-as netjes opmaken met
scale_y_continuous(labels = scales::comma).
Zelf vind ik de duidelijkste variant om een foutrange aan te
geven een combinatie van Deze zal ik hieronder laten zien. |
Voor het visualiseren van fouten wordt fictieve data gegenereerd en niet een dataset uit het ggplot2 package gebruikt. Het eenvoudige voorbeeld ziet er dan als volgt uit:
# data
df <- data.frame(grp = c("A", "B", "C"), fit = c(4, 5, 5.5), se = c(1, 2, 0.5))
# om de data te bekijken
df## grp fit se
## 1 A 4.0 1.0
## 2 B 5.0 2.0
## 3 C 5.5 0.5
df %>%
# basis grafiek
ggplot(
aes(x = grp, # variabele voor de x-as
y = fit, # punt van de waarneming
ymin = fit-se, # y-waarde voor de onderste foutbalk
ymax = fit+se) # y-waarde voor de bovenste foutbalk
) +
# weergavelagen
geom_errorbar() + # foutbalken
geom_point() # punt van de waarneming# data
df <- data.frame(grp = c("A", "B", "C"), fit = c(4, 5, 5.5), se = c(1, 2, 0.5))
# om de data te bekijken
df## grp fit se
## 1 A 4.0 1.0
## 2 B 5.0 2.0
## 3 C 5.5 0.5
df %>%
# basis grafiek
ggplot(
aes(x = grp, # variabele voor de x-as
color = grp, # kleur voor waarneming en lijnen
y = fit, # punt van de waarneming
ymin = fit-se, # y-waarde voor de onderste foutbalk
ymax = fit+se) # y-waarde voor de bovenste foutbalk
) +
# weergavelagen
geom_errorbar(size = 1) + # foutbalken
geom_point(size = 3) + # punt van de waarneming (wat groter gemaakt)
# opmaak
labs(
title = "Waarneming en foutmarge per categorie",
x = "",
y = "waarde"
) +
expand_limits(y = c(0, max(df$fit)+max(df$se))) + # y-as beginnen bij 0
theme_minimal() +
theme(legend.position = "none") # verwijderen van de legendaVoor het uitgebreide voorbeeld zijn de volgende stappen genomen:
Kleur op basis van de variabele grp toegevoegd in de
aes();
De dikte van de errorbar en punt van de waarneming iets vergroot
door het argeument size te gebruiken;
Titels en dergelijke toevoegen labs();
Y-as bij 0 laten beginnen met
Minimale opmaak voor het thema
theme_minimal();
Legenda verwijderd met
theme(legend.position = "none").
Positie aanpassingen bepalen hoe overlappende weergaves getoond worden.
De opties zijn:
|
Het spiekbriefje legt het eigenlijk heel goed uit.
De basisgrafiek is als volgt:
mpg %>%
# basis grafiek
ggplot(aes(x = fl, fill = drv)) +
geom_bar()Als we position = "dodge" gebruiken, dan worden de
balken naast elkaar geplaatst.
mpg %>%
# basis grafiek
ggplot(aes(x = fl, fill = drv)) +
# positie van de balken
geom_bar(position = "dodge")Je kunt met position = position_dodge(width = x) ook
aangeven hoe ver de verschuiving moet zijn. Met x = 0.5
zullen de balken elkaar overlappen en met x = 1 zullen de
balken iets uit elkaar staan (zie hieronder).
Deze instelling kun je ook voor andere weergavelagen (geoms)
gebruiken. Zie daarvoor
?postion_dodge().
mpg %>%
# basis grafiek
ggplot(aes(x = fl, fill = drv)) +
# positie van de balken
geom_bar(position = position_dodge(width = 1))Als we position = "fill" gebruiken, dan worden de balken
gestapeld en genormaliseerd (stapelt tot 100%). Dit is erg geschikt om
het aandeel per categorie aan te geven.
mpg %>%
# basis grafiek
ggplot(aes(x = fl, fill = drv)) +
# positie van de balken
geom_bar(position = "fill")Als we position = "stack" gebruiken, dan worden de
balken gestapeld zonder verdere bewerking. Dit is de
standaardinstelling. Daarmee is de grafiek dus hetzelfde als de basis
grafiek.
mpg %>%
# basis grafiek
ggplot(aes(x = fl, fill = drv)) +
# positie van de balken
geom_bar(position = "stack")Om duidelijk te maken wat position = "jitter" (net als
geom_jitter()) doet, is hieronder een grafiek opgenomen met
de originele punten in rood en sterk doorzichtig en de
"jitter" in het zwart met enige doorzichtigheid.
Doordat sommige punten roder zijn dan anderen, kunnen we zien dat er overlap in waarnemingen is. De zwarte punten kennen nauwelijks overlap.
mpg %>%
# basis grafiek
ggplot(aes(x = cty, y = hwy)) +
# spreidingsgrafiek met doorzichtige punten
geom_point(color = "red", alpha = 0.25) +
# jitter om individuele punten beter zichtbaar te maken
geom_point(position = "jitter", alpha = 0.5)Schalen kunnen in belangrijke mate bepalen hoe je grafiek eruit ziet. Ze hebben invloed op:
De doorzichtigheid (scale_alpha_*)
Kleuren in je grafiek (scale_color_*,
scale_fill_*)
Vormen (scale_shape_*,
scale_linetype_*)
De afmetingen van o.a. lijnen en punten
(scale_size_*)
De assen (scale_x_*,
scale_y_*)
Op elk van de * (behalve voor de assen) kunnen
voorkomen:
continuous, bijvoorbeeld
scale_fill_continous
discrete, bijvoorbeeld:
scale_color_discrete
identity, bijvoorbeeld:
scale_color_identity
manual, bijvoorbeeld: scale_color_manual
Het spiekbriefje gaat in op:
Hiermee heb je controle over het kleurgebruik in de grafiek.
In de voorbeelden van het spiekbriefje worden alleen voorbeelden met
vulkleuren getoond. Je zult hieronder ook voorbeelden van
color vinden in plaats van alleen met
fill. |
# zonder aanpassingen
mpg %>%
ggplot(aes(x = fl)) +
geom_bar()# blauwe balken volgens het aangegeven palette op brandstof type
mpg %>%
ggplot(aes(x = fl)) +
geom_bar(aes(fill = fl)) +
scale_fill_brewer(palette = "Accent")# zonder aanpassingen
mpg %>%
ggplot(aes(x = cty, y = hwy)) +
geom_point()# kleuren op basis van de typologie van de auto
mpg %>%
ggplot(aes(x = cty, y = hwy)) +
geom_point(aes(color = class)) +
scale_color_brewer(palette = "Accent")# zonder aanpassingen
mpg %>%
ggplot(aes(x = hwy)) +
geom_bar()# ingekleurd op basis van brandstofgebruik op de snelweg
mpg %>%
ggplot(aes(x = hwy)) +
geom_bar(aes(fill = ..x..)) + # ..x.. verwijst naar x-waarde van de balk
# dat is dus het resultaat van het groeperen van
# de x-waarde in aes(x = hwy)
scale_fill_gradient(
low = "red",
high = "yellow"
)# zonder aanpassingen
mpg %>%
ggplot(aes(x = cty, y = hwy)) +
geom_point()# kleuren op basis van de typologie van de auto
mpg %>%
ggplot(aes(x = cty, y = hwy)) +
geom_point(aes(color = displ)) +
scale_color_gradient(
low = "blue",
high = "red"
)Hiermee heb je controle over welke vormen je in de grafiek laat zien.
Bij geom_point() is dit standaard een gevuld bolletje.
| Het spiekbriefje biedt hier, behalve een voorbeeld ook een handig overzicht van welk cijfer bij welke vorm hoort. |
# zonder aanpassingen
mpg %>%
ggplot(aes(x = cty, y = hwy)) +
geom_point(aes(shape = fl)) # formen op basis van type brandstof# toon alleen de randen/lijnen van de vorm
mpg %>%
ggplot(aes(x = cty, y = hwy)) +
geom_point(aes(shape = fl)) +
scale_shape(solid = FALSE)# handmatig gekozen vormen
mpg %>%
ggplot(aes(x = cty, y = hwy)) +
geom_point(aes(shape = fl)) +
scale_shape_manual(values = c(3:7))Hiermee heb je controle over bijvoorbeeld de grootte van de punten in een spreidingsgrafiek.
Let op: het voorbeeld op het spiekbriefje klopt hier niet. Het
argument max is vervangen door max_size. |
# zonder aanpassingen, met grootte op basis van het aantal cylinders
mpg %>%
ggplot(aes(x = cty, y = hwy)) +
geom_point(aes(size = cyl))# maximale puntgrootte beperken
mpg %>%
ggplot(aes(x = cty, y = hwy)) +
geom_point(aes(size = cyl)) +
scale_size_area(max_size = 6)Het coördinatensysteem heeft invloed op de x- en de y-as van de grafiek.
Niet alle mogelijkheden worden vaak (door mij) gebruikt. Daarom worden ook niet alle mogelijkheden behandeld. Hieronder zal gekeken worden naar:
|
Dit is het normale coördinatensysteem voor grafieken. Je kunt daarbij als het ware inzoomen op de grafiek door grenswaardes voor de x- en/of y-as op te geven.
# zonder aanpassingen
g1 <- mpg %>%
ggplot(aes(x = hwy)) +
geom_bar() +
labs(title = "zonder aanpassingen")
# alleen de waardes (op de x-as) tussen 10 en 20 tonen
g2 <- mpg %>%
ggplot(aes(x = hwy)) +
geom_bar() +
coord_cartesian(xlim = c(10, 20)) +
labs(title = "x-as beperkt tot tussen 10 en 20")
g1 + g2 # grefieken naast elkaar tonenDoor coord_flip() te gebruiken, kun je de x- en y-as
omwisselen. Je kunt dan bijvoorbeeld een liggend staafdiagram maken.
# zonder aanpassingen
g1 <- mpg %>%
ggplot(aes(x = fl)) +
geom_bar() +
labs(title = "zonder aanpassingen")
# alleen de waardes (op de x-as) tussen 10 en 20 tonen
g2 <- mpg %>%
ggplot(aes(x = fl)) +
geom_bar() +
coord_flip() +
labs(title = "x- en y-as omgewisseld")
g1 + g2 # grefieken naast elkaar tonen# zonder aanpassingen
g1 <- mpg %>%
ggplot(aes(x = hwy)) +
geom_bar() +
labs(title = "zonder aanpassingen")
# alleen de waardes (op de x-as) tussen 10 en 20 tonen
g2 <- mpg %>%
ggplot(aes(x = hwy)) +
geom_bar() +
coord_trans(x = "log10", y = "sqrt") + # omrekenen van de assen
labs(title = "x-as in log schaal, y-as wortel")
g1 + g2 # grafieken naast elkaar tonenGgplot2 kent ook handige functies om je grafiek volgens een discrete variabele op te delen in meerdere grafieken. Dit wordt vaak ook “small multiples” genoemd (bijvoorbeeld in Power BI).
Met Met |
Voorbeelden van facet_grid() worden hieronder
uitgewerkt. Daarbij heb ik een beter leesbare code gebruikt dan op het
spiekbriefje. In plaats van .~variabele is dit
uitgeschreven als cols = vars(variabele) en
variabele~. is uitgeschreven als
rows = vars(variabele).
Dit is uiteraard ook te combineren als
cols = vars(kolom-variabele), rows = vars(rij-variabele).
Om te beginnen een eenvoudig voorbeeld waarbij de grafieken automatisch uitgesplits worden in een aantal kolommen uitgesplits wordt op basis van de fl variabele (= het brandstof type).
# basis grafiek
t <- mpg %>%
ggplot(aes(x = cty, y = hwy)) +
geom_point() +
labs(title = "uitgesplits per brandstof type")
# uitsplitsen in grafieken op basis van fl
t + facet_grid(cols = vars(fl))Op dezelfde manier kun je ook uitsplitsen per rij. In onderstaand voorbeeld gebeurt dit op basis van van het bouwjaar.
# basis grafiek
t <- mpg %>%
ggplot(aes(x = cty, y = hwy)) +
geom_point() +
labs(title = "uitgesplitst naar bouwjaar")
# uitsplitsen in grafieken op basis van year
t + facet_grid(rows = vars(year))Vervolgens een combinatie met uitsplitsing in kolommen op basis van brandstof type en rijen io basis van bouwjaar.
# basis grafiek
t <- mpg %>%
ggplot(aes(x = cty, y = hwy)) +
geom_point() +
labs(title = "uitgesplitst naar brandstof type én bouwjaar")
# uitsplitsen in grafieken op basis van year + brandstof type
t + facet_grid(cols = vars(fl), rows = vars(year))In deze grafiek valt op dat dat sommige combinaties leeg blijven. Bij
facet_grid wordt elke mogelijke combinatie getoond. Ook als
er geen gegevens zijn om in deze combinatie van variabelen.
Als je dat wil voorkomen, kun je facet_wrap gebruiken.
Dezelde grafiek als hierboven maak je dan als volgt:
# basis grafiek
t <- mpg %>%
ggplot(aes(x = cty, y = hwy)) +
geom_point() +
labs(title = "uitgesplitst naar brandstof type én bouwjaar")
# uitsplitsen in grafieken op basis van year + brandstof type
t + facet_wrap(facets = vars(fl, year))Voordeel is dat alleen combinaties met gegevens getoond worden. De
variant met facet_grid kan toch de voorkeur hebben, omdat
categoriën makkelijker te vergelijken zijn.
Wellicht is het opgevallen dat de assen van alle grafieken met
dezelfde reeks aan waarden werken. Dit kun je aanpassen door het
argument scales te gebruiken. Je hebt daarbij de keuze
uit:
# basis grafiek
t <- mpg %>%
ggplot(aes(x = cty, y = hwy)) +
geom_point() +
labs(title = "uitgesplitst naar brandstof type én bouwjaar")
# uitsplitsen in grafieken op basis van year + brandstof type
# & "vrije" x- en y-as
t + facet_wrap(facets = vars(fl, year), scales = "free")Ook hier heb je te maken met een afweging tussen duidelijke individuele grafieken en vergelijkbaarheid.
Titel, labels van assen, legenda en dergelijke kunnen erg belangrijke
elementen zijn voor de leesbaarheid van de grafiek/visual die je
maakt.
Het is aan te raden om hier goed over na te denken, en geen overbodige
informatie te tonen. Wat een goede titel, legenda, enzovoort is, is geen
onderdeel van deze uitleg. Maar het loont beslist de moeite om goed na
te denken over deze onderdelen.
Titel en labels zijn op meerdere manieren toe te voegen. De
eenvoudigste manier is om de labs te gebruiken in plaats
van een functie voor elk van de onderdelen die je toe wil voegen. |
In het onderstaande voorbeeld zijn de veel gebruikte opties van
labs meegenomen.
# basis grafiek
t <- mpg %>%
ggplot(aes(x = cty, y = hwy)) +
geom_point()
# toevoegen van label opties
t +
labs(
title = "Dit is de titel",
subtitle = "Dit is de subtitel",
caption = "Dit is het bijschrift (caption)",
x = "x-as label",
y = "y-as label"
)| Een legenda kun je op verschillende manieren toe- voegen c.q. bewerken. Er zijn behoorlijk wat mogelijkheden voor aanpas- singen. Buiten de mogelijkheden op het spiek- briefje, vind je hieronder ook nog enkele andere mogelijkheden. |
Bedenk bij legenda’s altijd dat deze afhankelijk zijn van de
aesthetics (of aes) die je toevoegt. Je krijgt bijvoorbeeld een legenda
op basis van color, op basis van fill, op
basis van size en op basis van shape.
Bij een combinatie van deze aesthetics, zullen er meerdere legenda’s aan
de grafiek toegevoegd worden
# basis grafiek
t <- mpg %>%
ggplot(aes(x = cty, y = hwy, color = fl)) +
geom_point()
t + theme(legend.position = "bottom") # met een steekwoord, zoals op het spiekbriefjet + theme(legend.position = c(0.7, 0.2), # exacte positie
legend.direction = "horizontal")# legenda niet tonen
t + theme(legend.position = "none") +
labs(subtitle = "geen legenda door: theme(legend.position = 'none')")t + guides(color = "none") +
labs(subtitle = "geen legenda voor 'color' door: guides(color = 'none')")
### legenda titel
# basis grafiek
t <- mpg %>%
ggplot(aes(x = cty, y = hwy, color = fl)) +
geom_point()
# legenda titel
t + theme(legend.title = element_blank()) +
labs(subtitle = "geen legenda titel door: theme(legend.title = element_blank()")t + labs(color = "Legenda titel via labs")t + scale_color_discrete(name = "Legenda tital via scale_color", labels = c("A", "B", "C", "D", "E"))Hoewel kleuren al in 5 Schalen (scale) behandeld zijn, is het goed om er een extra onderdeel aan te wijden.
Kleuren zijn immers erg belangrijk in visuals. Zij bepalen vaak voor
een groot deel hoe een visual gezien/geïnterpreteerd wordt (en hoe
aantrekkelijk de visual gevonden wordt). In ggplot2 kun je elke kleur
gebruiken die je kunt bedenken. Het gaat echter vaak om de combinaties
van kleuren en hoe ze in combinatie met elkaar gezien worden.
Hoewel dit niet in het spiekbriefje te vinden is, is het een dusdanig
belangrijk onderwerp dat het hier toch behandeld wordt.
Zo kun je consequent kleuren gebruiken voor bepaalde groepen, maar ook
de aandacht naar een bepaald onderdeel trekken door kleurgebruik
(bijvoorbeeld door de groepen die niet belangrijk zijn grijs te
maken).
De inspiratie voor dit onderdeel komt van de volgende blog: https://paulvanderlaken.com/2020/03/20/how-to-standardize-group-colors-in-data-visualizations-in-r/
Het kleurenpallet dat je gebruikt, is uiteraard ook erg belangrijk. Dat zal hier echter niet specifiek behandeld worden. Je kunt uit het onderstaande wel een idee krijgen hoe je zo’n kleurenpallet maakt. Als je echt visuals op maat wil maken, met een consequente opmaak, bekijk dan vooral ook het volgende hoofdstuk ‘Thema’s’.
Laten we als eerste naar een visaulisatie voor de mpg dataset kijken.
Hieronder wordt het verbruik (miles per galon) in de stad vergeleken
naar klasse. Daarbij worden de kleuren uit het tidyquant
pakket gebruikt, omdat deze er standaard aantrekkelijker uitzien dan de
kleuren die ggplot toont.
# data
mpg %>%
group_by(class) %>%
summarise(avg_cty = mean(cty)) %>%
ungroup() %>%
# grafiek met standaardinstellingen
ggplot(aes(x = class, y = avg_cty, fill = class)) +
geom_col() +
tidyquant::scale_fill_tq()
Als je in de analyse dan “in wil zoomen” op bepaalde klassen,
bijvoorbeeld met een verbruik in de stad (cty) > 18 miles per galon,
dan gebeurt er het volgende:
# data
mpg %>%
group_by(class) %>%
summarise(avg_cty = mean(cty)) %>%
ungroup() %>%
filter(avg_cty > 18) %>%
# grafiek met standaardinstellingen
ggplot(aes(x = class, y = avg_cty, fill = class)) +
geom_col() +
tidyquant::scale_fill_tq()
De kleuren “verspringen”. Dit is erg verwarrend voor de lezer of in een
presentatie. Je zou de kleuren graag constant houden.
Een oplossing voor dit probleem is namen aan het kleurenpalet toe te
kennen die overeenkomen met de categorieën.
tidyquant::scale_fill_tq() gebruikt de kleuren uit de
functie tidyquant::palette_light(). Als we hier een eigen
kleurenpalet van maken die bestaat uit het aantal kleuren dat
overeenkomt met het aantal klassen (class) in de dataset en deze de
namen van deze klassen meegeven, dan krijgen we het volgende
kleurenpalet.
# kleuren in tidyquant::scale_fill_tq()
print(tidyquant::palette_light())## blue red green yellow steel_blue navy_blue
## "#2C3E50" "#E31A1C" "#18BC9C" "#CCBE93" "#A6CEE3" "#1F78B4"
## light_green pink light_orange orange light_purple purple
## "#B2DF8A" "#FB9A99" "#FDBF6F" "#FF7F00" "#CAB2D6" "#6A3D9A"
# maak er een eigen palette van (we hebben maar 7 kleuren nodig en daar moeten we namen aan geven)
custom_pal <-
tidyquant::palette_light()[1:length(unique(mpg$class))] %>%
setNames(sort(unique(mpg$class)))
print(custom_pal)## 2seater compact midsize minivan pickup subcompact suv
## "#2C3E50" "#E31A1C" "#18BC9C" "#CCBE93" "#A6CEE3" "#1F78B4" "#B2DF8A"
Daarmee kun je de kleuren constant houden in verschillende grafieken
met en zonder selecties / filter op de data. Het kan zijn dat je een
kleine aanpassing in de legenda nodig hebt, omdat je niet alle mogelijke
kleuren wil tonen, maar alleen de kleuren die in de grafiek te zien
zijn.
Dit doe je door het breaks argument te gebruiken in de
scale_*_manual functie te gebruiken.
# oorspronkelijke grafiek
mpg %>%
group_by(class) %>%
summarise(avg_cty = mean(cty)) %>%
ungroup() %>%
# grafiek met standaardinstellingen
ggplot(aes(x = class, y = avg_cty, fill = class)) +
geom_col() +
scale_fill_manual(values = custom_pal)# grafiek voor gefilterde data
# data
mpg %>%
group_by(class) %>%
summarise(avg_cty = mean(cty)) %>%
ungroup() %>%
filter(avg_cty > 18) %>%
# grafiek
# (gebruik het data-argument om in het breaks-argument aan te kunnen roepen)
ggplot(aes(x = class, y = avg_cty, fill = class), data = .) +
geom_col() +
scale_fill_manual(values = custom_pal, breaks = data$class)In een analyse kan het heel goed zijn om de aandacht naar een
bepaalde categorie te trekken. Dit kan heel goed met kleurgebruik binnen
een grafiek. Aanvullend op het voorgaande, kun je dan bijvoorbeeld een
kleurenpalet maken dat een grijze kleur bevat voor alle waarnemingen die
niet van belang zijn en wel de eigen kleur te gebruiken voor het
onderdeel waar je de nadruk op wil leggen.
Dat kan door eerst een kleurenpalet te maken met namen, zoals we
hierboven hebben gedaan. Daarin ken je aan elke naam dezelfde kleur toe,
die de aandacht NIET trekt, zoals lichtgrijs. Daarna kies je de
variabele waar je nadruk op wil leggen en wijs je die toe aan een
r-object. Dit object kun je vervolgens gebruiken om de kleur uit het
kleurenpalet met namen uit het vorige voorbeeld toe te wijzen aan
dezelfde waarde in het kleurenpalet dat je in de grafiek gebruikt. Dit
levert het gewenste resultaat op.
In de code zie je het stap voor stap gebeuren.
# begin met een basis met alleen grijs als kleur
nadruk_pal_basis <-
rep("light grey", length(unique(mpg$class)))%>%
setNames(sort(unique(mpg$class)))
print(nadruk_pal_basis)## 2seater compact midsize minivan pickup subcompact
## "light grey" "light grey" "light grey" "light grey" "light grey" "light grey"
## suv
## "light grey"
# wijs de variabele toe waar de nadruk op moet komen te liggen
nadruk_var <- "subcompact"
print(nadruk_var)## [1] "subcompact"
# maak een kopie van het palet, zodat je dit telkens opnieuw als basis kunt gebruiken
nadruk_pal <- nadruk_pal_basis
# wijs de kleur voor de nadruk variabele uit het custom_pal toe
nadruk_pal[nadruk_var] <- custom_pal[nadruk_var]
print(nadruk_pal)## 2seater compact midsize minivan pickup subcompact
## "light grey" "light grey" "light grey" "light grey" "light grey" "#1F78B4"
## suv
## "light grey"
# maak de grafiek
mpg %>%
group_by(class) %>%
summarise(avg_cty = mean(cty)) %>%
ungroup() %>%
# grafiek
ggplot(aes(x = class, y = avg_cty, fill = class)) +
geom_col() +
scale_fill_manual(values = nadruk_pal) +
theme_minimal()Je kunt er uiteraard ook voor kiezen een andere kleur te gebruiken om de aandacht te trekken. De werkwijze is dan vergelijkbaar.
Thema’s zijn een set aan instellingen die je visual heel snel een
ander uiterlijk kunnen geven. Meestal kun je goed uit de voeten met 1
van de beschikbare thema’s in ggplot2 of een ander package,
zoals ggthemes. Hierbij gaat het vooral om zaken als het
uiterlijk van het canvas, de assen, legenda en dergelijke.
Er zijn verschillende standaard thema’s in ggplot2. Het ggthemes package biedt een uitgebreider aanbod. Hieronder kun je de voorbeelden van het spiek- briefje zien. |
# maak de basis grafiek
t <- mpg %>%
ggplot(aes(x = fl, fill = fl)) +
geom_bar() +
labs(
y = "aantal",
x = "brandstof type",
fill = "brandstof type"
)
# pas thema toe en toon dit in de titel en subtitel
t +
theme_grey() +
labs(
title = "Standaard thema",
subtitle = "theme_grey()"
)# pas thema toe en toon dit in de titel en subtitel
t +
theme_bw() +
labs(
title = "Zwart-wit thema",
subtitle = "theme_bw()"
)# pas thema toe en toon dit in de titel en subtitel
t +
theme_classic() +
labs(
title = "Klassiek thema",
subtitle = "theme_classic()"
)# pas thema toe en toon dit in de titel en subtitel
t +
theme_minimal() +
labs(
title = "Minimal thema",
subtitle = "theme_minimal()"
)De visuals die hier te zien zijn, moeten duidelijk maken dat je heel professionele visuals kunt maken met ggplot2. Daar waar de voorgaande hoofdstukken wellicht wat saaie grafieken lieten zien, is dat hier anders.
De visuals in dit hoofdstuk kunnen er nog mooier uitzien. Omdat rmarkdown zaken schaalt en omzet naar html, worden er (kleine) aanpassingen gedaan. Normaal gesproken zou je de visual naar bestand opslaan en het dan delen. Dat heeft als belangrijk nadeel dat je de code dan niet kunt zien. Deze schoonheidsfoutjes neem ik dus voor lief. Waar nodig heb ik de opgeslagen versie van de visual opgenomen, zodat je de kwaliteit kunt vergelijken.
De eerste visual is een combinatie van 3 grafieken. De inspiratie heb
ik gevonden op: https://www.storytellingwithdata.com/blog/2016/1/26/connecting-the-dots.
Het is tevens een mooi voorbeeld van hoe gegevens anders getoond kunnen
worden dan in de oorspronkelijke grafieken die ook op deze webpagina
getoond worden.
Hieronder zowel de opgeslagen versie (waarvan je de code niet kunt
bekijken) én de gegenereerde versie van deze visual.
# 1.1 projecten overzicht ----
# * data ----
project_per_status_tbl <-
tibble(
status = c("Totaal Projecten", "Relevant", "Voorstellen",
"Binnengehaald") %>% as_factor() %>% fct_rev(),
aantal = c(340, 264, 92, 37),
totaal = c(340, 264, 264, 92),
kleur_totaal = c("grey", "grey", "orange", "darkred"),
verschil = c(0, 0, 172, 55),
label_verschil = c(NA_character_, NA_character_, "Niet ingediend",
"Verloren")
)
# * visual ----
p1 <- project_per_status_tbl %>%
# basis grafiek
ggplot(aes(x = status, y = aantal)) +
# totaal als kolom met kleur van kleur_totaal en geen opvulling
geom_col(aes(y = totaal, color = kleur_totaal),
fill = NA,
width = 0.7,
linetype = "dashed",
size = 1) +
geom_col(fill = "grey", color = "grey", width = 0.7, size = 1) +
# waardes toevoegen op de kolommen
geom_text(aes(label = aantal), color = "white", hjust = 1.2, size = 5) +
# tekst voor de verschillen
geom_text(aes(y = totaal, label = label_verschil, color = kleur_totaal),
hjust = 1.1, size = 4) +
# opmaak
labs(
title = "Project samenvatting",
subtitle = "Januari - December",
x = "",
y = ""
) +
annotate("text", x = 4.525, y = 150,
label = "# projecten per stap in het proces",
color = "grey", size = 5) +
# grafiek draaien
coord_flip() +
# thema wijzigen
theme_minimal() +
# opmaak van titel, subtitel en grid
theme(
plot.title = element_text(size=20, face = "bold"),
plot.title.position = "plot",
plot.subtitle = element_text(size = 15),
axis.text.x = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank()
) +
# randkleur op basis van status-variabele (voor totaal)
scale_color_identity()
# 1.2 waarom niet ingediend ----
# * data ----
reden_niet_ingediend_tbl <-
tibble(
reden = c("Konden deadline niet halen", "Onvoldoende capaciteit",
"Onvoldoende mogelijkheden", "Te klein",
"Onmogelijk binnen te halen", "Buiten de doelmarkt",
"Slechte relatie") %>% as_factor() %>% fct_rev(),
aantal = c(56, 42, 24, 22, 12, 8, 8)
) %>%
mutate(
pct = (aantal / sum(aantal)) %>% round(digits = 2) %>% scales::percent()
)
# * visual ----
p2 <- reden_niet_ingediend_tbl %>%
# basis grafiek
ggplot(aes(x = reden, y = aantal)) +
geom_col(fill = "orange", width = 0.7, size = 1) +
# waardes toevoegen op de kolommen
geom_text(aes(label = aantal), color = "white", hjust = 1.5, size = 3) +
# percentages toevoegen boven de kolommen
geom_text(aes(label = pct), color = "grey", hjust = -0.25, size = 3) +
# opmaak
labs(
title = bquote("Waarom dienen we voorstellen"~bold("niet in")),
x = "",
y = ""
) +
# ruimte maken voor de annotatie 'aantal | % tot'
scale_x_discrete(
limits = c(reden_niet_ingediend_tbl %>%
arrange(aantal) %>%
pull(reden) %>%
as.character(), "")
) +
# tekst boven de grafiek
annotate("text", x = 7.75, y = 50, label = "aantal",
color = "orange", size = 3) +
annotate("text", x = 7.75, y = 61, label = "| % tot",
color = "grey", size = 3) +
# grafiek draaien
coord_flip() +
# thema wijzigen
theme_minimal() +
# opmaak van titel, subtitel en grid
theme(
plot.title = element_text(size=15),
plot.title.position = "plot",
plot.subtitle = element_text(size = 15),
axis.text.x = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank()
)
# 1.3 waarom niet gewonnen ----
# * data ----
verloren_biedingen_tbl <-
tibble(
reden = c("Levertijd", "Reikwijdte werk", "Prijs", "Slechte relatie") %>%
as_factor() %>% fct_rev(),
aantal = c(19, 18, 11, 7)
) %>%
mutate(
pct = (aantal / sum(aantal)) %>% round(digits = 2) %>% scales::percent()
)
# - visual ----
p3 <- verloren_biedingen_tbl %>%
# basis grafiek
ggplot(aes(x = reden, y = aantal)) +
geom_col(fill = "darkred", width = 0.7, size = 1) +
# waardes toevoegen op de kolommen
geom_text(aes(label = aantal), color = "white", hjust = 1.5, size = 3) +
# percentages toevoegen boven de kolommen
geom_text(aes(label = pct), color = "grey", hjust = -0.25, size = 3) +
# opmaak
labs(
title = bquote("Waarom we biedingen"~bold("verliezen")),
x = "",
y = ""
) +
# ruimte maken voor de annotatie 'aantal | % tot'
scale_x_discrete(
limits = c(verloren_biedingen_tbl %>%
arrange(aantal) %>%
pull(reden) %>%
as.character(), "")
) +
# tekst boven de grafiek
annotate("text", x = 5, y = 16.5, label = "aantal",
color = "darkred", size = 3) +
annotate("text", x = 5, y = 21, label = "| % tot",
color = "grey", size = 3) +
# grafiek draaien
coord_flip() +
# thema wijzigen
theme_minimal() +
# opmaak van titel, subtitel en grid
theme(
plot.title = element_text(size=15),
plot.title.position = "plot",
plot.subtitle = element_text(size = 15),
axis.text.x = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank()
)
p1 / (p2 + p3) +
plot_layout(heights = unit(c(6, 3), c('cm', 'cm')))De volgende visual is gebaseerd op fictieve data.
Bijzonderheden:
# data
# Lijst met Nederlandse fietsmerken maken
fietsmerken <- c("Batavus", "Gazelle", "Giant", "Koga", "Sparta", "Overige")
# gegevens over kleuren en logo's
merkgegevens <-
tibble(
fietsmerk = fietsmerken,
kleur = c("#c41d35", "#2a328f", "#006daf", "#0e7dc7", "#45ac36",
"#8e24bb") %>% setNames(fietsmerken),
logo = c("logo_batavus.jpg", "logo_gazelle.jpg", "logo_giant.png",
"logo_koga.jpg", "logo_sparta.png", "logo_overige.jpg")
)
# Dataset maken met fictieve omzetcijfers
set.seed(123)
verkoopdata <-
tibble(fietsmerk = fietsmerken,
omzet = round(runif(length(fietsmerken), min = 500, max = 5000))) %>%
arrange(desc(omzet))
# Nabewerken data voor juiste volgorde in grafiek e.d.
data <- verkoopdata %>%
left_join(merkgegevens) %>%
mutate(
omzet = ifelse(fietsmerk == "Overige", omzet * 4, omzet),
fietsmerk = fietsmerk %>% as_factor() %>% fct_rev() %>% relevel("Overige")
) %>%
mutate(level = as.numeric(fietsmerk)) %>%
mutate(logo = str_glue("www/{logo}"),
omzet_label = scales::number(omzet))
# Maak lollipop grafiek
g <-
# toewijzing van data
ggplot(data, aes(x = fietsmerk, y = omzet)) +
# lijnen voor de omzet van 0 tot omzet hoogte
geom_segment(aes(x = fietsmerk, xend = fietsmerk,
y = 0, yend = omzet, color = kleur), size = data$omzet / 2500) +
# omzet cijfer aan het eind van de lijn toevoegen
geom_label(aes(label = omzet_label, color = kleur)) +
# opmaak
# titels en as-labels
labs(
title = "Fietsmerken en omzet",
x = "",
y = "Omzet (x1000 €)",
caption = "fictieve data"
) +
# thema toepassn
theme_minimal() +
# kleur toewijzen op basis van fietsmerk
scale_color_identity() +
# x-as volledig blanco maken
scale_x_discrete(labels = NULL, breaks = NULL) +
# y-as volledig blanco maken
scale_y_continuous(labels = NULL, breaks = NULL) +
# grafiek draaien, zodat de merken op de 'y-as' komen
coord_flip() +
# opmaak van titel, subtitel en grid
theme(
plot.title = element_text(size=15),
plot.title.position = "plot",
panel.grid.major = element_blank(),
panel.grid.minor = element_blank()
)
# logo als x-as 'tick'
library(ggimage)
g +
geom_image(aes(image = logo, y = -300), size = 0.095, by = "width")