A1 – Grafiken mit ggplot2

Statistische Datenanalyse mit R

Autor

Clemens Brunner

Veröffentlicht

9. Mai 2023

Allgemeines

Im Gegensatz zum Base-Plotting-System muss das Paket ggplot2 installiert und aktiviert werden:

library(ggplot2)

Dieses Paket ist eine Implementierung der sogenannten Grammar of Graphics, welche statistische Grafiken mit einheitlichen grundlegenden Elementen zu beschreiben versucht. Dies hat den Vorteil, dass man mit dieser Grammatik die unterschiedlichsten Grafiken zusammenbauen kann und nicht für jede Darstellung einen anderen Befehl benötigt.

Aufbau einer Grafik

Eine Grafik in ggplot2 besteht aus verschiedenen Ebenen. Jede Ebene beinhaltet geometrische Elemente (Geoms genannt) – z.B. Balken, Linien oder Text. Geoms haben ästhetische Eigenschaften (kurz Aes genannt), welche das Aussehen von Geoms bestimmen (beispielsweise die Position von Punkten, Farben oder Linienstile). Diese ästhetischen Eigenschaften werden aus Spalten eines Data Frames bestimmt, d.h. man erstellt ein Mapping zwischen den Daten und passenden Aes. Das folgende Bild veranschaulicht den Ebenencharakter einer Grafik in ggplot2:

Die ggplot()-Funktion

Erstellen wir einige beispielhafte Grafiken mit dem in R verfügbaren Datensatz airquality. Diese Daten beinhalten diverse Luftgütemessungen in New York im Zeitraum Mai bis September 1973 (siehe dazu ?airquality). Es ist sinnvoll, wenn wir zunächst aus den beiden Spalten Month und Day eine neue Spalte namens date erzeugen:

airquality$date = as.Date(
    paste(airquality$Month, airquality$Day, "1973"),
    format="%m %d %Y"
)

Eine Grafik in ggplot2 beginnt immer mit der ggplot()-Funktion. Hier ist nun der Aufbau einer Grafik von Bedeutung – d.h. es ist wichtig zu wissen, dass sich eine Grafik aus mehreren Ebenen zusammensetzt. Man beginnt also immer mit der Spezifikation der Grafik, d.h. man legt das Data Frame fest, aus dem die darzustellenden Spalten stammen. Außerdem gibt man die Spalten aus diesem Data Frame an, die man durch Zuweisen gewünschter ästhetischer Eigenschaften plotten möchte.

Im ersten Schritt legen wir also das Data Frame und die Spalten fest:

ggplot(airquality, aes(x=Wind, y=Ozone))

Hier ist anzumerken, dass die darzustellenden Spalten innerhalb der Funktion aes() angegeben werden müssen. Weiters kann man (so wie bei allen Funktionsaufrufen) die Namen der übergebenen Funktionsargumente explizit angeben (data und mapping), dann ist die Zuordnung bzw. Bedeutung der Argumente sofort klar:

ggplot(data=airquality, mapping=aes(x=Wind, y=Ozone))

Die Spalte Wind wird also auf die ästhetische Eigenschaft x abgebildet (also entlang der x-Achse dargestellt), die Spalte Ozone analog auf die ästhetische Eigenschaft y.

Die eigentlichen Daten werden aber noch nicht dargestellt, denn wir haben noch nicht spezifiziert, wie die Daten gezeichnet werden sollen. Dafür benötigt man eine neue Ebene mit den gewünschten Geoms. In unserem Beispiel möchten wir Punkte zeichnen, d.h. wir verwenden geom_point() dafür und fügen diese mit + zur ersten Ebene hinzu:

ggplot(data=airquality, mapping=aes(x=Wind, y=Ozone)) +
    geom_point()

Hinweis

Der Zeilenumbruch ist hier (wie in alle R-Befehlen) nicht notwendig, erhöht aber die Übersicht, weil man so eine Ebene pro Zeile darstellen kann.

In weiteren Ebenen kann man dann Titel und Achsenbeschriftungen ändern/hinzufügen:

ggplot(data=airquality, mapping=aes(x=Wind, y=Ozone)) +
    geom_point() +
    ggtitle("Wind vs. Ozone") +
    xlab("Wind (mph)") +
    ylab("Ozone (ppb)")

Tipp

Alternativ könnte man alle drei Beschriftungen mit der Funktion labs() hinzufügen:

ggplot(data=airquality, mapping=aes(x=Wind, y=Ozone)) +
    geom_point() +
    labs(title="Wind vs. Ozone", x="Wind (mph)", y="Ozone (ppb)")

In einer weiteren Ebene kann man dann eine Regressionsgerade (einen sogenannten “Smoother”) hinzufügen:

ggplot(data=airquality, mapping=aes(x=Wind, y=Ozone)) +
    geom_point() +
    labs(title="Wind vs. Ozone", x="Wind (mph)", y="Ozone (ppb)") +
    geom_smooth(method="lm", formula="y ~ x")

Möchte man die Punkte z.B. für den Monat Mai (entspricht dem Wert 5) hervorheben (die Regressionsgerade aber für alle Punkte belassen), kann man innerhalb geom_point() eine lokale Ästhetik color definieren, welche dem logischen Vektor Month == 5 entspricht (also TRUE für alle Zeilen in denen die Spalte Month den Wert 5 hat und FALSE in allen anderen Fällen):

ggplot(data=airquality, mapping=aes(x=Wind, y=Ozone)) +
    geom_point(mapping=aes(color=Month==5)) +
    geom_smooth(method="lm", formula="y ~ x") +
    labs(title="Ozone and Wind in NYC")

Dieses lokale Mapping wird dem globalen Mapping (innerhalb von ggplot()) hinzugefügt.

Es gibt eine große Anzahl an Elementen, aus denen man die unterschiedlichsten Grafiken zusammenbauen kann. Die offizielle ggplot2-Website hat eine vollständige Liste aller Geoms, Aesthetics und anderer Befehle. Im Folgenden sehen wir uns noch an, wie man Histogramme, Boxplots und Fehlerbalkenplots erzeugen kann.

Eine Liniengrafik erzeugt man mit geom_line():

ggplot(data=airquality, mapping=aes(x=date, y=Ozone)) +
    geom_line()

Ein Histogramm erstellt man mit geom_histogram():

ggplot(data=airquality, mapping=aes(x=Ozone)) +
    geom_histogram() + ylab("")

Auch hier kann man die Bingröße manuell angeben:

ggplot(data=airquality, mapping=aes(x=Ozone)) +
    geom_histogram(binwidth=10) + ylab("")

Boxplots können mit geom_boxplot() erzeugt werden. Um Boxplots gleichzeitig für alle Stufen eines Faktors darzustellen, muss man dies wie folgt spezifizieren (die Spalte Month wird zur Darstellung auf der x-Achse in einen Faktor konvertiert):

ggplot(data=airquality, mapping=aes(x=factor(Month), y=Ozone)) +
    geom_boxplot() + xlab("Month")

Um einen Fehlerbalkenplot zu erstellen (der die Mittelwerte und deren 95%-Konfidenzintervalle zeigt), kann man die Funktion stat_summary() benutzen. Für diese Grafik muss außerdem das Paket Hmisc installiert sein.

library(Hmisc)

ggplot(data=airquality, mapping=aes(x=factor(Month), y=Ozone)) +
    stat_summary(fun=mean, geom="point") +
    stat_summary(fun.data=mean_cl_normal, geom="errorbar", width=0.2) +
    xlab("Month")

Themes

Wenn man mit dem generellen Stil der Grafiken nicht zufrieden ist, kann man ein anderes vordefiniertes Theme verwenden. Folgende Themes stehen zur Auswahl:

  • theme_gray()
  • theme_bw()
  • theme_linedraw()
  • theme_light()
  • theme_dark()
  • theme_minimal()
  • theme_classic()
  • theme_void()

Man aktiviert ein Theme indem man es als eigene Ebene zu einer vorhandenen Grafik hinzufügt:

ggplot(airquality, aes(x=factor(Month), y=Ozone)) +
    stat_summary(fun=mean, geom="point") +
    stat_summary(fun.data=mean_cl_normal, geom="errorbar", width=0.2) +
    xlab("Month") +
    theme_minimal()

Alternativ kann man mit der Funktion theme_set() ein Theme auch global für alle Grafiken setzen. Alle Grafiken, die danach erzeugt werden, verwenden diesen Stil. Das folgende Beispiel setzt theme_minimal() als Standard-Theme:

theme_set(theme_minimal())

Patchwork

Möchte man mehrere Grafiken in einem Plot darstellen, bietet sich das Paket patchwork an. Damit kann man Grafiken sehr einfach zu beliebigen Layouts kombinieren:

library(patchwork)

p1 = ggplot(airquality, aes(x=date, y=Ozone)) + geom_line() + geom_point()
p2 = ggplot(airquality, aes(x=Wind, y=Ozone, color=Month==5)) + geom_point()
p3 = ggplot(mpg, aes(x=factor(cyl), y=cty)) + geom_boxplot()

p1 / (p2 + p3)

Dabei kennzeichnet / eine neue Zeile und + eine neue Spalte.

Übungen

Übung 1

Laden Sie den Datensatz penguins aus dem Paket palmerpenguins und erstellen Sie einen Scatterplot der Spalten bill_length_mm auf der x-Achse und bill_depth_mm auf der y-Achse. Fügen Sie eine Regressionsgerade hinzu. Beschriften Sie die Achsen mit aussagekräftigen Bezeichnungen.

Übung 2

Laden Sie den Datensatz penguins aus dem Paket palmerpenguins und erstellen Sie einen Scatterplot der Spalten bill_length_mm auf der x-Achse und bill_depth_mm auf der y-Achse. Stellen Sie die Punkte der drei Spezies in unterschiedlichen Farben dar. Beschriften Sie die Achsen mit aussagekräftigen Bezeichnungen.

Vergleichen Sie die Regressionsgeraden der einzelnen Spezies mit der Gerade über die gesamten Daten aus Übung 1 – fällt Ihnen etwas auf (Stichwort Simpson-Paradoxon)?

Übung 3

Laden Sie den in R integrierten Datensatz Orange und stellen Sie die Abhängigkeit des Stammumfanges circumference (y-Achse) vom Alter age (x-Achse) grafisch dar. Stellen Sie die Daten als Punkte dar und verbinden Sie außerdem die Daten eines jeden Baumes (d.h. Sie sollten dann 5 Linien gleichzeitig darstellen, am besten in unterschiedlichen Farben indem Sie das Mapping color=Tree verwenden).

Übung 4

Verwenden Sie den Datensatz mpg, welcher automatisch mit ggplot2 geladen wird. Wie hängt der Hubraum displ mit dem Kraftstoffverbrauch hwy zusammen? Beantworten Sie diese Frage mit einem Scatterplot und überlagerter Regressionsgerade.

Übung 5

Verwenden Sie den Datensatz mpg und erstellen Sie einen Boxplot, in dem Sie den Kraftstoffverbrauch in Liter pro 100 Kilometer (l/100km) der Zylinderanzahl gegenüberstellen. Erstellen Sie dazu eine neue Spalte l100km im Data Frame mpg, die den Kraftstoffverbrauch in l/100km aus der Spalte hwy (in Meilen pro Gallone, MPG) berechnet. Sie erhalten diesen Verbrauch mit folgender Formel:

\[\text{Verbrauch (in l/100km)} = \frac{235}{\text{Verbrauch (in MPG)}}\]

Übung 6

Welches Problem hat die Grafik, die Sie in Übung 4 erstellt haben? Wie können Sie dieses Problem mit ggplot2 umgehen? Sehen Sie sich die Werte der displ-Spalte an. In diesem Zusammenhang könnte geom_jitter() hilfreich sein.

Übung 7

Betrachten Sie folgenden Scatterplot mit überlagerter Regressionsgeraden:

library(tibble)

df = tibble(x=1:10, y=1:10)

ggplot(data=df, mapping=aes(x=x, y=y)) +
    geom_point(size=4) +
    geom_smooth(method="lm", formula="y ~ x")

Die Punkte werden von der Regressionsgeraden überdeckt – wie kann man das verhindern? Die Gerade soll also “hinter” den Punkten gezeichnet werden.