4  Visualisierung mit {ggplot2}

Neben Kennzahlen/Tabellen können/sollten Verteilungen auch visualisiert werden. Dafür bietet {ggplot2} eine riesige Auswahl an Möglichkeiten.

{ggplot2} ist Teil des {tidyverse}, d.h. wir können entweder nur {ggplot2} oder die gesamte {tidyverse}-Sammlung laden:

library(haven) # für datenimport
library(tidyverse)
# library(ggplot2) # nicht nötig wenn tidyverse geladen

Zunächst sehen wir uns den Weg zu einem Scatterplot an:

Datengrundlage für unsere Graphik ist die ETB18 mit den Angaben zur Arbeitszeit sowie dem Geschlecht und Alter der Befragten:

etb18 <- read_dta("./data/BIBBBAuA_2018_suf1.0.dta")
etb18 %>% select(az,S1,zpalter) %>% head()
# A tibble: 6 × 3
     az S1           zpalter  
  <dbl> <dbl+lbl>    <dbl+lbl>
1    80 1 [männlich] 41       
2    30 2 [weiblich] 51       
3    40 1 [männlich] 49       
4    40 2 [weiblich] 63       
5    39 2 [weiblich] 41       
6    40 1 [männlich] 57       

Um die Grafik nicht zu groß zu machen, verwenden wir nur die ersten 100 Beobachtungen:

etb18$zpalter[etb18$zpalter>100] <- NA # missing in zpalter mit NA überschreiben
etb18_small <- etb18 %>% slice(1:100)

4.1 ggplot2 und die grammar of graphics

ggplot2 ist die Umsetzung des Konzepts der “layered grammar of graphics” in R. Die Idee dieses Visualisierungssystems ist es, Datenvisualisierung in Parameter zu unterteilen: der zugrundeliegende Datensatz, die darzustellenden Variablen, die Wahl der darzustellenden Formen, das Koordinatensystem, Skalen und statistische Transformationen. Ein Standardbefehl in ggplot2 sieht ungefähr so aus:

ggplot(data = datensatz, aes(x = var1, y = var2, color = var3)) +
  geom_point() +
  labs(title= "Titel", subtitle = "Untertitel") +
  theme_minimal()

Wir rufen also zunächst mit ggplot() eine Darstellung auf. In den weiteren Argumenten werden dann weitere Aspekte festgelegt:

  • Mit data = geben wir den data.frame an, den wir darstellen möchten
  • Die Aesthetics aes() legen fest, welche Variablen dargestellt werden sollen: hier also var1 auf der x-Achse, var2 auf der y-Achse und var3 soll die Farbgebung festlegen
  • Die Layers geom_.. geben die Art der Darstellung an, zB. geom_point() für Punkt- und geom_bar() für Säulendiagramme.
  • Mit labs können wir Beschriftungen angeben, zB. einen Titel vergeben oder die Achsenbeschriftungen anpassen
  • Die Themes theme_... legen das Design der Graphik fest, zB. schwarz/weiße Achsen- und Hintergrundfarben mit theme_bw()

Wir arbeiten uns also jetzt durch die einzelnen layer/Schichten der Grafik:

4.1.1 data =

In data = geben die den data.frame an, aus dem die darzustellenden Informationen kommen. Wir starten unseren ggplot also mit:

ggplot(data = etb18_small)

4.1.2 aes

Diese Werte wollen wir also in einem Scatterplot darstellen, sodass das Alter auf der x-Achse und auf der y-Achse die Wochenarbeitszeit abgetragen ist:

ggplot(data = etb18_small, aes(x = zpalter, y = az))

4.1.3 geom

Wenn wir nur diese Angaben machen, bekommen wir lediglich ein leeres Koordinatensystem - warum? Weil wir noch nicht angegeben haben, welche Form der Darstellung wir gerne möchten. Dazu muss wir ein geom_ angeben, für Säulendiagramme ist das geom_col(), diese hängen wir an den ggplot-Befehl mit + an:

ggplot(data = etb18_small, aes(x = zpalter, y = az)) + geom_point()

Mit color = können wir den Punkten auch eine andere Farbe geben:

ggplot(data = etb18_small, aes(x = zpalter, y = az)) + geom_point(color = "orange")

Hier findet sich eine Übersicht mit allen Farbnamen, die verstanden werden, es gibt aber noch viel mehr Farben - siehe Anhang.

4.1.4 aes() Teil II

Das sieht soweit schon ganz gut aus, allerdings werden die Punkte noch nicht getrennt nach Geschlecht dargestellt. Dazu müssen wir die Geschlechtsangabe (S1) in aes() angeben. Neben den Achsen werden in aes() nämlich auch die Variablen für das Aussehen der geom_s angeben - das kann neben der Farbe auch die Form, Größe oder Transparenz sein. Hier ein Überblick

Das Geschlecht soll die Färbung der Punkte vorgeben, diese können wir in aes mit color angeben:

# ergibt einen Fehler aufgrund der Labels:
ggplot(data = etb18_small, aes(x = zpalter, y = az, color = S1 )) + 
  geom_point()
Error in UseMethod("rescale"): nicht anwendbare Methode für 'rescale' auf Objekt der Klasse "c('haven_labelled', 'vctrs_vctr', 'double')" angewendet

Eine numerische Variable für color = ergibt einen Farbverlauf, eine factor/character-Variable ergibt eine diskrete Farbskala:

ggplot(data = etb18_small, aes(x = zpalter, y = az, color = as.numeric(S1))) + 
  geom_point()
ggplot(data = etb18_small, aes(x = zpalter, y = az, color = as.factor(S1))) + 
  geom_point()
ggplot(data = etb18_small, aes(x = zpalter, y = az, color = as.character(S1))) + 
  geom_point()

Außerdem können wir mit scale_color_manual1 selbst Farben angeben, eine Liste möglicher Farben findet sich hier.

ggplot(data = etb18_small, aes(x = zpalter, y = az, color = as.factor(S1))) + 
  geom_point() + 
  scale_color_manual(values = c("lightskyblue4","navy"))

4.1.5 Beschriftungen

Wir können mit den Optionen breaks und labels zudem auch die Beschriftung der Legende bearbeiten. Dazu geben wir zunächst in breaks die Ausprägungen der Variable Geschlecht an und dann in der gleichen Reihenfolge die zu vergebenden Labels:

ggplot(data = etb18_small, aes(x = zpalter, y = az, color = as.factor(S1))) + 
  geom_point() + 
  scale_color_manual(values = c("lightskyblue4","navy"),
                    breaks = c(1,2), labels = c("Männer", "Frauen") )

Abschließend passen wir dann noch mit labs die Beschriftungen an, dabei haben wir folgende Optionen:

  • title: Überschrift für die Graphik
  • subtitle: Unterzeile zur Überschrift
  • caption: Anmerkung unterhalb der Graphik
  • x: x-Achsenbeschriftung
  • y: y-Achsenbeschriftung
  • fill: Beschriftung für die Legende, wenn fill in aes() angegeben wurde
  • color: Beschriftung für die Legende, wenn color in aes() angegeben wurde
ggplot(data = etb18_small, aes(x = zpalter, y = az, color = as.factor(S1))) + 
  geom_point() + 
  scale_color_manual(values = c("lightskyblue4","navy"),
                    breaks = c(1,2), labels = c("Männer", "Frauen") ) +
  labs(color = "Geschlecht", y = "Arbeitszeit/Woche",
       x = "Alter",
       title = "Arbeitszeit und Alter",
       subtitle = "Nach Geschlecht",
       caption = "Quelle: ETB 2018"
       ) 

Außerdem können wir mit theme_ ein anderes Design auswählen, zB. mit theme_minimal() einen weißen Hintergrund mit grauen Markierungslinien (weitere Beispiele in den Hinweisen unter Themes)

4.2 Kombination aus allem

etb18_small$m1202[etb18_small$m1202<0] <- NA
ggplot(data = etb18_small, aes(x = zpalter, y = az, 
                               color = as.factor(S1),
                               shape = as.factor(m1202))) + 
  geom_point(size = 2) + 
  scale_color_manual(values = c("lightskyblue3","navy"),
                    breaks = c(1,2), labels = c("Männer", "Frauen") ) +
  scale_shape_manual(values = c(15:18),breaks = c(1:4), 
                     labels = c("ohne Aus", "duale Ausb.","Aufstiegsfortb.","FH/Uni")) +
  labs(color = "Geschlecht", 
       shape = "Ausbildung",
       fill = "Geschlecht",
       y = "Arbeitszeit/Woche",
       x = "Alter",
       title = "Arbeitszeit und Alter",
       subtitle = "Nach Geschlecht",
       caption = "Quelle: ETB 2018"
       ) 

Übersicht zu shapes

4.3 Grafiken speichern: ggsave()

Um eine Grafik dann zu speichern, steht uns ggsave() zur Verfügung. Wenn wir nichts anderes angeben, wird automatisch die gerade offene Grafik2 gespeichert. Besser ist es aber explizit zu sein und die gewünschte Grafik als Objekt abzulegen und dann in ggsave() anzugeben:

plot_objekt1 <- ggplot(data = etb18_small, aes(x = zpalter, y = az, 
                               color = factor(S1),
                               shape = factor(m1202))) + 
  geom_point(size = 2) + 
  scale_color_manual(values = c("lightskyblue3","navy"),
                    breaks = c(1,2), labels = c("Männer", "Frauen") ) +
  scale_shape_manual(values = c(15:18),breaks = c(1:4), 
                     labels = c("ohne Aus", "duale Ausb.","Aufstiegsfortb.","FH/Uni")) +
  labs(color = "Geschlecht",shape = "Ausbildung", fill = "Geschlecht",
       y = "Arbeitszeit/Woche",x = "Alter",
       title = "Arbeitszeit und Alter", subtitle = "Nach Geschlecht",caption = "Quelle: ETB 2018") 
ggsave(plot = plot_objekt1,filename = "./results/plot1.png",
       dpi = 800, # auflösung
       # width = 9, height = 7, # falls angepasst werden soll
       )

Die richtige Kombination aus Auflösung, Textgröße und Gesamtgröße des Plots zu finden hat einige Fallstricke. Hier mehr dazu.

4.3.1 Übung

4.4 Verteilungen visualisieren

4.4.1 Boxplot

Definition der Bestandteile eines Boxplots:

Mit der folgenden Syntax können wir mit ggplot2 einen Boxplot erstellen. Da wir nur eine Variable betrachten, müssen wir lediglich y = oder x = angeben - je nachdem ob die Box vertikal oder horizontal orientiert sein soll.

ggplot(data = etb18_small, aes(y = az)) + geom_boxplot()

So können wir einen Boxplot erstellen, der die Werte für Männer und Frauen getrennt darstellt:

ggplot(data = etb18_small, aes(y = az, x = factor(S1))) + geom_boxplot()

4.4.2 Histogram

Ebenso können Verteilungen mit einem Histogramm beschrieben werden:

ggplot(data = etb18_small, aes(x = az)) + 
  geom_histogram()  

Wenn wir hier die Farbe ändern möchten, dann ist fill = anstelle von color = die richtige Option:

ggplot(data = etb18_small, aes(x = az)) + 
  geom_histogram(fill = "sienna1")  

Möchten wir das Histogramm nach Geschlecht aufsplitten, können wir auch hier wieder fill als Aesthetic angeben. Mit position = position_dodge() können wir die Balken nebeneinander stellen lassen:

ggplot(data = etb18_small, aes(x = az, fill = factor(S1))) + 
  geom_histogram() 
ggplot(data = etb18_small, aes(x = az, fill = factor(S1))) + 
  geom_histogram(position = position_dodge()) 

Auch hier funktionieren natürlich wieder die scale_...manual Befehle, allerdings hier als scale_fill_manual anstelle scale_color_manual von oben:

ggplot(data = etb18_small, aes(x = az, fill = factor(S1))) + 
  geom_histogram(position = position_dodge()) +
  scale_fill_manual(values = c("sienna1","dodgerblue4"),
                    breaks = 1:2, labels = c("Männer","Frauen")) +
  labs(fill = "Geschlecht")

4.4.3 Übung

4.5 Kategoriale Merkmale

Im Folgenden sehen wir uns eine Möglichkeit an, die Kontingenztabelle aus Kapitel 2 zu visualisieren:

etb18$m1202[etb18$m1202<0] <- NA # missings ausschließen
etb18 %>% 
  count(S1,m1202) %>% 
  filter(!is.na(m1202))
# A tibble: 8 × 3
  S1           m1202                                                           n
  <dbl+lbl>    <dbl+lbl>                                                   <int>
1 1 [männlich] 1 [Ohne Berufsabschluss]                                      594
2 1 [männlich] 2 [duale o. schulische Berufsausbildung/einf.,mittl. Beamt…  4371
3 1 [männlich] 3 [Aufstiegsfortbildung (Meister, Techniker, kfm. AFB u.ä.…  1073
4 1 [männlich] 4 [Fachhochschule, Universität/ geh., höhere Beamte]         4015
5 2 [weiblich] 1 [Ohne Berufsabschluss]                                      497
6 2 [weiblich] 2 [duale o. schulische Berufsausbildung/einf.,mittl. Beamt…  4926
7 2 [weiblich] 3 [Aufstiegsfortbildung (Meister, Techniker, kfm. AFB u.ä.…   652
8 2 [weiblich] 4 [Fachhochschule, Universität/ geh., höhere Beamte]         3839

Da wir mit count() einen data.frame erhalten, können wir diesen direkt in ggplot() schicken und mit geom_col() Säulen darstellen:

etb18 %>% 
  count(S1,m1202) %>% 
  filter(!is.na(m1202)) %>% 
  ggplot(data = ., aes(x = m1202, y = n, fill = factor(S1))) +
  geom_col(position=position_dodge()) 

Wie kommen wir jetzt an die relativen Häufigkeiten? Wir erweitern einfach die Pipeline vor ggplot() um den prop.table()-Befehl aus Kapitel 2. Mit scale_y_continuous(labels = scales::label_percent(accuracy = 1)) können wir außerdem die y-Achse in Prozentwerten angezeigen lassen:

etb18 %>% 
  filter(!is.na(m1202)) %>% 
  count(S1,m1202) %>% 
  group_by(S1) %>% 
  mutate(pct_gender = prop.table(n)) %>% 
  ggplot(data = ., aes(x = m1202, y = pct_gender, fill = factor(S1))) +
  geom_col(position=position_dodge())  +
  scale_y_continuous(labels = scales::label_percent(accuracy = 1)) 

Auch diese Grafiken können wir dann wieder mit scale_... anpassen und mit labs() ausführlich labeln - alle Optionen sind konsistent über alle Darstellungsformen hinweg:

etb18 %>% 
  filter(!is.na(m1202)) %>% 
  count(S1,m1202) %>% 
  group_by(S1) %>% 
  mutate(pct_gender = prop.table(n)) %>% 
  ggplot(data = ., aes(x = m1202, y = pct_gender, fill = factor(S1))) +
  geom_col(position=position_dodge())  +
  scale_y_continuous(labels = scales::label_percent(accuracy = 1))  + 
  scale_fill_manual(values = c("navajowhite","navy"),
                    breaks = c(1,2), labels = c("Männer", "Frauen")) +
  scale_x_continuous(breaks = 1:4 , labels = c("ohne Ausb.", "duale Ausb.","Aufstiegsfortb.","FH/Uni")) +
  scale_y_continuous(labels = scales::label_percent(accuracy = 1)) +
  labs(title = "Ausbildungsabschlüsse nach Geschlecht",
       subtitle = "Relative Häufigkeiten",
       caption = "Quelle: ETB 2018",
       x = "Ausbildung",
       y = "Relative Häufigkeit",
       fill = "Geschlecht" ) 

4.5.1 Übung

4.6 Übungen

Nutzen Sie für alle Aufgaben die ersten 150 Beobachtungen (etb18_small), um den Plot einfach zu halten. Denken Sie daran die fehlenden Werte mit filter() auszuschließen, Sie können dazu diesen Befehl verwenden:

etb18 <-
  haven::read_dta("./data/BIBBBAuA_2018_suf1.0.dta",
    col_select = c("h1216d", "S2_j", "S1", "m1202", "F518_SUF", "nt", "gkpol")
    )
etb18_small <-
  etb18 %>% filter(S2_j < 9999, h1216d > 0, F518_SUF < 99998) %>% slice(1:150)

4.6.1 Übung 1

  • Erstellen Sie einen Scatterplot für die Variablen Geburtsjahr (S2_j, x-Achse) und Dauer der Ausbildung (h1216d, y-Achse).
  • Legen Sie die Farbe so fest, dass Männer und Frauen unterschiedliche Farben gekennzeichnet werden (S1)
  • Verändern Sie die Farben auf goldenrod1 und dodgerblue4 fest (oder eine beliebige andere)
  • Beschriften Sie die Achsen und Legende!

Zurück nach oben

4.6.2 Übung 2

  • Erstellen Sie einen Boxplot oder Histogramm für die Verteilung des Einkommens (F518_SUF).
  • Passen Sie diese Grafik so an, dass die Einkommensverteilungen für Männer und Frauen getrennt dargestellt werden.
  • Wie können Sie auch die Farben nach dem Geschlecht getrennt anlegen? (Denken Sie an color = und fill =)
  • Verändern Sie die Farben der Balken mit Hilfe von scale_fill_manual oder scale_fill_brewer oder scale_fill_viridis (Siehe Abschnitte Farben und ColorBreweR und viridis unter “weitere Optionen”)

Zurück nach oben

4.6.3 Übung 3

  • Erstellen Sie ein Säulen-Diagramm für die Größenklasse des Wohnorts der Befragten (gkpol)
  • Erstellen Sie ein Säulen-Diagramm für die Größenklasse des Wohnorts der Befragten (gkpol) getrennt nach der Variable nt - färben Sie die Säulen nach nt. Die Variable nt erfasst, ob die Befragten einer Nebentätigkeit nachgehen (1 = ja/ 0 = nein).

Kleine Hilfe: das sind die Labels für gkpol 1-7:

c("<2k", "2k bis <5k", "5k bis <20k", "20k bis <50k", "50k bis <100k", 
"100k bis <500k", "500k und mehr")
Code
scale_x_continuous(breaks = 1:7,
                   labels = c("<2k", "2k bis <5k", "5k bis <20k", "20k bis <50k", 
                              "50k bis <100k", "100k bis <500k", "500k und mehr"))

Zurück nach oben

4.7 Weitere Optionen für ggplot2

4.7.1 Aesthetics

4.7.2 themes

Mit sog. themes können wir das layout der Grafik verändern. Weitere Themes sind zB: theme_light(), theme_classic() ider theme_void(), eine Liste findet sich hier. Außerdem bietet das Paket {ggthemes} (install.packages('ggthemes')) eine große Auswahl.

ggplot(data = etb18_small, aes(x = zpalter, y = az, color = factor(S1))) + 
  geom_point(size = 2) + 
  theme_minimal()

ggplot(data = etb18_small, aes(x = zpalter, y = az, color = factor(S1))) + 
  geom_point(size = 2) +
  theme_dark()

4.7.3 Farben

p1 <- ggplot(data = etb18_small, aes(x = zpalter, y = az, color = factor(S1))) + 
  geom_point(size = 3) 

Neben den im Beispiel verwendeten Farben für fill können natürlich auch noch unzählige weitere Farben in scale_fill_manual und scale_color_manual verwendet werden:

  • Hier findet sich eine Übersicht mit allen Farbnamen, die verstanden werden
  • Alternativ können auch sog. HEX-Codes angeben werden, die bspw. mit dem Adobe Color Wheel oder Color Hex erstellt werden können.
p1 +  scale_color_manual(values = c("dodgerblue4","sienna1"),
                    breaks = c(1,2), labels = c("Männer", "Frauen") )
p1 +  scale_color_manual(values = c("#005b96","#6497b1"),
                    breaks = c(1,2), labels = c("Männer", "Frauen") )

4.7.3.1 ColorBreweR

Alternativ zur manuellen Auswahl der Farben mit scale_fill_manual und scale_color_manual können mit scale_fill_brewer() auch vorgegebene Farbpaletten des colorbrewer verwendet werden. Dazu muss lediglich scale_fill_brewer() anstelle von scale_fill_manual angeben werden und statt values eine der Paletten - eine Übersicht findet sich hier. Die Farbpaletten von ColorBreweR sind alle in ggplot2 integriert.

p1 +
  scale_color_brewer(palette = "RdYlBu",
                    breaks = c(1,2), labels = c("Männer", "Frauen") ) 

4.7.3.2 viridis

Analog dazu gibt es auch die {viridis}-Paletten, welche durchgängig “colorblind-safe” und ebenfalls in {ggplot2} integriert sind. Allerdings ist hier zu beachten, dass für Farbauswahlen basierend auf einer kategorialen Variable scale_color_viridis_d() zu verwenden ist. Soll die Farbe entlang einer numerischen/metrischen Variable bestimmt werden, dann ist scale_color_viridis_c() zu verwenden. Außerdem kann mit begin und end die Breite der Farbskala angepasst werden:

p1 +
  scale_color_viridis_d(option="magma",
                    breaks = c(1,2), labels = c("Männer", "Frauen") ) 
p1 +
  scale_color_viridis_d(option="magma",begin = .65,end = .85,
                    breaks = c(1,2), labels = c("Männer", "Frauen") ) 

4.7.3.3 Weitere Farbpaletten

Darüber hinaus gibt es unzählige Pakete, die ebenfalls scale_color_ und scale_fill_-Funktionen bieten: Hier noch zwei Beispiele mit {scico} und {MetBrewer}, welches Farben aus Bildern im Metropolitan Museum of Art enthält:

install.packages('scico')
install.packages("MetBrewer")

{scico} Farbpaletten

{MetBrewer} Farbpaletten

library(scico)
p1 +
  scale_color_scico_d(palette = "oslo",begin = .5,end = .8,
                    breaks = c(1,2), labels = c("Männer", "Frauen") ) 
library(MetBrewer)
p1 +
  scale_color_met_d(name = "Kandinsky",
                    breaks = c(1,2), labels = c("Männer", "Frauen") ) 

Vergleichbare Pakete gibt es auch für

  • {DutchMasters} - Farbpaletten aus Bildern niederländischer Maler
  • {wesanderson} - Farbpaletten basierend auf verschiedenen Filmen von Wes Anderson (The Grand Budapest Hotel usw.)
  • {ochRe} - Farbpaletten “inspired by Australian art, landscapes and wildlife”
  • {paletteer} bietet eine riesige Auswahl verschiedenster Farbpaletten

4.7.4 Shapes

Zusätzlicher Überblick

4.7.5 Linetypes

Übersicht zu Shapes und Linetypes im R Cookbook

4.8 Linksammlung

  • From Data to Viz bietet einen Entscheidungsbaum für verschiedene Zusammenhänge und Deskriptionen mit Beispiel-Syntax


  1. Hätten wir color in aes angeben, wäre der entsprechende Befehl scale_color_manual.↩︎

  2. im Panel Plots rechts↩︎