5  Visualisierung

Ein Bild sagt mehr als tausend Worte.

Sprichwort

5.1 Einführung in die grafische Darstellung in R

Datenvisualisierung ist ein entscheidender Bestandteil der Datenanalyse. Sie hilft dabei, komplexe Zusammenhänge sichtbar zu machen, Muster zu identifizieren und Ergebnisse verständlich zu kommunizieren. Visualisierungen dienen dabei nicht nur der Präsentation von Ergebnissen, sondern bereits sehr früh der explorativen Datenanalyse: Ausreißer, Verteilungen und Auffälligkeiten werden häufig erst durch Grafiken sichtbar.

R bietet mehrere Grafiksysteme. In der Praxis sind insbesondere zwei Ansätze relevant:

  1. Basisgrafiken (Base R): schnell verfügbar, direkt in R enthalten.
  2. ggplot2: sehr konsistentes, flexibles und im Data-Science-Umfeld verbreitetes Grafiksystem.

In diesem Kapitel werden zunächst Basisgrafiken kompakt eingeführt und anschließend Visualisierungen mit ggplot2 ausführlich behandelt.

5.2 Base R kompakt

5.2.1 Das Basisprinzip

Die Basisfunktion für viele Darstellungen ist plot(x, y, ...). Diese Funktion zeichnet standardmäßig ein Streudiagramm und lässt sich über zahlreiche Argumente anpassen.

Damit plot(x, y) funktioniert, müssen

  • x und y numerische Vektoren sein,
  • beide Vektoren die gleiche Länge besitzen.

Die Werte aus x bestimmen die horizontale Position (x-Achse), die Werte aus y die vertikale Position (y-Achse).

x <- 1:10
y <- c(2, 4, 3, 5, 6, 7, 9, 8, 10, 11)

plot(x, y)

5.2.2 Plot-typübergreifende Parameter in Base R

Viele Base-R-Funktionen (plot, hist, boxplot, barplot, …) verwenden dieselben oder sehr ähnliche grafische Parameter. Die wichtigsten sind in Tabelle 5.1 zusammengefasst.

Tabelle 5.1: Wichtige plot-typübergreifende Parameter in Base R
Parameter Bedeutung
main Titel der Abbildung
sub Untertitel der Abbildung
xlab Beschriftung der x-Achse
ylab Beschriftung der y-Achse
col Farbe (z. B. Name wie "steelblue" oder Hex-Farbe)
pch Punktsymbol (bei Punktdarstellungen)
cex Größenfaktor für Text/Symbole
lty Linientyp (durchgezogen, gestrichelt, …)
lwd Linienstärke
xlim Grenzen der x-Achse als Vektor c(min, max)
ylim Grenzen der y-Achse als Vektor c(min, max)

5.2.3 Streudiagramm mit plot

Die Funktion plot eignet sich für die Darstellung des Zusammenhangs zweier numerischer Variablen.

Wichtige Inputs:

  • x: numerischer Vektor für die x-Achse,
  • y: numerischer Vektor für die y-Achse (gleiche Länge wie x),
  • optional type: Darstellungsart ("p" Punkte, "l" Linie, "b" beides).
plot(
  x = x,
  y = y,
  type = "b",
  pch = 19,
  col = "steelblue",
  lwd = 2,
  main = "Beispiel: x-y-Plot mit Base R",
  xlab = "x-Werte",
  ylab = "y-Werte"
)
Abbildung 5.1: Streudiagramm mit Base R

Die Abbildung in Abbildung 5.1 zeigt bereits mehrere typische Parameter: über type = "b" werden Punkte und Linien kombiniert, pch steuert die Punktsymbole, lwd die Linienstärke und col die Farbe.

5.2.4 Histogramm mit hist

Die Funktion hist dient zur Darstellung von Verteilungen einer einzelnen numerischen Variable.

Wichtige Inputs:

  • x: numerischer Vektor,
  • optional breaks: Anzahl oder genaue Definition der Klassen,
  • optional freq: Häufigkeit (TRUE) oder Dichte (FALSE).
hist(
  mtcars$mpg,
  breaks = 12,
  col = "grey80",
  border = "white",
  main = "Verteilung der Variable mpg",
  xlab = "Miles per Gallon"
)
Abbildung 5.2: Histogramm mit Base R

breaks beeinflusst die Interpretation stark: zu wenige Klassen glätten zu stark, zu viele Klassen erzeugen ein sehr unruhiges Bild.

5.2.5 Boxplot mit boxplot

Boxplots sind besonders nützlich, um Verteilungen und Ausreißer zwischen Gruppen zu vergleichen.

Wichtige Inputs:

  • entweder ein einzelner numerischer Vektor,
  • oder eine Formel y ~ gruppe zusammen mit einem data-Argument.

Formelnotation in R

In vielen R-Funktionen (z. B. bei boxplot, später auch bei Regressionsmodellen) wird die sogenannte Formelnotation verwendet.

Die allgemeine Form lautet

zielvariable ~ erklärende_variable

Die Tilde ~ kann man hier sprachlich lesen als:

  • „in Abhängigkeit von“
  • oder „aufgeteilt nach“

Beispiele:

  • mpg ~ cyl: Verbrauch (mpg) in Abhängigkeit von der Zylinderzahl (cyl)
  • arr_delay ~ origin: Verspätung in Abhängigkeit vom Startflughafen

Für den Boxplot bedeutet mpg ~ cyl konkret: Für jede Ausprägung von cyl wird ein eigener Boxplot für mpg gezeichnet.

boxplot(
  mpg ~ cyl,
  data = mtcars,
  col = "grey90",
  main = "mpg nach Anzahl Zylinder",
  xlab = "Zylinder",
  ylab = "Miles per Gallon"
)
Abbildung 5.3: Boxplot mit Base R

Die Formel mpg ~ cyl bedeutet: Zeige die Verteilung von mpg, gruppiert nach den Ausprägungen von cyl.

5.2.6 Export von Base-R-Grafiken

Für den Export einzelner Abbildungen in Dateien (z. B. PNG, PDF oder SVG) kann die Ausgabe gezielt umgeleitet werden. In Base R erfolgt das über sogenannte Grafikgeräte. Die Grundlogik ist immer gleich:

  1. Grafikgerät öffnen (z. B. png(), pdf(), svg()),
  2. Plot-Befehle ausführen,
  3. Gerät mit dev.off() schließen.
Tabelle 5.2: Vergleich häufiger Exportformate für Abbildungen
Format Typ R-Funktion(en) Stärken Typische Nutzung
PNG Raster png() Sehr breit unterstützt, gut für Folien und Webseiten, steuerbares DPI Web, Präsentation
JPEG Raster jpeg() Kleine Dateien bei Fotos, aber verlustbehaftete Kompression Fotos, keine Standardwahl für Diagramme
TIFF Raster tiff() Hohe Qualität, drucknah, oft in Verlagen verlangt Druck/Publikation (je nach Vorgaben)
PDF Vektor pdf() Scharfe Linien/Text bei jeder Skalierung, druckfreundlich Berichte, Manuskripte, Druck
SVG Vektor svg() Skalierbar ohne Qualitätsverlust, oft ideal für Diagramme im Web Web, Quarto/HTML, nachträgliche Bearbeitung
Auto abhängig ggsave() (ggplot2) Format wird über Dateiendung gewählt, konsistent für ggplot2-Plots ggplot2-Workflows

Gerade für Datenvisualisierungen ist SVG häufig sehr gut geeignet:

  • Linien, Punkte und Text bleiben beim Zoomen scharf (keine Pixelartefakte).
  • Beschriftungen bleiben als Textobjekte erhalten und sind nachträglich editierbar.
  • In HTML/Quarto lassen sich SVG-Grafiken gut integrieren und bei Bedarf per CSS weiter stylen.

Einschränkung: Bei extrem vielen grafischen Elementen (z. B. sehr große Punktwolken) können SVG-Dateien groß und in Browsern träge werden. In solchen Fällen ist PNG oft robuster.

dev.off() ist entscheidend: Erst dadurch wird die Datei sauber abgeschlossen und final gespeichert.

Nutzung der Exportfunktionen

Das folgende Muster funktioniert für alle Gerätefunktionen:

<geraetefunktion>("dateiname.ext", ...)
<plot-befehle>
dev.off()

Typische Beispiele:

# Rasterformate
png("plot.png", width = 1600, height = 1000, res = 200, bg = "white")
plot(x, y, type = "b", col = "steelblue")
dev.off()

jpeg("plot.jpg", width = 1600, height = 1000, res = 200, quality = 90)
plot(x, y, type = "b", col = "steelblue")
dev.off()

tiff("plot.tiff", width = 1600, height = 1000, res = 300, compression = "lzw")
plot(x, y, type = "b", col = "steelblue")
dev.off()

# Vektorformate
pdf("plot.pdf", width = 8, height = 5, onefile = TRUE)
plot(x, y, type = "b", col = "steelblue")
dev.off()

svg("plot.svg", width = 8, height = 5, pointsize = 11)
plot(x, y, type = "b", col = "steelblue")
dev.off()
Tabelle 5.3: Wichtige Parameter für Grafik-Exportfunktionen in R
Parameter Bedeutung Gilt für
filename Zielpfad bzw. Dateiname der Ausgabedatei alle Gerätefunktionen
width Breite der Grafik (Raster meist Pixel; Vektor meist Zoll) alle Gerätefunktionen
height Höhe der Grafik (Raster meist Pixel; Vektor meist Zoll) alle Gerätefunktionen
bg Hintergrundfarbe der Grafik häufig (png, jpeg, tiff, pdf, svg)
pointsize Basis-Schriftgröße für Text häufig (pdf, svg, teilweise Rastergeräte)
res Auflösung in DPI Rasterformate (png, jpeg, tiff)
units Einheit von width/height ("px", "in", "cm", "mm") v. a. Rasterformate
quality JPEG-Kompressionsqualität (0-100) jpeg()
compression Kompressionsverfahren ("none", "lzw", "zip", …) tiff()
onefile Mehrere aufeinanderfolgende Plots in eine PDF-Datei schreiben pdf()

Für pdf() ist onefile = TRUE besonders praktisch: Jeder zusätzliche Plot-Befehl erzeugt automatisch eine neue Seite in derselben PDF-Datei.

pdf("mehrseitiger-report.pdf", width = 8, height = 5, onefile = TRUE)
plot(x, y, type = "b")
hist(mtcars$mpg)
boxplot(mpg ~ cyl, data = mtcars)
dev.off()

Für ggplot2-Grafiken ist häufig ggsave() der einfachste Weg:

p <- ggplot(mtcars, aes(wt, mpg)) + geom_point()
ggsave("plot.png", plot = p, width = 8, height = 5, dpi = 200)
ggsave("plot.pdf", plot = p, width = 8, height = 5)
ggsave("plot.svg", plot = p, width = 8, height = 5)

Export in RStudio über die Oberfläche

Neben dem Code-Export können Abbildungen direkt im Plots-Fenster exportiert werden:

  1. Plot im Bereich Plots anzeigen lassen (siehe Abbildung 5.4).
  2. Auf Export klicken (siehe Abbildung 5.4).
  3. Save as Image… oder Save as PDF… wählen (siehe Abbildung 5.5 und Abbildung 5.6).
  4. Dateiname, Größe (Breite/Höhe), Auflösung (DPI) und ggf. Format festlegen (siehe Abbildung 5.5).
  5. Speichern.
Abbildung 5.4: RStudio: Plot-Panel mit geöffnetem Export-Menü.
Abbildung 5.5: RStudio-Dialog „Save as Image…“ mit Optionen für Dateiname, Größe und Auflösung.
Abbildung 5.6: RStudio-Dialog „Save as PDF…“ für den Vektorexport als PDF-Datei.

Hinweis: Welche Formate im UI direkt angeboten werden, hängt von RStudio-Version und Betriebssystem ab. Falls SVG im Dialog nicht verfügbar ist, ist der Export per svg()-Funktion der zuverlässige Weg.

TippTipp

Basisgrafiken sind schnell und robust für erste Datenchecks. Für komplexere Visualisierungen mit konsistentem Stil und schrittweisem Aufbau ist ggplot2 in der Regel besser geeignet.

VorsichtÜbung

Base-R-Auffrischung

  1. Erstellen Sie mit plot ein Streudiagramm für wt und mpg aus mtcars.
  2. Passen Sie Titel, Achsenbeschriftung, Farbe und Punktsymbol an.
  3. Erstellen Sie zusätzlich ein Histogramm für mpg und einen Boxplot mpg ~ cyl.

5.3 ggplot2: Visualisierung mit System

Das Paket ggplot2 implementiert die Idee der Grammar of Graphics Wilkinson, Anand, und Grossman (2005) (vgl. auch Wilkinson (2005)) und wurde von Wickham u. a. (2024) in R umgesetzt (vgl. Wickham (2010)).

Die zentrale Idee lautet: Eine Grafik wird aus klaren Bausteinen zusammengesetzt. Dadurch wird die Erstellung komplexer Darstellungen methodisch nachvollziehbar.

Im Kapitelverlauf werden diese Bausteine in genau der folgenden Reihenfolge aufgebaut:

  1. Daten in Kapitel 5.3.1
  2. Ästhetisches Mapping in Kapitel 5.3.2
  3. Geometrische Objekte in Kapitel 5.3.3
  4. Statistische Transformationen in Kapitel 5.3.4
  5. Skalen in Kapitel 5.3.5
  6. Koordinatensysteme in Kapitel 5.3.6
  7. Facettierung in Kapitel 5.3.7
  8. Theme in Kapitel 5.3.8
  9. Vom Rohplot zur finalen Grafik in Kapitel 5.3.9
  10. Typische Fehlerquellen in Kapitel 5.3.10

5.3.1 Daten (data)

Im Sinne der Grammar of Graphics sind Daten der Ausgangspunkt jeder Abbildung. In ggplot2 werden sie in der Regel im ersten Argument von ggplot() festgelegt.

Eine sichtbare Grafik entsteht in ggplot2 erst dann, wenn zusätzlich mindestens eine Geometrie (geom_*) ergänzt wird.

Für die Arbeit mit ggplot2 ist es hilfreich, sich ein einfaches Datenmodell zu merken:

  • Eine Zeile entspricht einer Beobachtung.
  • Eine Spalte entspricht einer Variable.
  • Variablen werden später über aes(...) auf visuelle Eigenschaften abgebildet.
Tabelle 5.4: Zentrale Variablen aus mpg für dieses Kapitel
Variable Typ Inhalt Typische Rolle im Plot
displ numerisch Hubraum (Liter) x-Achse
hwy numerisch Verbrauch auf Highway (mpg) y-Achse
drv kategorial Antriebsart ("4", "f", "r") Farbe oder Facettierung
class kategorial Fahrzeugklasse Gruppierung, Boxplots, Balken
cty numerisch Verbrauch in der Stadt (mpg) Vergleichsgröße
year numerisch Modelljahr (1999, 2008) Gruppierung / Vergleich

Vor dem ersten Plot lohnt sich ein kurzer Datencheck:

dim(mpg)
[1] 234  11
head(mpg[, c("manufacturer", "model", "displ", "hwy", "drv", "class")])
# A tibble: 6 × 6
  manufacturer model displ   hwy drv   class  
  <chr>        <chr> <dbl> <int> <chr> <chr>  
1 audi         a4      1.8    29 f     compact
2 audi         a4      1.8    29 f     compact
3 audi         a4      2      31 f     compact
4 audi         a4      2      30 f     compact
5 audi         a4      2.8    26 f     compact
6 audi         a4      2.8    26 f     compact
sapply(mpg[, c("displ", "hwy", "drv", "class")], class)
      displ         hwy         drv       class 
  "numeric"   "integer" "character" "character" 
colSums(is.na(mpg[, c("displ", "hwy", "drv", "class")]))
displ   hwy   drv class 
    0     0     0     0 

Damit prüfen Sie, ob

  • die relevanten Variablen vorhanden sind,
  • numerische Größen tatsächlich numerisch kodiert sind,
  • fehlende Werte die Darstellung beeinflussen könnten.

Wichtig für die Praxis: Daten können global oder layer-spezifisch gesetzt werden. Ein einzelner Layer darf also mit einem eigenen Datenausschnitt arbeiten.

ggplot(mpg, aes(displ, hwy)) +
  geom_point(alpha = 0.25, color = "grey40") +
  geom_point(data = subset(mpg, drv == "4"), color = "firebrick", size = 2)

So bleibt der Gesamtkontext sichtbar, während eine Teilgruppe gezielt hervorgehoben wird.

HinweisLink

5.3.2 Ästhetisches Mapping (aes)

Mit aes(...) legen Sie fest, welche Variable welche visuelle Eigenschaft steuert.

Tabelle 5.5: Häufige Ästhetiken in ggplot2
Ästhetik Bedeutung
x, y Position auf x- und y-Achse
color Randfarbe von Punkten/Linien
fill Flächenfarbe (z. B. Balken, Boxplots)
shape Punktsymbol
size Punkt- oder Linienstärke
alpha Transparenz
linetype Linientyp
group Gruppierung (wichtig z. B. für Linien)

Ein einfaches Mapping auf Position und Farbe:

ggplot(mpg, aes(x = displ, y = hwy, color = drv)) +
  geom_point(size = 2)

ggplot2 unterscheidet strikt zwischen Mapping (innerhalb von aes(...)) und festen Werten (außerhalb von aes(...)).

# Farbe durch Datenvariable gesteuert (mit Legende)
ggplot(mpg, aes(displ, hwy, color = class)) +
  geom_point(size = 2)

# Fester Stilwert (ohne Legende)
ggplot(mpg, aes(displ, hwy)) +
  geom_point(size = 2, color = "steelblue")

TippTipp

Merksatz: Innerhalb von aes(...) bedeutet in der Regel: Zuordnung auf Daten. Außerhalb von aes(...) bedeutet in der Regel: fester Darstellungsstil.

Globale und lokale Mappings lassen sich kombinieren:

ggplot(mpg, aes(displ, hwy)) +
  geom_point(aes(color = drv), alpha = 0.7) +
  geom_smooth(method = "lm", se = FALSE, color = "black")
`geom_smooth()` using formula = 'y ~ x'

Hier gelten x und y für beide Layer, während color = drv nur für die Punkte gesetzt wird.

HinweisLink

5.3.3 Geometrische Objekte (geom_*)

Geoms bestimmen, wie Daten sichtbar werden: als Punkte, Linien, Balken, Boxplots usw. Welche Geom geeignet ist, hängt von der Fragestellung und vom Datentyp ab.

In Tabelle 5.6 sind häufige Geoms und ihre zentralen Inputs zusammengefasst.

Tabelle 5.6: Wichtige Geoms in ggplot2 und ihre zentralen Inputs
Geom Typische Inputs
geom_point() x, y (zwei numerische Variablen)
geom_line() x (geordnet), y (numerisch), oft zusätzlich group
geom_bar() kategoriale Variable auf x (Zählung erfolgt automatisch)
geom_col() x (Kategorie), y (bereits aggregierte Werte)
geom_histogram() x (numerisch), optional bins oder binwidth
geom_boxplot() x (Gruppe), y (numerisch)

Scatterplot

ggplot(mpg, aes(displ, hwy, color = drv)) +
  geom_point(alpha = 0.7, size = 2) +
  labs(title = "Scatterplot: hwy in Abhängigkeit von displ")

Ein Scatterplot eignet sich, um Zusammenhänge zwischen zwei numerischen Variablen sichtbar zu machen.

Histogramm

ggplot(mpg, aes(hwy)) +
  geom_histogram(bins = 20, fill = "grey75", color = "white") +
  labs(title = "Histogramm von hwy", x = "Highway mpg", y = "Häufigkeit")

Das Histogramm zeigt die Verteilung einer einzelnen numerischen Variable.

Boxplot

ggplot(mpg, aes(class, hwy)) +
  geom_boxplot(fill = "grey85") +
  labs(title = "Boxplot: hwy nach Fahrzeugklasse", x = "Klasse", y = "Highway mpg")

Hier wird die Verteilung einer numerischen Variable (hwy) zwischen Gruppen (class) verglichen. In Base R wird dieselbe Beziehung häufig als Formel hwy ~ class notiert ("hwy in Abhängigkeit von class").

Balkendiagramm mit geom_bar()

ggplot(mpg, aes(class)) +
  geom_bar(fill = "grey70") +
  labs(title = "Anzahl Fahrzeuge je Klasse", x = "Klasse", y = "Anzahl")

geom_bar() zählt Beobachtungen automatisch.

Balkendiagramm mit voraggregierten Daten (geom_col())

df_drv <- as.data.frame(table(mpg$drv))
colnames(df_drv) <- c("drv", "n")

ggplot(df_drv, aes(drv, n)) +
  geom_col(fill = "steelblue") +
  labs(title = "Anzahl nach Antriebsart", x = "Antrieb", y = "Anzahl")

geom_col() verwendet vorhandene Werte auf der y-Achse und führt keine automatische Zählung durch.

HinweisLink

5.3.4 Statistische Transformationen (stat_*)

Viele Geoms enthalten bereits implizite statistische Transformationen.

Tabelle 5.7: Standard-Statistiken ausgewählter Geoms
Geom Standard-Statistik
geom_histogram() stat_bin()
geom_bar() stat_count()
geom_boxplot() stat_boxplot() (Quartile, Median, Whisker)

Das bedeutet: Ein Plot zeigt oft nicht nur Rohdaten, sondern bereits eine verarbeitete statistische Darstellung.

Beispiel 1: Zählen mit geom_bar() (implizit) vs. stat_count() (explizit)

ggplot(mpg, aes(class)) +
  geom_bar(fill = "grey70") +
  labs(title = "Automatische Zählung mit geom_bar()", x = "Klasse", y = "Anzahl")

ggplot(mpg, aes(class)) +
  stat_count(geom = "bar", fill = "grey70") +
  labs(title = "Dieselbe Zählung explizit mit stat_count()", x = "Klasse", y = "Anzahl")

Beide Varianten erzeugen inhaltlich dasselbe Ergebnis. geom_bar() ist die Kurzform, stat_count() macht die zugrunde liegende Statistik sichtbar.

Beispiel 2: Klassierung mit geom_histogram() (stat_bin())

ggplot(mpg, aes(hwy)) +
  geom_histogram(bins = 10, fill = "grey80", color = "white") +
  labs(title = "Histogramm mit 10 Klassen", x = "Highway mpg", y = "Anzahl")

ggplot(mpg, aes(hwy)) +
  geom_histogram(bins = 30, fill = "grey80", color = "white") +
  labs(title = "Histogramm mit 30 Klassen", x = "Highway mpg", y = "Anzahl")

Hier wird dieselbe Variable unterschiedlich fein klassiert. Die Wahl von bins beeinflusst die visuelle Aussage einer Verteilung deutlich.

Beispiel 3: Boxplot als statistische Verdichtung

ggplot(mpg, aes(class, hwy)) +
  geom_boxplot(fill = "grey85") +
  labs(title = "Boxplot: Statistische Verdichtung pro Klasse", x = "Klasse", y = "Highway mpg")

Ein Boxplot basiert auf Quartilen und Median und komprimiert viele Einzelbeobachtungen zu einer gut vergleichbaren Zusammenfassung.

Ausblick

Dichtekurven (geom_density()) und modellbasierte Trendlinien (geom_smooth()) sind ebenfalls statistische Layer. Sie werden später im Skript inhaltlich vertieft eingeführt.

HinweisLink

5.3.5 Skalen (scale_*)

Skalen steuern die Übersetzung von Datenwerten in visuelle Ausprägungen: Achsen, Farben, Legendenbeschriftungen und Breaks.

Tabelle 5.8: Häufige Scale-Funktionen
Funktion Zweck
scale_x_continuous() Achsenbreaks, Labels, Grenzen der x-Achse
scale_y_continuous() Achsenbreaks, Labels, Grenzen der y-Achse
scale_x_log10() log10-Transformation der x-Achse (nur positive Werte)
scale_y_log10() log10-Transformation der y-Achse (nur positive Werte)
scale_x_discrete() Reihenfolge und Labels einer kategorialen x-Achse steuern
scale_y_discrete() Reihenfolge und Labels einer kategorialen y-Achse steuern
scale_color_brewer() diskrete Farbpaletten
scale_color_manual() frei definierte diskrete Farben
scale_fill_brewer() diskrete Flächenfarben
scale_size_continuous() Größenabbildung für numerische Variablen

Beispiel mit diskreter Farbskala:

ggplot(mpg, aes(displ, hwy, color = drv)) +
  geom_point(size = 2, alpha = 0.8) +
  scale_color_brewer(palette = "Dark2") +
  labs(color = "Antrieb")

Beispiel für Achsensteuerung:

ggplot(mpg, aes(displ, hwy)) +
  geom_point(alpha = 0.7) +
  scale_x_continuous(breaks = seq(1, 7, by = 1)) +
  scale_y_continuous(breaks = seq(10, 45, by = 5))

Achsentransformationen (z. B. Log-Skala)

Neben Breaks und Labels können Skalen auch transformiert werden. Besonders häufig ist die Log-Transformation, z. B. bei stark rechtsschiefen Variablen oder wenn eher relative als absolute Unterschiede interessieren.

ggplot(mpg, aes(displ, hwy)) +
  geom_point(alpha = 0.7) +
  labs(title = "Lineare x-Achse", x = "Hubraum (Liter)", y = "Highway mpg")

ggplot(mpg, aes(displ, hwy)) +
  geom_point(alpha = 0.7) +
  scale_x_log10() +
  labs(title = "Log-transformierte x-Achse (log10)", x = "Hubraum (log10)", y = "Highway mpg")

Wichtig für die Interpretation:

  • Auf einer Log-Skala entsprechen gleiche Abstände gleichen Faktoren (z. B. Verdopplung), nicht gleichen absoluten Differenzen.
  • Eine Log-Transformation ist nur für positive Werte definiert. Bei 0 oder negativen Werten muss zuerst fachlich sinnvoll transformiert oder gefiltert werden.

Neben scale_x_log10() und scale_y_log10() sind auch andere Transformationen möglich, z. B. über scale_x_continuous(trans = "sqrt").

Hinweis: Wenn Sie mit scale_* harte Achsengrenzen setzen, können Daten außerhalb der Grenzen entfernt werden. Für „Zoom“ ohne Datenverlust ist coord_cartesian() meist besser geeignet (siehe Kapitel 5.3.6).

5.3.6 Koordinatensysteme (coord_*)

Standardmäßig nutzt ggplot2 ein kartesisches Koordinatensystem. Über coord_* kann die Darstellung verändert werden, ohne das eigentliche Mapping neu zu definieren.

Ein häufiger Fall ist das visuelle Zoomen:

ggplot(mpg, aes(displ, hwy)) +
  geom_point(alpha = 0.7) +
  coord_cartesian(xlim = c(2, 5), ylim = c(15, 35))

Mit coord_flip() werden x- und y-Achse vertauscht. Das ist bei kategorialen Darstellungen oft lesbarer.

ggplot(mpg, aes(class, hwy)) +
  geom_boxplot(fill = "grey85") +
  coord_flip()

Für Spezialfälle gibt es weitere Koordinatensysteme (z. B. Polarkoordinaten), die hier nicht vertieft werden.

5.3.7 Facettierung (facet_*)

Facettierung teilt eine Grafik in mehrere Teilgrafiken auf. Dadurch lassen sich Gruppen vergleichen, ohne dass sich Punkte, Linien oder Balken gegenseitig überlagern.

Ein-Dimension-Facettierung mit facet_wrap():

ggplot(mpg, aes(displ, hwy)) +
  geom_point(alpha = 0.6, color = "steelblue") +
  facet_wrap(~ drv)

Zwei-Dimension-Facettierung mit facet_grid():

ggplot(mpg, aes(displ, hwy)) +
  geom_point(alpha = 0.6) +
  facet_grid(drv ~ cyl)

Wenn sich Wertebereiche zwischen Panels stark unterscheiden, kann scales = "free" (oder "free_y") sinnvoll sein. Für direkte Vergleiche ist eine gemeinsame Skala jedoch oft vorzuziehen.

5.3.8 Theme (theme)

Während aes(...) und geom_* den Inhalt definieren, steuert theme(...) das visuelle Design: Schrift, Gitterlinien, Legendenposition und viele weitere Elemente.

Ein schneller Einstieg sind die vordefinierten Themes wie theme_minimal(), theme_bw() oder theme_classic().

ggplot(mpg, aes(displ, hwy, color = drv)) +
  geom_point(size = 2, alpha = 0.8) +
  theme_minimal()

Über theme(...) lassen sich Details gezielt anpassen:

Tabelle 5.9: Häufig genutzte Theme-Elemente
Element Bedeutung
legend.position Position der Legende ("right", "bottom", …)
plot.title Formatierung des Titels
plot.subtitle Formatierung des Untertitels
axis.title.x, axis.title.y Formatierung der Achsentitel
panel.grid.major Hauptgitterlinien
panel.grid.minor Nebengitterlinien
ggplot(mpg, aes(displ, hwy, color = drv)) +
  geom_point(size = 2, alpha = 0.8) +
  theme_minimal() +
  theme(
    legend.position = "bottom",
    plot.title = element_text(face = "bold"),
    panel.grid.minor = element_blank()
  ) +
  labs(title = "Beispiel mit angepasstem Theme")

HinweisLink

5.3.9 Vom Rohplot zur finalen Grafik

Nach den Einzelbausteinen folgt nun ein durchgängiger Aufbau in fünf Schritten. Die Schritte orientieren sich an einem typischen Analyseworkflow.

Schritt 1: Rohplot erstellen

p1 <- ggplot(mpg, aes(displ, hwy)) +
  geom_point()

p1

Dies ist die Minimalform: Daten, Mapping und Geometrie.

Schritt 2: Beschriftung ergänzen

p2 <- p1 +
  labs(
    title = "Zusammenhang zwischen Hubraum und Verbrauch",
    subtitle = "Datensatz mpg",
    x = "Hubraum (Liter)",
    y = "Highway mpg"
  )

p2

Beschriftungen sind zentral für die Interpretierbarkeit. Die wichtigsten labs()-Argumente zeigt Tabelle 5.10.

Tabelle 5.10: Häufige Argumente von labs() in ggplot2
Argument Bedeutung
title Haupttitel der Abbildung
subtitle Untertitel, häufig für Datensatz oder Kontext
caption Quellenangabe oder methodische Hinweise
x Beschriftung der x-Achse
y Beschriftung der y-Achse
color Titel der Farb-Legende
fill Titel der Flächen-Farb-Legende
shape Titel der Form-Legende
size Titel der Größen-Legende
linetype Titel der Linientyp-Legende

Schritt 3: Mapping und Layer erweitern

p3 <- ggplot(mpg, aes(displ, hwy, color = drv)) +
  geom_point(alpha = 0.7, size = 2) +
  geom_smooth(method = "lm", se = FALSE, color = "black", linewidth = 1)

p3
`geom_smooth()` using formula = 'y ~ x'

Hier kommen zwei zentrale Ideen zusammen:

  • Mapping über color = drv macht Gruppen sichtbar.
  • Ein zusätzlicher Layer (geom_smooth) verdichtet das Muster zu einer Trenddarstellung.

Schritt 4: Darstellung verfeinern

p4 <- p3 +
  scale_color_brewer(palette = "Dark2") +
  facet_wrap(~ drv) +
  theme_minimal() +
  theme(legend.position = "bottom") +
  labs(color = "Antrieb")

p4
`geom_smooth()` using formula = 'y ~ x'

In diesem Schritt wird aus einer Analysegrafik eine kommunikationsfähige Darstellung.

Schritt 5: Finalisieren und speichern

p_final <- p4 +
  labs(
    title = "hwy und displ nach Antriebsart",
    subtitle = "Facettierte Darstellung mit Trendlinie",
    caption = "Quelle: ggplot2::mpg"
  )

p_final
`geom_smooth()` using formula = 'y ~ x'

Einzelne Grafiken speichern Sie mit ggsave():

ggsave("mpg-scatter-facets.png", plot = p_final, width = 9, height = 5, dpi = 150)
ggsave("mpg-scatter-facets.pdf", plot = p_final, width = 9, height = 5)
ggsave("mpg-scatter-facets.svg", plot = p_final, width = 9, height = 5)

ggsave() erkennt das Ausgabeformat über die Dateiendung. Für Veröffentlichungen und skalierbare Darstellungen sind PDF oder SVG oft die bessere Wahl als reine Pixelgrafiken.

5.3.10 Typische Fehlerquellen

  1. Variablen versehentlich außerhalb von aes(...) gesetzt (kein Mapping, keine Legende).
  2. geom_bar() und geom_col() verwechselt (geom_bar() zählt, geom_col() nutzt vorhandene y-Werte).
  3. Ungeeignete Geom für den Datentyp gewählt (z. B. Histogramm für kategoriale Variablen).
  4. Achsen oder Legenden nicht beschriftet (labs(...) fehlt).
  5. Overplotting bei vielen Punkten nicht adressiert (alpha, Aggregation oder Facets fehlen).
  6. Harte Achsengrenzen über scale_* gesetzt, obwohl eigentlich nur gezoomt werden sollte (coord_cartesian() nutzen).
  7. Zu viele visuelle Kodierungen gleichzeitig (z. B. Farbe, Form, Größe und Facets in einem Plot) und dadurch geringe Lesbarkeit.

Diese Fehler sind normal und treten besonders in der Lernphase häufig auf. Ein schrittweiser Plotaufbau (wie in Kapitel 5.3.9) hilft, Probleme früh zu erkennen.

VorsichtÜbung

ggplot2 Grundlagen und Transfer

  1. Erstellen Sie einen Scatterplot für mpg mit displ auf der x- und hwy auf der y-Achse.
  2. Färben Sie Punkte nach drv.
  3. Ergänzen Sie Titel und Achsenbeschriftungen.
  4. Fügen Sie eine lineare Regressionslinie hinzu.
  5. Erstellen Sie zusätzlich eine Facettierung nach drv.
  6. Erstellen Sie eine Zeitreihe der Radfahrerzahlen der Neutor-Daten (stündlich oder täglich aggregiert).
  7. Visualisieren Sie den Zusammenhang zwischen Temperatur und Radverkehr als Scatterplot.
  8. Ergänzen Sie eine Glättungslinie und interpretieren Sie den Trend.

5.4 Exkurs: lattice, rgl und 3D-Visualisierung

Neben Base R und ggplot2 existieren weitere Grafiksysteme, die Sie in älterem Code oder in Spezialanwendungen weiterhin antreffen können.

5.4.1 lattice

lattice war lange ein wichtiges Grafiksystem in R und wird bis heute in Bestandscode genutzt. Es

  • setzt stark auf Formelnotation,
  • ist besonders für konditionierte Darstellungen (Small Multiples) ausgelegt,
  • eignet sich gut für schnelle facettierte Übersichten.
library(lattice)

xyplot(hwy ~ displ | drv, data = mpg,
       main = "Trellis-Plot mit lattice")

5.4.2 rgl und 3D

rgl ermöglicht interaktive 3D-Grafiken (drehen, zoomen, Perspektive ändern). Das kann in explorativen Phasen hilfreich sein, wenn drei numerische Variablen gemeinsam untersucht werden sollen.

In Berichten ist 3D jedoch mit Vorsicht zu verwenden:

  • 3D-Darstellungen sind oft schwerer zu lesen als gut gestaltete 2D-Plots,
  • interaktive 3D-Renderings sind in Skripten und CI-Pipelines teilweise fehleranfällig (abhängig von Grafik-Backend, Betriebssystem und Ausgabeformat).

Daher wird im Skript standardmäßig eine statische Beispielabbildung gezeigt (siehe Abbildung 5.7). Der interaktive Code bleibt als optionale Vorlage erhalten.

Abbildung 5.7: Beispiel einer 3D-Darstellung mit rgl (statisch eingebettet).
library(rgl)

with(mpg, {
  plot3d(displ, hwy, cty,
         col = as.numeric(as.factor(drv)),
         size = 5,
         xlab = "displ", ylab = "hwy", zlab = "cty")
})

Didaktisch ist meist ein guter 2D-Plot der bessere Standard. 3D ist eher ein ergänzendes Werkzeug für spezielle Fragestellungen.

5.5 Dokumente mit Quarto

Visualisierungen entstehen in der Praxis selten isoliert. Meist werden sie gemeinsam mit Text, Code und Interpretation in einem reproduzierbaren Dokument bereitgestellt. Dafür eignet sich Quarto.

5.5.1 Warum Quarto?

Quarto verbindet

  • Fließtext,
  • ausführbaren Code,
  • Tabellen,
  • Abbildungen,
  • Verweise und Literatur

in einem einzigen, reproduzierbaren Dokument. Dadurch bleibt transparent, welcher Code zu welcher Aussage oder welcher Abbildung geführt hat.

5.5.2 Grundstruktur einer Quarto-Datei

Eine Quarto-Datei (.qmd) besteht typischerweise aus

  1. einem YAML-Kopf (Metadaten und Ausgabeformate),
  2. Markdown-Text,
  3. Code-Chunks.

Beispiel für einen YAML-Kopf mit mehreren Zielformaten:

---
title: "Analyse der Fahrzeugdaten"
author: "Max Mustermann"
format:
  html:
    toc: true
    number-sections: true
  pdf:
    toc: true
    number-sections: true
  docx: default
---

Damit kann dasselbe Dokument als HTML, PDF oder Word-Datei gerendert werden.

5.5.3 Dokumenttypen und Templates

Quarto unterstützt verschiedene Dokumenttypen. Typische Einsatzfälle sind in Tabelle 5.11 zusammengefasst.

Tabelle 5.11: Typische Dokumenttypen in Quarto
Dokumenttyp Typische Formate Einsatz
Bericht / Paper html, pdf, docx Analysen, Hausarbeiten, technische Berichte
Präsentation revealjs, beamer, pptx Vorträge, Seminarpräsentationen
Website website Kurswebseiten, Projektdokumentation
Buch / Skript book Lehrmaterial, längere strukturierte Inhalte

Templates steuern Layout und Erscheinungsbild (z. B. Theme, Schriften, Seitenelemente). In der Praxis arbeiten Sie meist mit

  1. eingebauten Formaten (z. B. html, pdf, revealjs) und
  2. erweiterten Formaten/Templates aus der Quarto-Dokumentation.

5.5.4 Basic Markdown-Syntax

Quarto nutzt Markdown als Textsyntax. Die wichtigsten Elemente zeigt Tabelle 5.12.

Tabelle 5.12: Häufige Markdown-Syntax in Quarto
Syntax Bedeutung
# Überschrift Überschrift Ebene 1
## Unterüberschrift Überschrift Ebene 2
**fett**, *kursiv* Hervorhebung
`code` Inline-Code
- Punkt A Aufzählung
1. Schritt Nummerierte Liste
[Linktext](https://quarto.org) Hyperlink
![Caption](img/datei.png) Abbildung einbinden

5.5.6 Verweise und Literatur (Cross-References und Zitation)

Für größere Dokumente sind konsistente Verweise zentral:

  1. Abbildungen labeln mit #fig-...
  2. Tabellen labeln mit #tbl-...
  3. Abschnitte labeln mit {#sec-...}

Referenziert wird dann im Text z. B. über @fig-rstudio-plot-panel, @tbl-chunkoptions oder @sec-gg-scales.

Für Literaturverweise wird im YAML eine Bibliographie-Datei angegeben und im Text mit Zitationsschlüsseln referenziert:

bibliography:
  - book.bib
  - packages.bib

Beispiel im Fließtext: Die Grammar of Graphics wurde in @Wickham2010 für R operationalisiert.

5.5.7 Code-Chunks und Optionen

Code-Chunks sind ausführbare Codeblöcke in einer .qmd-Datei.

Aufbau eines Code-Chunks (Triple-Backticks)

Code-Chunks werden durch Triple-Backticks begrenzt. Das sind drei Zeichen ` hintereinander:

```{r}
#| eval: false
mean(mpg$hwy)
```

Wichtig: Triple-Backticks sind keine drei einfachen Anführungszeichen (''').

Ein Chunk besteht typischerweise aus:

  1. Öffnungszeile mit Sprache, z. B. ```{r}
  2. optionalen Chunk-Optionen mit #|
  3. dem auszuführenden Code
  4. der Abschlusszeile ```

Wichtige Chunk-Optionen

Tabelle 5.13: Häufige Chunk-Optionen in Quarto
Option Bedeutung
echo Code anzeigen (true, false, fenced)
eval Code ausführen (true) oder nicht (false)
include Chunk komplett ein-/ausblenden
warning Warnungen anzeigen oder unterdrücken
message Paket-/Info-Meldungen anzeigen oder unterdrücken
results Ausgabeformat der Resultate steuern
fig-cap Bildunterschrift setzen
label Chunk-Label setzen (für Referenzen)
fig-width Breite der Abbildung
fig-height Höhe der Abbildung
out-width Ausgabegröße im Dokument (z. B. "80%")
fig-align Ausrichtung der Abbildung (left, center, right)

Beispiel 1: Numerische Ausgabe

```{r}
mean(mpg$hwy)
```
[1] 23.44017

Beispiel 2: Tabellenartige Ausgabe aus einem Chunk

```{r}
head(mpg[, c("manufacturer", "model", "displ", "hwy")], 6)
```
# A tibble: 6 × 4
  manufacturer model displ   hwy
  <chr>        <chr> <dbl> <int>
1 audi         a4      1.8    29
2 audi         a4      1.8    29
3 audi         a4      2      31
4 audi         a4      2      30
5 audi         a4      2.8    26
6 audi         a4      2.8    26

Beispiel 3: Code zeigen, aber nicht ausführen

```{r}
#| eval: false
install.packages("sf")
```

Beispiel 4: Chunk-Syntax sichtbar machen und Ergebnis erzeugen

```{r}
#| label: fig-quarto-beispiel
#| fig-cap: "Scatterplot mit Loess-Glättung"
#| warning: false
#| message: false
#| fig-width: 7
#| fig-height: 4
#| fig-align: center

ggplot(airquality, aes(Temp, Ozone)) +
  geom_point() +
  geom_smooth(method = "loess", se = FALSE)
```
Abbildung 5.8: Scatterplot mit Loess-Glättung

Sie können im Fließtext auf die Abbildung verweisen, z. B. mit @fig-quarto-beispiel.

Zusätzlich sind Inline-Berechnungen im Fließtext möglich. Die Quarto-Syntax lautet `{r} ausdruck`. Die Knitr-Kurzform `r ausdruck` funktioniert ebenfalls, ist aber enginespezifisch.

Beispiel (Syntax in der .qmd-Datei):

Der Datensatz `mpg` enthält `{r} nrow(mpg)` Beobachtungen.

Hinweis: Im Quelltextbeispiel ist die Inline-Auswertung absichtlich escaped, damit die Syntax sichtbar bleibt. Für die tatsächliche Berechnung im Fließtext schreiben Sie {r}.

Gerendertes Ergebnis:

Der Datensatz mpg enthält 234 Beobachtungen.

5.5.8 Arbeiten mit der RStudio-Oberfläche

Quarto lässt sich vollständig über die GUI von RStudio/Posit nutzen. Ein typischer Einstieg sieht so aus:

  1. Menü öffnen: File -> New File -> Quarto Document… (siehe Abbildung 5.9).
  2. Im Dialog Titel und ggf. Autor eintragen und ein Startformat wählen (siehe Abbildung 5.10).
  3. Dialog mit Create bestätigen und die neue Datei als .qmd speichern.
  4. Inhalt schreiben (Markdown + Code-Chunks) und im Source-Editor den Render-Button nutzen (siehe Abbildung 5.11).
  5. Optional im Visual-Editor arbeiten und ebenfalls über Render bauen (siehe Abbildung 5.12).
Abbildung 5.9: RStudio-Menü: Neue Quarto-Datei über File -> New File -> Quarto Document… erstellen.
Abbildung 5.10: RStudio-Dialog zum Erstellen eines Quarto-Dokuments mit Titel, Autor und Formatwahl.
Abbildung 5.11: RStudio Source-Editor mit geöffneter .qmd-Datei und sichtbarem Render-Button.
Abbildung 5.12: RStudio Visual-Editor mit sichtbarem Render-Button für das Quarto-Dokument.

Praktische Hinweise:

  • Im Editor können Sie zwischen Source (Quelltext) und Visual (visueller Markdown-Editor) wechseln.
  • Der Render-Button befindet sich im Editorbereich der geöffneten .qmd-Datei.
  • Nach dem Rendern wird bei HTML typischerweise eine Vorschau in RStudio geöffnet.
  • Für reproduzierbare Abgaben ist es sinnvoll, die .qmd-Datei und alle referenzierten Ressourcen (z. B. img/) gemeinsam im Projekt zu halten.

5.5.9 Rendern von Quarto-Dokumenten

Rendern bedeutet, aus .qmd-Dateien ein Ausgabedokument zu erzeugen.

In RStudio/Posit:

  1. Datei öffnen.
  2. Render klicken.
  3. Zielformat auswählen (falls mehrere konfiguriert sind).

In der Konsole:

quarto render bericht.qmd --to html
quarto render bericht.qmd --to pdf
quarto render bericht.qmd --to docx
quarto render slides.qmd --to revealjs

Für ganze Projekte (z. B. Website oder Book) genügt meist:

quarto render

Hinweis zu PDF: Für --to pdf wird eine LaTeX-Umgebung benötigt.

5.5.10 Typischer Workflow mit Quarto

  1. Dokumentstruktur und YAML festlegen.
  2. Inhalte in Markdown schreiben.
  3. Code-Chunks schrittweise ergänzen.
  4. Abbildungen/Tabellen labeln und im Text referenzieren.
  5. Dokument in ein oder mehrere Zielformate rendern.
  6. Ergebnis fachlich und formal prüfen.
VorsichtÜbung

Quarto in der Praxis

  1. Erstellen Sie eine neue .qmd-Datei mit Titel, Autor und zwei Ausgabeformaten (html, pdf).
  2. Schreiben Sie einen kurzen Einführungstext mit Überschrift, Aufzählung und einem externen Link.
  3. Binden Sie eine externe Abbildung aus dem img-Ordner ein und versehen Sie diese mit Label.
  4. Erstellen Sie einen Chunk mit numerischer Ausgabe und einen Chunk mit einer ggplot2-Abbildung.
  5. Referenzieren Sie die Abbildung im Fließtext.
  6. Rendern Sie das Dokument als HTML und als PDF.