7  Grafiken erstellen

7.1 Aller Anfang…

… ist eigentlich nicht schwer. Bevor es losgeht müssen wir immer die notwendigen Pakete laden. Da in diesem Kapitel mit ggplot2 gearbeitet wird, muss zumindest das geladen sein. Der Datensatz penguins ist seit der Version R 4.5.0 immer als Datensatz geladen. Sollte die installierte R Version älter sein, so ist die Installation einer neueren R-Version sowieso sinnvoll. Ferner benötigen wir das Paket ggthemes: in diesem gibt es Farbpaletten, die auch von Farbenblinden gut auseinander gehalten werden können, weswegen wir auch dieses Paket laden (und ggf. vorher installieren)

# ab R Version  4.5.0
library(pacman)
p_load(ggplot2, ggthemes)

Später, wenn Daten nicht in einem Paket gegeben sind, sondern zusätzlich geladen und aufgearbeitet werden müssen, ist es einfacher das komplette Tidyverse (und ggf. andere benutzte Pakete) am Anfang (eines Skriptes) zu laden, da nicht nur ggplot2 sondern auch Pakete wir readr, tidyr, dplyr etc. benötigt werden, die alle Teil des Tidyverses sind. Wir werden in Kapitel 3 noch näher darauf eingehen.

## Laden der Pakete (ein Beispiel!):

library(pacman)
p_load(tidyverse, ggthemes)

7.2 Erstellen von Grafiken

Ziel dieses Kapitels ist es den Aufbau einer ggplot2-Grafik zu verstehen, und am Ende der Kapitels wollen wir aus der Datentabelle penguins das folgende Streudiagramm erstellen können:

Abbildung 7.1: Palmer Pinguine

7.2.1 Die Datentabelle penguins

Wir nutzen den Datensatz penguins um die Funktionsweise von ggplot2 zu verstehen. Durch Eingabe von penguins in der Konsole können wir uns den Datensatz (bzw. die ersten Zeilen des Datensatzes) ansehen.

penguins

Bei dem Datensatz handelt es sich um ein Data Frame einem Standard Datenformat in R für Datentabellen. Die Ausgabe ist ein wenig unübersichtlich, weshalb wir das modernere Format eines Tibbles (aus dem Tidyverse) bevorzugen.

as_tibble(penguins)  # interpretiert den Datensatz als Tibble
# A tibble: 344 × 8
   species island    bill_len bill_dep flipper_len body_mass sex     year
   <fct>   <fct>        <dbl>    <dbl>       <int>     <int> <fct>  <int>
 1 Adelie  Torgersen     39.1     18.7         181      3750 male    2007
 2 Adelie  Torgersen     39.5     17.4         186      3800 female  2007
 3 Adelie  Torgersen     40.3     18           195      3250 female  2007
 4 Adelie  Torgersen     NA       NA            NA        NA <NA>    2007
 5 Adelie  Torgersen     36.7     19.3         193      3450 female  2007
 6 Adelie  Torgersen     39.3     20.6         190      3650 male    2007
 7 Adelie  Torgersen     38.9     17.8         181      3625 female  2007
 8 Adelie  Torgersen     39.2     19.6         195      4675 male    2007
 9 Adelie  Torgersen     34.1     18.1         193      3475 <NA>    2007
10 Adelie  Torgersen     42       20.2         190      4250 <NA>    2007
# ℹ 334 more rows

Der Datensatz enthält 8 Merkmale (die Spalten) und 344 Beobachtungen (die Zeilen). Die Tabelle zeigt eine Erläuterung der Merkmale, die man auch in der Hilfe help(penguins) findet.

Tabelle 7.1: Übersicht zur Datentabelle penguins aus dem Paket datasets.
Name des Merkmals Bedeutung Skalentyp in R
species Pinguin Spezies nominal <fct>
island Insel im Palmer-Archipel nominal <fct>
bill_len Schnabellänge in mm metrisch <dbl>
bill_dep Schnabeltiefe in mm metrisch <dbl>
flipper_len Flossenlänge in mm metrisch <dbl>
body_mass Körpergewicht in g metrisch <int>
sex Geschlecht nominal <fct>
year Jahr der Untersuchung metrisch <int>

Beim Aufrufen der Hilfefunktion in der Konsole mittels

help(penguins)  
# oder alternativ 
?penguins

erscheint die Hilfe im dafür vorgesehenen Reiter. Die geschweifte Klammer in der Hilfe penguins {datasets} bedeutet, dass der Datensatz (allgemein das R-Objekt) im Paket datasets enthalten ist. Einige Pakete wie zum Beispiel base, datasets, utils oder stats sind immer geladen, wenn R geöffnet wird.

Abbildung 7.2: Hilfe zum Datensatz penguins

Eine weitere Möglichkeit eine Übersicht über die Daten zu bekommen, ist die Funktion glimpse(), die im Paket dplyr aus dem Tidyverse enthalten ist.

glimpse(penguins)
Rows: 344
Columns: 8
$ species     <fct> Adelie, Adelie, Adelie, Adelie, Adelie, Adelie, Adelie, Ad…
$ island      <fct> Torgersen, Torgersen, Torgersen, Torgersen, Torgersen, Tor…
$ bill_len    <dbl> 39.1, 39.5, 40.3, NA, 36.7, 39.3, 38.9, 39.2, 34.1, 42.0, …
$ bill_dep    <dbl> 18.7, 17.4, 18.0, NA, 19.3, 20.6, 17.8, 19.6, 18.1, 20.2, …
$ flipper_len <int> 181, 186, 195, NA, 193, 190, 181, 195, 193, 190, 186, 180,…
$ body_mass   <int> 3750, 3800, 3250, NA, 3450, 3650, 3625, 4675, 3475, 4250, …
$ sex         <fct> male, female, female, NA, female, male, female, male, NA, …
$ year        <int> 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007…

In der ersten Spalte stehen die Merkmale des Datensatzes, dahinter der Datentyp und in der dritten Spalte die ersten Einträge des jeweiligen Merkmals.

7.2.2 Erste Schritte zur Grafik

Um Daten zu untersuchen sind geeigneten Grafiken ein sehr gutes Mittel. Welche Grafiken geeignet sind hängt von der Anzahl der Merkmale, die dargestellt werden sollen, sowie deren Skalenniveaus ab. Darauf werden wir im Kapitel 5 und im Kapitel 9 noch genauer eingehen. Neben dem explorativen Charakter haben Grafiken in wissenschaftlichen Publikationen, Bachelor-, Master- oder Doktorarbeiten die Aufgabe Informationen möglichst verständlich zu übermitteln.

Wir fangen mit einem einfachen Streudiagramm (zwei metrische Merkmale) an, und untersuchen den Datensatz penguins auf die Frage

“Gibt es einen Zusammenhang zwischen Flossenlänge und Körpergewicht bei Pinguinen?”

Die Merkmale des Datensatzes um dieser Frage nachzugehen sind flipper_len und body_mass. Wie wollen nun die Grafik Schritt für Schritt aufbauen. Dabei erkennt man sehr schnell, dass der Aufbau in Lagen (auf englisch: layers) funktioniert.

Die Funktion ggplot() stellt das Grundgerüst jeder Grafik dar.

ggplot(
  data = penguins,
  mapping = aes(x = flipper_len, y = body_mass)
)
Abbildung 7.3: Leeres Koordinatensystem

Gehen wir jeden Schritt oben einmal durch: Dem Argument data= wird die Datentabelle (hier: penguins) zugewiesen. Im Argument mapping= wird angegeben, wie die Merkmale des Datensatzes zu verwenden sind. Dies geschieht innerhalb der Funktion aes(), was für Aesthetics steht. In unserem Beispiel wird der x-Koordinate das Merkmal flipper_len zugewiesen und der y-Koordinate das Merkmal body_mass. Damit hat man nun ein leeres Koordinatensystem geschaffen wie Abbildung 7.3 zeigt. Der dargestellte Abschnitt der Achsen wird so gewählt, dass alle Datenpunkte dargestellt werden könnten. Wir werden später noch lernen, wie man die dargestellten Achsenabschnitte ändern kann.

Im nächsten Schritt wird der Grafik die geometrische Funktion geom_point() hinzugefügt. Dies geschieht mit einem + Zeichen hinter der Funktion ggplot(). Die Funktion geom_point() zeichnet nun das Streudiagramm, das heißt für jede Beobachtung wird der Punkt (flipper_len, body_mass) in das Koordinatensystem eingezeichnet.

ggplot(
  data = penguins,
  mapping = aes(x = flipper_len, y = body_mass)
) + 
   geom_point()
Warning: Removed 2 rows containing missing values or values outside the scale range
(`geom_point()`).
Abbildung 7.4: Koordinatensystem mit Datenpunkten

Dieses Streudiagramm ist noch relativ weit weg von Abbildung 7.1, allerdings kann man an dieser Stelle bereits die Frage “Gibt es einen Zusammenhang zwischen Flossenlänge und Körpergewicht bei Pinguinen?” beantworten, da der Trend “von unten links nach oben rechts” der Punkte im Koordinatensystem gut zu sehen ist.

Bemerkung:

Zwischen dem R-Code und der Grafik steht die Warnung:

| Warning: Removed 2 rows containing missing values or values

Dies bedeutet, dass bei zwei Beobachtungen mindestens eines der beiden Merkmale ein Wert fehlt. An Stelle eines Wertes steht NA, was für Not Available steht, in der Datentabelle. Daher kann für diese Beobachtung kein Punkt in der Grafik dargestellt werden.

Dies ist ein typisches Verhalten für R (sofern man bei Programmiersprachen von einem Verhalten reden kann): es werden keine Daten einfach unterschlagen, sondern der Benutzer soll wissen wenn R Daten nicht oder nur partiell darstellen kann. Es gibt einige Stellen an denen R den Nutzer warnt, da dieser entweder ungünstige Entscheidungen getroffen hat oder ggf. für den Nutzer unerwartete Ausgaben produziert wurden.

7.2.3 Hinzufügen von Aesthetics und Schichten

Der nächste Schritt beim Aufbau der Grafik ist nun zusätzlich zu den zwei metrischen Merkmalen ein kategoriales Merkmal, nämlich die Spezies, die im Merkmal species steht, hinzuzufügen. Wir möchten die Punkte je nach Spezies verschieden einfärben. Das Argument dazu heißt color= oder colour= und muss ebenfalls in die Funktion aes() geschrieben werden. Der Grund ist, dass alle Eigenschaften der Grafik, die von der Ausprägung eines Merkmals abhängig sind, innerhalb der Funktion aes() stehen müssen.

ggplot(
  data = penguins,
  mapping = aes(x = flipper_len, y = body_mass, color = species)
) +
  geom_point()
Abbildung 7.5: Das Streudiagramm enthält zwei metrische Merkmale (die x- bzw. y-Koordinate), und ein nominales Merkmal (die Färbung).
WichtigMerke: Aesthetics Funktion aes()

Alle Eigenschaften einer Grafik, die von den Ausprägungen eines Merkmals abhängen, müssen in die Funktion aes() geschrieben werden!

Der nächste Schritt besteht darin eine Regressionsgerade durch die Daten zu legen. Die erreichen wir durch Hinzufügen einer weiteren geometrischen Funktion geom_smooth(). Ohne weitere Argumente hinzufügen wird eine geglättete Kurve (auch Spline genannt) mit Konfindezintervall eingezeichnet.

ggplot(
  data = penguins,
  mapping = aes(x = flipper_len, y = body_mass, color = species)
) +
  geom_point() + 
  geom_smooth(method = "lm")
Abbildung 7.6: Eine Regressionsgerade je Spezies

Das Argument method= "lm" sorgt dafür, dass die geglättete Kurve mit Hilfe einer linearen Regression gewonnen wird. Wie man erkennen kann, werden in obigen Fall die Regressionsgeraden für jede Spezies einzeln ermittelt. Das ist allerdings nicht das, was wir im Sinn hatten. Beheben kann man dies indem die Aesthetic für die Einfärbung color= nur für die geometrische Funktion geom_point(), nicht aber für alle anderen geometrischen Funktionen verwendet werden soll.

ggplot(
  data = penguins,
  mapping = aes(x = flipper_len, y = body_mass)
) +
  geom_point(mapping = aes(color = species)) + 
  geom_smooth(method = "lm")
Abbildung 7.7: Eine Regressionsgerade für alle Datenpunkte

Wir sehen, dass mapping= in der Funktion ggplot() global für alle geometrischen Funktionen gilt, man jedoch auch lokal Aesthetics für einzelne geometrische Funktionen angeben kann.

Das Ergebnis ist schon sehr nah an Abbildung 7.3. Da innerhalb des Streudiagramms nicht nur die Farbe, sondern auch die Form der Datenpunkte bezüglich des Merkmals species geändert ist, kann man dies noch ändern. Dafür wird das Argument shape= in die Aesthetics geschrieben. Da für jede Spezies die Datenpunkte im Koordinatensystem eine andere Form bekommen sollen, lautet das Argument shape=species.

ggplot(
  data = penguins,
  mapping = aes(x = flipper_len, y = body_mass)
) +
  geom_point(mapping = aes(color = species, shape = species)) + 
  geom_smooth(method = "lm")
Abbildung 7.8: Wie Abbildung 7.7, aber mit geänderter Form der Datenpunkte.

Die beiden letzten Änderungen betreffen die Beschriftungen, sowie das Ändern des Farbschemas.

ggplot(
  data = penguins,
  mapping = aes(x = flipper_len, y = body_mass)
) +
  geom_point(mapping = aes(color = species, shape = species)) + 
  geom_smooth(method = "lm") +
  labs(title = "Körpergewicht und Flossenlänge",
       subtitle = "für Adelie, Chinstrap und Gentoo Pinguine",
       x = "Flossenlänge (mm)", 
       y = "Körpergewicht (g)",
       color = "Spezies", 
       shape = "Spezies") +
  scale_color_colorblind()
Abbildung 7.9: Das fertige Diagramm!

Für die Änderungen aller Beschriftung fügt man als nächste Schicht die Funktion labs() hinzu und gibt an, welche Größen umbenannt werden sollen. Interessant sind die letzten beide Argumente: color= und shape= Damit wird in der Legende die Überschrift geändert.

Die letzte Funktion scale_color_colorblind() aus dem Paket ggthemes ändert das Farbschema derart, dass es für Farbenblinde geeignet ist.

7.2.4 Die ggplot2-Syntax

Der Code der obigen Grafiken war sehr explizit und etwas sperrig. Um die Syntax ein wenig zu vereinfachen, schauen wir uns den Code der Grafiken noch einmal an und vereinfachen die Syntax.

ggplot(
  data = penguins,
  mapping = aes(x = flipper_len, y = body_mass)
) + 
  geom_point(mapping = aes(color = species))

Sehen wir uns dafür einmal die Hilfe der Funktion ggplot() an:

Abbildung 7.10: Hilfe zur Funktion ggplot()

Die ersten beiden Argumente der Funktion ggplot() sind data= und mapping= und bei den geometrischen Funktionen wie geom_point() ist mapping= das erste Argument. Bei Funktionen, die man häufiger nutzt, lässt man den Namen des ersten, ggf. auch der ersten beiden Argumente in der Regel weg. Dies erleichtert die Lesbarkeit des Codes. An den allermeisten Stellen in diesem Kurs werden wir auch auf diese Argumentnamen verzichten. Der obige Code wird damit zu:

ggplot(penguins, aes(x = flipper_len, y = body_mass)) + 
   geom_point(aes(color = species))
WichtigAchtung

Die Reihenfolge der Argumente innerhalb einer Funktion darf nicht geändert werden, wenn man Argumentnamen weglässt! Wir werden dies in Kapitel 11.2 noch detaillierter betrachten.

Nutzen wir nun noch die Pipe-Syntax (siehe Kapitel 11.5), so erhalten wir eine kompakte und praktische Form um Grafiken zu erzeugen. Dass diese Schreibweise sehr vorteilhaft ist wird spätetstens im Kapitel 17 klar.

penguins |> 
   ggplot(aes(x = flipper_len, y = body_mass)) + 
   geom_point(aes(color = species))

Bemerkungen

  • Sowohl der Pipe-Operator |> als auch das Plus-Zeichen + dürfen nur in der der Mitte oder am Ende einer Zeile, nicht aber am Anfang einer Zeile stehen. R interpretiert eine Zeile in die nicht mit einer Pipe oder einem Plus endet als vollständig (sofern alle Klammern geschlossen wurden), und führt diese dann nur bis dahin aus!

  • Bei R sind die Einrückungen der Zeilen wie im obigen Code nicht notwendig. Bei andern Programmiersprachen, wie zum Beispiel Python, ist das anders, da dort keine Klammern gesetzt werden. Ein Einrücken der Zeilen, sowie gezielt gesetzte Leerzeilen, erhöhen aber die Lesbarkeit des Codes. Es gibt einen Tidyverse Style Guide in dem erläutert wird wie man Code setzen soll. Dies ist insbesondere dann interessant, wenn man ein Skript schreibt und nicht nur Code in die Konsole eintippt.

7.3 Grafiken abspeichern

Nachdem wir eine Grafik erstellt haben, möchten wir diese speichern, um sie ggf. an anderer Stelle zu nutzen. Dies geht mit der Funktion ggsave(), die die erzeugte Grafik im Arbeitsverzeichnis abspeichert:

penguins |> 
  ggplot(aes(x = flipper_len,  y = body_mass)) +
  geom_point()

ggsave(filename = "pinguin-plot.png")

Es ist auch möglich der Funktion ggsave() die Argumente width= und height= mitzugeben, so dass man die Größe der Grafik kontrollieren kann. Gibt man die Argumente nicht an, so werden die Größen vom aktuellen plotting device genommen.

Viel besser als die Grafiken abzuspeichern und irgendwo einzufügen ist allerdings die Verwendung von quarto, da man dort die Grafiken direkt dynamisch einbinden kann.

7.4 Aufgaben

HinweisGrafik erstellen
  1. Laden Sie das Paket DA.students und verschaffen Sie sich einen Überblick über den Datensatz dat.studenten. Wie viele Merkmale und wie viele Beobachtungen gibt es?

  2. Erstellen Sie aus dem Datensatz ein Streudiagramm aus den Merkmalen AlterV und AlterM.

  3. Die geometrische Funktion geom_point() hat das Argument alpha=. Was macht das Argument und warum ist dies in der letzten Grafik sinnvoll?

  4. Zeichnen Sie eine Regressionsgerade in das Diagramm ein.

  5. Beschriften sie die Achsen und geben Sie der Grafik einen geeigneten Namen.

  6. Speichern Sie die Grafik als png-Datei ab.

Hier sind die Lösungen zum Download.

  1. In einer ersten Variante habe ich ein gewöhnliches R-Skript erstellt (mit der Endung .R). Dieses können wir laden und dann manuell ausführen. Dabei erhalten wir alle Grafiken. Kommentare sind hinter # (oder auch mehere) geschrieben und werden bei der Ausführung nicht ausgeführt.

uebung_grafiken.R

  1. In einer zweiten Variante habe ich die Lösungen in ein Quarto-Skript geschrieben (mit der Endung .qmd). Dieses muss gerendert werden (zum Beispiel mit der Pfeiltaste oberhalb des Skripts). Heraus kommt eine html-Seite die im Browser usgegeben wird. Bei der Quarto Datei geben # die verschiedenen Kapitel an. Kommentare können als Text geschrieben werden. Dafür muss der R-Code in Chunks geschrieben werden, das sind Abschnitte, die mit ```{r} starten und mit ``` enden.

uebung_grafiken.qmd