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 pend mit den Angaben zur Arbeitszeit sowie dem Geschlecht und Alter der Befragten:

library(haven)
pend <- read_dta("./orig/PENDDAT_cf_W13.dta")
pend %>% select(azges1,zpsex,palter) %>% head()
# A tibble: 6 × 3
  azges1                           zpsex         palter   
  <dbl+lbl>                        <dbl+lbl>     <dbl+lbl>
1 -9 [Item in Welle nicht erhoben] 2 [Weiblich]  36       
2 -9 [Item in Welle nicht erhoben] 1 [Maennlich] 39       
3 -3 [Trifft nicht zu (Filter)]    2 [Weiblich]  38       
4 -9 [Item in Welle nicht erhoben] 1 [Maennlich] 66       
5 -9 [Item in Welle nicht erhoben] 2 [Weiblich]  61       
6 -3 [Trifft nicht zu (Filter)]    2 [Weiblich]  62       

Um die Grafik nicht zu groß zu machen, verwenden wir nur die Beobachtungen aus Welle 13:

# missings mit NA überschreiben (wir sehen später noch in Kap6 wie das schneller geht)
pend$palter[pend$palter>100] <- NA 
pend$casmin[pend$casmin<0] <- NA
pend$PAS0100[pend$PAS0100<0] <- NA
pend$azges1[pend$azges1<0] <- NA

pend_small <- pend %>% filter(welle==13)

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 = pend_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 = pend_small, aes(x = palter, y = azges1))

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 = pend_small, aes(x = palter, y = azges1)) + geom_point()

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

ggplot(data = pend_small, aes(x = palter, y = azges1)) + 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 (zpsex) 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 = pend_small, aes(x = palter, y = azges1, color = zpsex )) + 
  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 = pend_small, aes(x = palter, y = azges1, color = as.numeric(zpsex))) + 
  geom_point()
ggplot(data = pend_small, aes(x = palter, y = azges1, color = as.factor(zpsex))) + 
  geom_point()
ggplot(data = pend_small, aes(x = palter, y = azges1, color = as.character(zpsex))) + 
  geom_point()

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

ggplot(data = pend_small, aes(x = palter, y = azges1, color = as.factor(zpsex))) + 
  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 = pend_small, aes(x = palter, y = azges1, color = as.factor(zpsex))) + 
  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 = pend_small, aes(x = palter, y = azges1, color = as.factor(zpsex))) + 
  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

ggplot(data = pend_small, aes(x = palter, y = azges1, 
                               shape = as.factor(zpsex),
                               color = as_factor(PAS0100))) + 
  geom_point(size = 2) + 
  scale_color_manual(values = c("#007ACF","navy","lightskyblue","orange") ) +
  scale_shape_manual(values = c(18,20),
                    breaks = c(1,2), labels = c("Männer", "Frauen")
                     ) +
  labs(color = "", 
       fill = "",
       shape = "Geschlecht",
       y = "Arbeitszeit/Woche",
       x = "Alter",
       title = "Arbeitszeit und Alter",
       subtitle = "Nach Geschlecht",
       caption = "Quelle: PASS CF 0619"
       ) 

Ü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 = pend_small, aes(x = palter, y = azges1, 
                               shape = as.factor(zpsex),
                               color = as_factor(PAS0100))) + 
  geom_point(size = 2) + 
  scale_color_manual(values = c("lightskyblue","#007ACF","navy","orange") ) +
  scale_shape_manual(values = c(18,20),
                    breaks = c(1,2), labels = c("Männer", "Frauen")
                     ) +
  labs(color = "", 
       fill = "",
       shape = "Geschlecht",
       y = "Arbeitszeit/Woche",
       x = "Alter",
       title = "Arbeitszeit und Alter",
       subtitle = "Nach Geschlecht",
       caption = "Quelle: PASS CF 0619"
       ) 
ggsave(plot = plot_objekt1,
       filename = "./results/plot1.png",
       dpi = 800, # auflösung
       width = 25, height = 11, units = "cm" # 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 = pend_small, aes(y = azges1)) + geom_boxplot()

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

ggplot(data = pend_small, aes(y = azges1, x = factor(zpsex))) + geom_boxplot()

4.4.2 Histogram

Ebenso können Verteilungen mit einem Histogramm beschrieben werden:

ggplot(data = pend_small, aes(x = azges1)) + 
  geom_histogram()  

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

ggplot(data = pend_small, aes(x = azges1)) + 
  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 = pend_small, aes(x = azges1, fill = factor(zpsex))) + 
  geom_histogram() 
ggplot(data = pend_small, aes(x = azges1, fill = factor(zpsex))) + 
  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 = pend_small, aes(x = azges1, fill = factor(zpsex))) + 
  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:

pend_small$PD0400[pend_small$PD0400<0] <- NA # missings ausschließen
pend_small %>% 
  count(zpsex,PD0400) 
# A tibble: 10 × 3
   zpsex         PD0400                              n
   <dbl+lbl>     <dbl+lbl>                       <int>
 1 1 [Maennlich]  1 [Ueberhaupt nicht religioes]    40
 2 1 [Maennlich]  2 [Eher nicht religioes]          41
 3 1 [Maennlich]  3 [Eher religioes]                49
 4 1 [Maennlich]  4 [Sehr religioes]                22
 5 1 [Maennlich] NA                                780
 6 2 [Weiblich]   1 [Ueberhaupt nicht religioes]    26
 7 2 [Weiblich]   2 [Eher nicht religioes]          34
 8 2 [Weiblich]   3 [Eher religioes]                40
 9 2 [Weiblich]   4 [Sehr religioes]                16
10 2 [Weiblich]  NA                                816

Mit geom_bar() können wir Säulen darstellen, indem wir ..count.. für y die Höhe als Anzahl der Beobachtungen festlegen:

pend_small %>% 
  filter(!is.na(PD0400)) %>% 
  ggplot(data = ., aes(x = as_factor(PD0400), fill = factor(zpsex),
                       y = ..count..)) +
  geom_bar(position=position_dodge()) 

Wie kommen wir jetzt an die relativen Häufigkeiten? Wir passen unsere aes auf y = (..count..)/sum(..count..) an. Mit scale_y_continuous(labels = scales::label_percent(accuracy = 1)) können wir außerdem auf der y-Achse die Prozentwerte anzeigen lassen:

pend_small %>% 
  filter(!is.na(PD0400)) %>% 
  ggplot(data = ., aes(x = as_factor(PD0400), fill = factor(zpsex),
                       y = (..count..)/sum(..count..) )) +
  geom_bar(position=position_dodge()) +
  scale_y_continuous(labels = scales::label_percent(accuracy = 1)) 

Um jetzt ein Balken- statt einem Säulendiagramm zu erhalten, tauschen wir einfach x und y sowie die Prozentbeschriftung auf scale_x_continuous:

pend_small %>% 
  filter(!is.na(PD0400)) %>% 
  ggplot(data = ., aes(y = as_factor(PD0400), fill = factor(zpsex),
                       x = (..count..)/sum(..count..) )) +
  geom_bar(position=position_dodge()) +
  scale_x_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. Außerdem können wir die Kategorien mit breaks = und labels = auch selbst labeln, wenn uns die definierten Labels nicht gefallen:

pend_small %>% 
  filter(!is.na(PD0400)) %>% 
  ggplot(data = ., aes(y = as_factor(PD0400), fill = factor(zpsex),
                       x = (..count..)/sum(..count..) )) +
  geom_bar(position=position_dodge()) +
  scale_fill_manual(values = c("navajowhite","navy"),
                    breaks = c(1,2), labels = c("Männer", "Frauen")) +
  scale_x_continuous(labels = scales::label_percent(accuracy = 1)) +
  labs(title = "Religiösität nach Geschlecht",
       subtitle = "Relative Häufigkeiten",
       caption = "Quelle: PASS-CF 0619",
       y = "Religiösität",
       x = "Relative Häufigkeit",
       fill = "Geschlecht" ) 
pend_small %>% 
  filter(!is.na(PD0400)) %>% 
  ggplot(data = ., aes(y = PD0400, fill = factor(zpsex),
                       x = (..count..)/sum(..count..) )) +
  geom_bar(position=position_dodge()) +
  scale_fill_manual(values = c("navajowhite","navy"),
                    breaks = c(1,2), labels = c("Männer", "Frauen")) +
  scale_x_continuous(labels = scales::label_percent(accuracy = 1)) +
  scale_y_continuous(breaks = 1:4, 
                     labels = c("Überhaupt nicht",
                                "Eher nicht",
                                "Eher schon",
                                "Sehr")) +
  labs(title = "Religiösität nach Geschlecht",
       subtitle = "Relative Häufigkeiten",
       caption = "Quelle: PASS-CF 0619",
       y = "Religiösität",
       x = "Relative Häufigkeit",
       fill = "Geschlecht" ) 

4.5.1 Übung

4.6 Übungen

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

pend <-
  haven::read_dta("./orig/PENDDAT_cf_W13.dta",
    col_select = c("zpsex","welle","bilzeit","PA0445","PG1270","PEO0400c")
    )

4.6.1 Übung 1

pend_u41 <-
  pend %>% 
  filter(welle == 13, bilzeit > 0, PA0445 >0) 
  • Erstellen Sie einen Scatterplot für die Variablen Dauer der gesamten Arbeitslosigkeitserfahrung in Monaten (PA0445, y-Achse) und Dauer der Ausbildung (bilzeit, x-Achse).
  • Legen Sie die Farbe so fest, dass Männer und Frauen unterschiedliche Farben gekennzeichnet werden (zpsex)
  • 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

pend_u42 <-
  pend %>% 
  filter(welle == 9, PG1270 >0) 
  • Erstellen Sie einen Boxplot oder Histogramm für die Verteilung der Anzahl gerauchter Zigaretten und Zigarillos pro Tag (i.d. letzten Woche) (PG1270).
  • Passen Sie diese Grafik so an, dass die Verteilungen 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

pend_u43 <-
  pend %>% 
  filter(welle == 11, PEO0400c >0) 
  • Erstellen Sie ein Säulen-Diagramm für die Antworten auf die Frage “Eine berufstätige Mutter kann ein genauso herzliches Verhältnis zu ihren Kindern haben, wie eine Mutter, die nicht erwerbstätig ist.” (PEO0400c)
  • Erstellen Sie ein Säulen-Diagramm für d(PEO0400c) getrennt nach der Variable migration, legen Sie also die Farbe der Säulen nach migration fest. Die Variable migration erfasst, ob die Befragten einen Migrationshintergrund haben:
Variable value label

PEO0400c

1 Stimme voll und ganz zu
2 Stimme eher zu
3 Stimme eher nicht zu
4 Stimme ueberhaupt nicht zu

migration

1 Kein Migrationshintergrund
2 selbst / mind. 1 Elternteil zugezogen
3 Mind. 1 Elternteil zugezogen
4 Mind. 1 Grosselt. zugez., Elt. in D geb.

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 = pend_small, aes(x = palter, y = azges1, color = factor(zpsex))) + 
  geom_point(size = 2) + 
  theme_minimal()

ggplot(data = pend_small, aes(x = palter, y = azges1, color = factor(zpsex))) + 
  geom_point(size = 2) +
  theme_dark()

4.7.3 Farben

p1 <- ggplot(data = pend_small, aes(x = palter, y = azges1, color = factor(zpsex))) + 
  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

  • Das Graph Kapitel des R Cookbooks ist eine hervorragende Quelle für alle möglichen Optionen und eine grundlegende Übersicht - bspw. zur Anpassung der Legende, Linien- und Punktvarianten oder den Achsen

  • Schriftgröße und -farbe anpassen: Hier findet sich eine gute Übersicht, wie die Schriftgröße und -farbe in {ggplot2} angepasst werden kann.

  • 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↩︎