10  Themes und Scales

Dieses Dokument ist ein Nachschlagewerk für die Gestaltung von Grafiken mit ggplot2. Im Mittelpunkt stehen die scale_*()- und theme*()-Funktionen, über die wir Schriften, Achsen, Ticks, Labels, Skalen, Farben, Hintergründe und Legenden ändern können.

HinweisLesehinweise
  • Alle Pakete werden in Kapitel 10.1 mit p_load() geladen. Funktionen aus Zusatzpaketen schreiben wir trotzdem mit Präfix (scales::, ggrepel::, ggthemes::): So ist immer klar, woher eine Funktion stammt, und nach scales::label_ schlägt die Autovervollständigung alle Formatierer vor.
  • Die Basisgrafiken p, p_disk, p_kont und p_titel entstehen in Kapitel 10.1 und werden überall wiederverwendet. Weitere Grafiken werden dort erzeugt, wo sie zum ersten Mal gebraucht werden.
  • Die häufigsten Änderungen zeigt Kapitel 10.3 jeweils im direkten Vergleich zur Standardgrafik.
  • Schnellzugriff: „Wie ändere ich …?“ in Kapitel 10.17, vollständige Argumentlisten in Kapitel 10.15 und Kapitel 10.16.

10.1 Einrichten

Alle Befehle gelten für ggplot2 ab Version 4.0.

library(pacman)
p_load(ggplot2, scales, ggrepel, ggthemes, gapminder)
# Streudiagramm – Ausgangspunkt der meisten Beispiele
p <- ggplot(mpg, aes(displ, hwy)) +
  geom_point() +
  labs(x = "Hubraum (l)", y = "Autobahn (mpg)")

# diskrete Farbe: Antrieb (4 = Allrad, f = Front, r = Heck)
p_disk <- ggplot(mpg, aes(displ, hwy, colour = drv)) +
  geom_point() +
  labs(x = "Hubraum (l)", y = "Autobahn (mpg)", colour = "Antrieb")

# kontinuierliche Farbe: Verbrauch in der Stadt
p_kont <- ggplot(mpg, aes(displ, hwy, colour = cty)) +
  geom_point() +
  labs(x = "Hubraum (l)", y = "Autobahn (mpg)", colour = "Stadt (mpg)")

# vollständig beschrifteter Plot
p_titel <- p_disk +
  labs(
    title    = "Hubraum und Verbrauch",
    subtitle = "234 Fahrzeuge aus dem mpg-Datensatz",
    caption  = "Quelle: ggplot2::mpg (EPA)",
    tag      = "A"
  )

# Übersetzung der Antriebsarten (wird mehrfach genutzt)
antrieb_de <- c("4" = "Allrad", f = "Front", r = "Heck")

10.2 Was ist wofür zuständig?

Eine ggplot-Grafik entsteht aus mehreren Bausteinen. Für jede gewünschte Änderung lohnt zuerst die Frage, welcher Baustein zuständig ist:

Baustein beantwortet die Frage … Funktionen Beispiel
Ästhetik Welche Variable steuert x, y, Farbe, Größe …? aes() aes(displ, hwy, colour = drv)
Skala Wie werden Datenwerte übersetzt: Wertebereich, Breaks, Labels, Farben, Transformation? scale_*(), lims(), expansion() scale_x_log10()
Guide Wie wird eine Skala dargestellt: als Achse oder als Legende? guide_*(), guides() guides(x = guide_axis(angle = 45))
Koordinaten Welcher Ausschnitt, welches Seitenverhältnis, welche Richtung? coord_*() coord_cartesian(xlim = c(2, 4))
Theme Wie sieht alles Nicht-Datenbezogene aus: Schriften, Linien, Flächen, Abstände, Layer-Defaults, Paletten? theme_*(), theme(), theme_sub_*(), element_*() theme(panel.grid.minor = element_blank())
Beschriftung Welche Titel tragen Grafik, Achsen und Legenden? labs() labs(x = "Hubraum (l)")

Faustregel: Was von den Daten abhängt, regelt die Skala – wie etwas aussieht, regelt das Theme. Wo eine Achsenmarke sitzt, bestimmt die Skala (breaks); Farbe und Länge der Tickmarke bestimmt das Theme (axis.ticks, axis.ticks.length); ob kleine Ticks überhaupt gezeichnet werden, bestimmt der Guide (guide_axis(minor.ticks = TRUE)).

10.2.1 Namensschema der Skalen

Alle Skalenfunktionen folgen dem Muster scale_<Ästhetik>_<Typ>(). Welcher Typ passt, hängt von der Art der Daten ab:

Ästhetik kontinuierlich diskret gebinnt Sonderfälle
x, y continuous, log10, sqrt, reverse discrete binned date, datetime, time
colour, fill continuous, gradient, gradient2, gradientn, distiller, viridis_c discrete, hue, brewer, viridis_d, grey, manual, ordinal binned, steps, steps2, stepsn, fermenter, viridis_b identity
alpha, size, linewidth continuous (Größe auch size_area, radius) discrete, manual, ordinal binned identity
shape, linetype – Grundfunktion (scale_shape()), manual binned identity

Wird keine Skala angegeben, ergänzt ggplot2 automatisch die Standardskala (scale_x_continuous(), scale_colour_discrete() …). Eine explizit hinzugefügte Skala ersetzt diese vollständig – Argumente addieren sich also nicht über mehrere scale_x_*()-Aufrufe hinweg.

10.3 Häufige Anpassungen im Vergleich zum Standard

Die folgenden Abschnitte zeigen die Änderungen, die man am häufigsten braucht – jeweils im Vergleich zur unveränderten Grafik:

  • Reiter: Der erste Reiter Standard zeigt die Ausgangsgrafik. Beim Umschalten bleibt die Grafik an derselben Stelle, so sieht man direkt, was sich ändert. Über jeder Grafik steht genau der Code, der die Änderung bewirkt.
  • Raster: Bei den kompletten Themes stehen alle Varianten nebeneinander, das Standard-Theme jeweils oben links.

10.3.1 Komplette Themes

Ein komplettes Theme legt alle Theme-Elemente fest. Wird es zu einem Plot addiert, ersetzt es alle vorherigen Theme-Einstellungen. Deshalb gehört + theme_*() immer vor individuelle + theme(...)-Anpassungen.

Eingebaute Themes

p_gal <- p + facet_wrap(~ year)

p_gal + theme_grey()     + labs(title = "theme_grey() – Standard")
p_gal + theme_bw()       + labs(title = "theme_bw()")
p_gal + theme_linedraw() + labs(title = "theme_linedraw()")
p_gal + theme_light()    + labs(title = "theme_light()")
p_gal + theme_dark()     + labs(title = "theme_dark()")
p_gal + theme_minimal()  + labs(title = "theme_minimal()")
p_gal + theme_classic()  + labs(title = "theme_classic()")
p_gal + theme_void()     + labs(title = "theme_void()")
p_gal + theme_test()     + labs(title = "theme_test()")

Theme Hintergrund Gitter Rahmen / Achsenlinie typischer Einsatz
theme_grey() grau weiß – Standard, explorative Grafiken
theme_bw() weiß grau Rahmen Berichte, Abschlussarbeiten
theme_linedraw() weiß schwarz, dünn Rahmen Druck in Schwarz-Weiß
theme_light() weiß hellgrau hellgrauer Rahmen ruhige Darstellung
theme_dark() dunkelgrau grau – helle Datenfarben
theme_minimal() weiß grau – Präsentationen, Web
theme_classic() weiß – Achsenlinien Fachzeitschriften
theme_void() transparent – – Karten, Diagramme ohne Achsen
theme_test() weiß – Rahmen automatisierte Tests (stabil über Versionen)

Themes aus ggthemes

Erweiterungspakete liefern weitere komplette Themes. Sie werden genauso verwendet:

p_gal + ggthemes::theme_economist()      + labs(title = "theme_economist()")
p_gal + ggthemes::theme_fivethirtyeight() + labs(title = "theme_fivethirtyeight()")
p_gal + ggthemes::theme_tufte()          + labs(title = "theme_tufte()")
p_gal + ggthemes::theme_few()            + labs(title = "theme_few()")
p_gal + ggthemes::theme_solarized()      + labs(title = "theme_solarized()")
p_gal + ggthemes::theme_stata()          + labs(title = "theme_stata()")

theme_fivethirtyeight() blendet die Achsentitel bewusst aus; wer sie braucht, ergänzt + theme(axis.title = element_text()).

Argumente der kompletten Themes

Alle eingebauten theme_*()-Funktionen haben dieselben Argumente:

Gruppe Argument Standard Wirkung
Größen base_size 11 Basisschriftgröße in pt; skaliert alle Texte und Abstände sowie Punkt- und Schriftgröße der Layer
base_line_size base_size / 22 Basisstärke aller Linien in mm
base_rect_size base_size / 22 Basisstärke aller Rahmen in mm
Schriften base_family "" (Systemschrift) Schriftfamilie aller Texte
header_family NULL (wie base_family) Schriftfamilie für Plottitel, Achsentitel, Legendentitel und Tag
Farben ink "black" Vordergrund: Text, Linien, Punkte
paper "white" (theme_void(): transparent) Hintergrund; Panel, Streifen und Gitter werden aus ink und paper gemischt
accent "#3366FF" Akzentfarbe für geom_smooth(), geom_contour(), geom_quantile()

base_size ist der schnellste Weg, eine Grafik für Folien oder Druck anzupassen:

p_disk + theme_grey(base_size = 8)  + labs(title = "base_size = 8")
p_disk + theme_grey()               + labs(title = "base_size = 11 (Standard)")
p_disk + theme_grey(base_size = 14) + labs(title = "base_size = 14")

Mit ink, paper und accent lässt sich ein Plot in einem Schritt umfärben – bis hin zum „Dark Mode“. Die Layer übernehmen die Farben automatisch:

p_lm <- p + geom_smooth(method = "lm", formula = y ~ x)

p_lm + labs(title = "Standard")
p_lm + theme_grey(ink = "navy", paper = "cornsilk", accent = "tomato") +
  labs(title = "ink, paper, accent")
p_lm + theme_bw(ink = "grey85", paper = "grey15", accent = "gold") +
  labs(title = "Dark Mode")

WichtigReihenfolge beachten

Ein komplettes Theme überschreibt alles, was vorher mit theme() gesetzt wurde:

p_disk + theme(legend.position = "bottom") + theme_bw()   # Legende wieder rechts
p_disk + theme_bw() + theme(legend.position = "bottom")   # richtig

10.3.2 Achsenbeschriftung

Eine Achse trägt zwei Arten von Text: den Achsentitel und die Tick-Beschriftungen. Beide sind Textelemente und werden mit element_text() gestaltet.

Text beide Achsen nur x nur y
Achsentitel axis.title axis.title.x axis.title.y
Tick-Beschriftungen axis.text axis.text.x axis.text.y
Eigenschaft Argument von element_text() Werte
Farbe colour Farbname oder Hex-Code
Größe size absolut in pt (12) oder relativ zur Basisgröße (rel(1.2))
Schriftstärke face "plain", "bold", "italic", "bold.italic"
Schriftart family "sans", "serif", "mono" oder eine installierte Schrift
Drehung angle Grad gegen den Uhrzeigersinn; dazu passend hjust, vjust
Ausrichtung hjust, vjust 0 = links/unten, 0.5 = Mitte, 1 = rechts/oben
Abstand margin margin_part(t = 10) usw. (Kapitel 10.4.5)

Der Text der Tick-Beschriftungen (Zahlenformat, Einheiten) ist dagegen Sache der Skala: scale_*(labels = …).

p

p + theme(
  axis.title = element_text(colour = "steelblue"),
  axis.text  = element_text(colour = "firebrick")
)

p + theme(
  axis.title = element_text(size = 14),        # absolut: 14 pt
  axis.text  = element_text(size = rel(1.2))   # relativ: 1,2 × 11 pt
)

p + theme(
  axis.title = element_text(face = "bold"),
  axis.text  = element_text(face = "italic")
)

p + theme(
  axis.title.y = element_text(angle = 0, vjust = 0.5),           # y-Titel waagrecht
  axis.text.x  = element_text(angle = 45, hjust = 1, vjust = 1)  # x-Beschriftung schräg
)

p + theme(
  axis.title.x = element_text(hjust = 1),   # ans rechte Ende
  axis.title.y = element_text(hjust = 1)    # ans obere Ende
)

p + theme(
  axis.title.x = element_text(margin = margin_part(t = 15)),
  axis.title.y = element_text(margin = margin_part(r = 15)),
  axis.text.x  = element_text(margin = margin_part(t = 6))
)

p + theme(
  axis.title = element_text(family = "serif"),
  axis.text  = element_text(family = "mono")
)

p +
  scale_x_continuous(labels = scales::label_number(suffix = " l", decimal.mark = ",")) +
  scale_y_continuous(labels = scales::label_number(suffix = " mpg"))

p + theme_sub_axis(
  title = element_text(face = "bold", colour = "grey20"),
  text  = element_text(colour = "grey40", size = rel(0.9))
)

p + theme(
  axis.title.x = element_blank(),   # Titel samt Platz weg (alternativ labs(x = NULL))
  axis.text.y  = element_blank()
)

10.3.3 Ticks

Bei Ticks wirken drei Bausteine zusammen:

Was soll sich ändern? zuständig Code
Position und Anzahl Skala scale_x_continuous(breaks = …), n.breaks = …
Farbe, Stärke, Linientyp Theme axis.ticks = element_line(…)
Länge und Richtung Theme axis.ticks.length = unit(…); negativ = nach innen
kleine Ticks Guide + Theme guide_axis(minor.ticks = TRUE), axis.minor.ticks.length
Ticks entfernen Theme axis.ticks = element_blank()
Ticks auf allen vier Seiten Skala sec.axis = dup_axis(name = NULL, labels = NULL)
p

p + theme(axis.ticks.length = unit(3, "mm"))

p + theme(axis.ticks.length = unit(-2, "mm"))

p + theme(axis.ticks = element_line(colour = "firebrick", linewidth = 1))

p +
  guides(x = guide_axis(minor.ticks = TRUE),
         y = guide_axis(minor.ticks = TRUE)) +
  theme(axis.ticks.length       = unit(2, "mm"),
        axis.minor.ticks.length = rel(0.5))     # halb so lang wie die großen

p +
  scale_x_continuous(n.breaks = 10) +
  scale_y_continuous(n.breaks = 10)

p +
  scale_x_continuous(breaks = scales::breaks_width(0.5)) +
  scale_y_continuous(breaks = seq(10, 45, by = 5))

p +
  theme_sub_axis_x(ticks = element_line(colour = "firebrick"),
                   ticks.length = unit(3, "mm")) +
  theme_sub_axis_y(ticks = element_blank())

p + theme(
  axis.line  = element_line(colour = "black", linewidth = 0.8),
  axis.ticks = element_line(colour = "black", linewidth = 0.8)
)

p +
  scale_x_continuous(sec.axis = dup_axis(name = NULL, labels = NULL)) +
  scale_y_continuous(sec.axis = dup_axis(name = NULL, labels = NULL)) +
  theme(axis.ticks.length = unit(-2, "mm"))

p + theme(axis.ticks = element_blank())

10.3.4 Logarithmische Skalen

Logarithmische Achsen eignen sich für positive, stark rechtsschiefe Daten, die sich über mehrere Größenordnungen erstrecken – etwa Einkommen, Einwohnerzahlen oder Körpergewichte. Gleiche Abstände auf der Achse entsprechen dann gleichen Faktoren (z. B. ×10) statt gleichen Differenzen. Die Skalentransformation wirkt vor der Statistik (etwa vor geom_smooth()); beschriftet wird die Achse trotzdem in Originaleinheiten.

Schritt Ziel Code
Transformation Basis 10 scale_x_log10(), gleichwertig scale_x_continuous(transform = "log10")
Basis 2 bzw. natürlicher Logarithmus transform = "log2", transform = "log"
Daten mit Nullen oder negativen Werten transform = "pseudo_log"
Breaks an Zehnerpotenzen breaks = scales::breaks_log() (Standard bei log-Skalen)
eigene Werte, z. B. 1-2-5-Reihe breaks = c(500, 1000, 2000, 5000)
Beschriftung normale Zahlen mit Tausenderpunkt labels = scales::label_number(big.mark = ".", decimal.mark = ",")
Potenzschreibweise (10³) labels = scales::label_log()
Ticks logarithmische Zwischenticks guide = guide_axis_logticks()
Alternative nur die Achse transformieren, Statistik auf Originaldaten coord_transform(x = "log10") (Kapitel 10.13)
gapminder_2007 <- subset(gapminder, year == 2007)

p_gdp <- ggplot(gapminder_2007, aes(gdpPercap, lifeExp)) +
  geom_point(alpha = 0.6) +
  labs(x = "BIP pro Kopf (US-$)", y = "Lebenserwartung (Jahre)")
p_gdp

p_gdp + scale_x_log10()

p_gdp + scale_x_log10(labels = scales::label_number(big.mark = ".", decimal.mark = ","))

p_gdp + scale_x_log10(
  breaks = c(500, 1000, 2000, 5000, 10000, 20000, 50000),
  labels = scales::label_number(big.mark = ".", decimal.mark = ",")
)

p_gdp + scale_x_log10(
  labels = scales::label_number(big.mark = ".", decimal.mark = ","),
  guide  = guide_axis_logticks()
)

# Die Gerade wird auf log10(x) angepasst und erscheint als Gerade
p_gdp +
  geom_smooth(method = "lm", formula = y ~ x) +
  scale_x_log10(labels = scales::label_number(big.mark = ".", decimal.mark = ","))

# Die Gerade wird auf x angepasst, erst danach wird die Achse gestaucht
p_gdp +
  geom_smooth(method = "lm", formula = y ~ x) +
  coord_transform(x = "log10")

10.3.5 Beide Achsen logarithmisch

Sind beide Variablen rechtsschief, werden beide Achsen transformiert. Bei sehr großen Wertebereichen ist die Potenzschreibweise oft am übersichtlichsten:

p_log <- ggplot(msleep, aes(bodywt, brainwt)) +
  geom_point(na.rm = TRUE) +
  labs(x = "Körpergewicht (kg)", y = "Gehirngewicht (kg)")

p_log + labs(title = "Standard")
p_log + scale_x_log10() + scale_y_log10() + labs(title = "scale_*_log10()")
p_log +
  scale_x_log10(labels = scales::label_log(), guide = guide_axis_logticks()) +
  scale_y_log10(labels = scales::label_log(), guide = guide_axis_logticks()) +
  labs(title = "label_log() + Log-Ticks")

10.3.6 Gitterlinien

Gitterlinien folgen den Breaks der Skalen: Hauptgitter an breaks, Nebengitter an minor_breaks. Die Endung .x meint die Linien an den x-Breaks – das sind die senkrechten Linien.

Richtung Haupt- und Nebengitter nur Hauptgitter nur Nebengitter
beide panel.grid panel.grid.major panel.grid.minor
senkrecht (an x-Breaks) – panel.grid.major.x panel.grid.minor.x
waagrecht (an y-Breaks) – panel.grid.major.y panel.grid.minor.y

Alle Gitterelemente sind Linien und werden mit element_line() gestaltet oder mit element_blank() entfernt. Wer Gitterlinien an anderen Stellen möchte, ändert nicht das Theme, sondern breaks bzw. minor_breaks der Skala.

p

p + theme(panel.grid.minor = element_blank())

p + theme(
  panel.grid.major.x = element_blank(),
  panel.grid.minor   = element_blank()
)

p + theme(
  panel.grid.major = element_line(colour = "grey50", linewidth = 0.3, linetype = "dashed"),
  panel.grid.minor = element_line(colour = "grey80", linewidth = 0.2, linetype = "dotted")
)

p + theme(
  panel.background = element_rect(fill = "white", colour = "grey50"),
  panel.grid       = element_line(colour = "grey90")
)

p +
  scale_x_continuous(breaks = 2:7, minor_breaks = scales::breaks_width(0.25)) +
  scale_y_continuous(breaks = seq(10, 45, by = 5), minor_breaks = NULL)

p + theme(
  panel.background = element_rect(fill = NA),
  panel.grid       = element_line(colour = "grey60", linewidth = 0.2),
  panel.ontop      = TRUE
)

p + theme_minimal() +
  theme(
    panel.grid.minor = element_blank(),
    panel.grid.major = element_line(colour = "grey85")
  )

p + theme(panel.grid = element_blank())

10.3.7 Überlappende Beschriftungen

Achsenbeschriftungen

Bei vielen oder langen Kategorienamen überlappen die Tick-Beschriftungen. Die Lösungen im Überblick:

Lösung Code Vorteil Nachteil
schräg stellen guides(x = guide_axis(angle = 45)) alle Labels bleiben, wenig Platzbedarf schräg schwerer lesbar
senkrecht stellen guides(x = guide_axis(angle = 90)) auch sehr viele Labels passen Kopf muss gedreht werden
versetzen guides(x = guide_axis(n.dodge = 2)) waagrecht lesbar Zuordnung zum Balken schwieriger
ausdünnen guides(x = guide_axis(check.overlap = TRUE)) ruhiges Bild einzelne Labels fehlen
umbrechen scale_x_discrete(labels = scales::label_wrap(10)) waagrecht lesbar wirkt nur bei Leerzeichen im Text
Achsen tauschen aes(y = …) statt aes(x = …) am besten lesbar, leicht sortierbar Grafik braucht mehr Höhe

guide_axis(angle = …) wählt hjust und vjust selbst; mit element_text(angle = …) im Theme müssen sie von Hand gesetzt werden.

p_hersteller <- ggplot(mpg, aes(manufacturer)) +
  geom_bar() +
  labs(x = "Hersteller", y = "Anzahl")
p_hersteller

p_hersteller + guides(x = guide_axis(angle = 45))

p_hersteller + guides(x = guide_axis(angle = 90))

p_hersteller + guides(x = guide_axis(n.dodge = 2))

p_hersteller + guides(x = guide_axis(check.overlap = TRUE))

ggplot(mpg, aes(y = manufacturer)) +
  geom_bar() +
  labs(x = "Anzahl", y = "Hersteller")

ggplot(mpg, aes(y = reorder(manufacturer, manufacturer, FUN = length))) +
  geom_bar() +
  labs(x = "Anzahl", y = "Hersteller")

10.3.8 Beschriftungen von Datenpunkten

Auch Texte in der Grafik (geom_text(), geom_label()) überlagern sich schnell. Das Paket ggrepel schiebt die Beschriftungen auseinander und verbindet sie bei Bedarf mit einer Linie mit ihrem Punkt.

Lösung Code Vorteil Nachteil
Überlappende weglassen geom_text(check_overlap = TRUE) ohne Zusatzpaket Beschriftungen fehlen
abstoßende Texte ggrepel::geom_text_repel() alles lesbar Position zufällig, seed setzen
abstoßende Labels ggrepel::geom_label_repel() gut lesbar vor Punkten braucht mehr Platz
nur Auswahl beschriften ggrepel::geom_text_repel(data = auswahl) lenkt den Blick Auswahl muss begründet sein

Wichtige Argumente der repel-Funktionen: seed (reproduzierbare Lage), max.overlaps (ab wie vielen Überlappungen ein Label weggelassen wird; Standard 10, Inf zeigt alle), box.padding (Abstand zwischen Labels), min.segment.length (ab welchem Abstand eine Verbindungslinie gezeichnet wird; 0 = immer).

autos <- data.frame(modell = rownames(mtcars), mtcars)

p_autos <- ggplot(autos, aes(wt, mpg, label = modell)) +
  geom_point(colour = "grey50") +
  labs(x = "Gewicht (1000 lbs)", y = "Verbrauch (mpg)")

auswahl <- subset(autos, mpg > 27 | wt > 5)
p_autos + geom_text()

p_autos + geom_text(size = 3, nudge_y = 0.8)

p_autos + geom_text(size = 3, nudge_y = 0.8, check_overlap = TRUE)

p_autos + ggrepel::geom_text_repel(size = 3, max.overlaps = Inf, seed = 1)

p_autos + ggrepel::geom_label_repel(size = 2.5, max.overlaps = Inf, seed = 1)

p_autos +
  geom_point(data = auswahl, colour = "firebrick") +
  ggrepel::geom_text_repel(data = auswahl, colour = "firebrick", size = 3, seed = 1)

p_autos + ggrepel::geom_text_repel(
  size               = 3,
  box.padding        = 0.5,
  min.segment.length = 0,
  segment.colour     = "grey60",
  max.overlaps       = Inf,
  seed               = 1
)

10.4 theme(): Elemente, Vererbung, Kurzformen

theme() hat rund 150 Argumente (vollständige Liste in Kapitel 10.15). Ihre Namen sind aus festen Teilen zusammengesetzt:

Teil mögliche Werte Beispiel
Bereich axis, legend, panel, plot, strip axis
Bestandteil title, text, ticks, line, background, grid, border … axis.text
Richtung (optional) x, y axis.text.x
Seite (optional) bottom, top, left, right axis.text.x.bottom

10.4.1 Elementfunktionen

Jedes Theme-Element wird mit einer Elementfunktion befüllt. Welche Funktion passt, hängt davon ab, was das Element zeichnet:

Funktion zeichnet typische Elemente
element_text() Texte axis.title, axis.text, plot.title, legend.text, strip.text
element_line() Linien axis.line, axis.ticks, panel.grid
element_rect() Flächen und Rahmen panel.background, panel.border, plot.background, legend.key, strip.background
element_blank() nichts – entfernt das Element samt Platzbedarf alle
element_geom() Standardaussehen der Layer geom, geom.point, geom.boxplot … (Kapitel 10.5)

Die drei Zeichenfunktionen teilen sich viele Argumente. Gleiche Eigenschaften stehen in einer Zeile:

Eigenschaft element_text() element_line() element_rect()
Farbe colour colour colour (Rahmen), fill (Fläche)
Stärke face (Schriftschnitt) linewidth linewidth (Rahmen)
Linientyp – linetype linetype (Rahmen)
Größe size – –
Schriftfamilie family – –
Drehung angle – –
Ausrichtung hjust, vjust – –
Abstände margin, lineheight – –
Enden und Ecken – lineend, linejoin linejoin
Pfeilspitzen – arrow, arrow.fill –
Hilfen debug, inherit.blank inherit.blank inherit.blank

Erlaubte Werte:

Argument Werte
colour, fill Farbname ("firebrick"), Hex-Code ("#B22222"); NA = keine Farbe
size Schriftgröße in pt oder rel()
linewidth Linienstärke in mm oder rel()
face "plain", "bold", "italic", "bold.italic"
family "sans", "serif", "mono" oder eine installierte Schrift (Kapitel 10.11)
hjust, vjust 0 = links/unten, 0.5 = Mitte, 1 = rechts/oben
angle Grad, gegen den Uhrzeigersinn
lineheight Faktor für den Zeilenabstand, z. B. 0.9
linetype "solid", "dashed", "dotted", "dotdash", "longdash", "twodash", "blank", Zahl 0–6 oder Hex-Muster wie "44"
lineend "butt", "round", "square"
linejoin "round", "mitre", "bevel"
arrow arrow(length = unit(2, "mm"), type = "closed")
margin margin(), margin_auto(), margin_part() (Kapitel 10.4.5)
debug TRUE zeigt Textbox und Ankerpunkt
inherit.blank TRUE: Element wird leer, wenn ein Elternelement element_blank() ist
p + labs(title = "Standard")
p + labs(title = "element_text()") +
  theme(plot.title = element_text(family = "serif", face = "bold.italic",
                                  colour = "darkblue", size = rel(1.4)))
p + labs(title = "debug = TRUE") +
  theme(axis.text = element_text(debug = TRUE))
p + labs(title = "element_line(): Pfeile") +
  theme(axis.line = element_line(colour = "black", linewidth = 0.6,
                                 arrow = arrow(length = unit(2, "mm"), type = "closed")))
p + labs(title = "element_rect(): Panel") +
  theme(panel.background = element_rect(fill = "aliceblue", colour = "steelblue"))
p + labs(title = "element_rect(): Plot") +
  theme(plot.background = element_rect(fill = "grey95", colour = "grey20", linewidth = 1),
        panel.border    = element_rect(colour = "black", linetype = "dashed"))

panel.background liegt unter den Daten, panel.border über ihnen; die Füllung von panel.border wird deshalb ignoriert.

10.4.2 Vererbung

Theme-Elemente erben ihre Eigenschaften von übergeordneten Elementen. Eine Einstellung an der Wurzel wirkt daher auf viele Elemente, eine Einstellung an einem Blatt nur auf dieses:

text ─┬─ title ─┬─ axis.title ─┬─ axis.title.x ── .x.bottom, .x.top
      │         │              └─ axis.title.y ── .y.left, .y.right
      │         ├─ legend.title
      │         └─ plot.title
      ├─ axis.text ─┬─ axis.text.x ── .x.bottom, .x.top
      │             └─ axis.text.y ── .y.left, .y.right
      ├─ legend.text
      ├─ strip.text ─┬─ strip.text.x ── .x.top, .x.bottom
      │              └─ strip.text.y ── .y.left, .y.right
      └─ plot.subtitle, plot.caption, plot.tag

line ─┬─ axis.line ── axis.line.x ── .x.bottom, .x.top      (analog y)
      ├─ axis.ticks ── axis.ticks.x ── .x.bottom, .x.top    (analog y)
      │     axis.minor.ticks.x.bottom usw. erben vom jeweiligen Major-Tick
      └─ panel.grid ─┬─ panel.grid.major ── .major.x, .major.y
                     └─ panel.grid.minor ── .minor.x, .minor.y

rect ─┬─ plot.background, panel.background, panel.border
      ├─ legend.background, legend.box.background
      │     (legend.key erbt von panel.background)
      └─ strip.background ── strip.background.x, .y

spacing ── axis.ticks.length, legend.key.size, legend.spacing,
           legend.key.spacing, legend.box.spacing, panel.spacing …
margins ── plot.margin, legend.margin, legend.box.margin
p_titel + theme(text = element_text(colour = "firebrick"))
p_titel + theme(
  text       = element_text(colour = "firebrick"),
  axis.text  = element_text(colour = "firebrick"),
  plot.title = element_text(face = "bold", size = rel(1.3))
)

Links bleiben die Tick-Beschriftungen grau: axis.text setzt in den Standard-Themes eine eigene Farbe, und ein Wert auf einer tieferen Ebene gewinnt immer gegen die Wurzel. Welche Werte ein Element nach Auflösung aller Vererbungen tatsächlich hat, zeigt calc_element():

calc_element("axis.text.x.bottom", theme_grey())
<ggplot2::element_text>
 @ family       : chr ""
 @ face         : chr "plain"
 @ italic       : chr NA
 @ fontweight   : num NA
 @ fontwidth    : num NA
 @ colour       : chr "#4D4D4DFF"
 @ size         : num 8.8
 @ hjust        : num 0.5
 @ vjust        : num 1
 @ angle        : num 0
 @ lineheight   : num 0.9
 @ margin       : <ggplot2::margin> num [1:4] 2.2 0 0 0
 @ debug        : logi FALSE
 @ inherit.blank: logi TRUE
p_titel + theme(plot.title = element_text(colour = "firebrick"))
p_titel + (theme_grey() %+replace% theme(plot.title = element_text(colour = "firebrick")))

Rechts hat der Titel seine Größe, Linksbündigkeit und seinen Abstand verloren: Diese Eigenschaften kommen nun von title bzw. text (Standardgröße, zentriert, ohne Rand).

10.4.3 Elemente entfernen: element_blank()

p_titel + labs(title = "Standard")
p_titel + labs(title = "element_blank()") +
  theme(
    panel.grid.minor = element_blank(),
    axis.ticks       = element_blank(),
    legend.title     = element_blank(),
    plot.caption     = element_blank()
  )

10.4.4 Längen: unit() und rel()

Einheit Bedeutung typischer Einsatz
"pt" Punkt (1/72,27 Zoll) Schriftgrößen, Ränder (Standard von margin())
"mm", "cm", "in" absolute Längen Ticklänge, Schlüsselgröße, Panelgröße
"lines" Vielfache der Zeilenhöhe Abstände relativ zur Schrift
"npc" Anteil der verfügbaren Fläche (0–1) Positionen innerhalb des Panels
"null" flexibel, füllt den restlichen Platz Farbleiste über die volle Breite

rel(x) multipliziert den geerbten Wert – bei Texten (size = rel(1.5)) ebenso wie bei Längen, etwa axis.ticks.length.x = rel(2) (doppelt so lang wie axis.ticks.length).

10.4.5 Ränder und Abstände

Funktion Beispiel Ergebnis
margin() margin(t = 5, r = 10, b = 5, l = 10) jede Seite einzeln (Einheit pt)
margin_auto() mit 1 Wert margin_auto(5) alle vier Seiten 5
margin_auto() mit 2 Werten margin_auto(5, 10) oben/unten 5, rechts/links 10
margin_auto() mit 3 Werten margin_auto(5, 10, 15) oben 5, rechts/links 10, unten 15
margin_auto() mit 4 Werten margin_auto(5, 10, 15, 20) oben, rechts, unten, links (wie margin())
margin_part() margin_part(b = 10) nur unten 10; übrige Seiten bleiben, wie sie sind

margin_auto() funktioniert wie margin/padding in CSS. margin_part() setzt nicht angegebene Seiten auf NA – sie werden vom bisherigen Wert übernommen. Damit lässt sich eine Seite ändern, ohne die anderen zu verstellen. Alle drei Funktionen haben das Argument unit = "pt".

p_disk + labs(title = "Standard") +
  theme(plot.background = element_rect(colour = "grey50"))
p_disk + labs(title = "plot.margin") +
  theme(plot.margin     = margin_auto(15, 30),
        plot.background = element_rect(colour = "grey50"))
p_disk + labs(title = "Textränder") +
  theme(plot.title      = element_text(margin = margin_part(b = 15)),
        axis.title.x    = element_text(margin = margin_part(t = 12)),
        axis.title.y    = element_text(margin = margin_part(r = 12)),
        plot.background = element_rect(colour = "grey50"))

Die Wurzelelemente spacing (eine Länge) und margins (ein Rand) steuern alle Abstände bzw. Nicht-Text-Ränder gemeinsam. Standardwert ist jeweils die halbe Basisschriftgröße (5,5 pt bei base_size = 11); abgeleitete Elemente wie axis.ticks.length sind als rel() davon definiert.

p_disk + labs(title = "Standard")
p_disk +
  theme(spacing = unit(3, "mm"), margins = margin_auto(3, unit = "mm")) +
  labs(title = "spacing, margins = 3 mm")

10.4.6 Kurzformen: theme_sub_*()

Die theme_sub_*()-Funktionen setzen das Präfix automatisch. Das spart Tipparbeit und ordnet lange Theme-Definitionen nach Bereichen.

Bereich Funktion setzt Beispiel
Achsen theme_sub_axis() axis.* (alle Achsen) theme_sub_axis(text = element_text(colour = "grey40"))
theme_sub_axis_x(), theme_sub_axis_y() axis.*.x bzw. axis.*.y theme_sub_axis_y(ticks = element_blank())
theme_sub_axis_bottom(), _top(), _left(), _right() axis.*.x.bottom usw., auch minor.ticks theme_sub_axis_bottom(minor.ticks = element_line())
Legende theme_sub_legend() legend.* theme_sub_legend(position = "bottom")
Panel theme_sub_panel() panel.* theme_sub_panel(grid.minor = element_blank())
Plot theme_sub_plot() plot.* theme_sub_plot(title.position = "plot")
Streifen theme_sub_strip() strip.* theme_sub_strip(placement = "outside")

Diese beiden Schreibweisen sind gleichwertig:

# ausgeschrieben
theme(
  axis.title.x.bottom = element_text(colour = "firebrick"),
  axis.text.x.bottom  = element_text(colour = "firebrick"),
  axis.line.x.bottom  = element_line(colour = "firebrick"),
  axis.ticks.x.bottom = element_line(colour = "firebrick")
)

# Kurzform
theme_sub_axis_bottom(
  title = element_text(colour = "firebrick"),
  text  = element_text(colour = "firebrick"),
  line  = element_line(colour = "firebrick"),
  ticks = element_line(colour = "firebrick")
)
rot_text  <- element_text(colour = "firebrick")
rot_linie <- element_line(colour = "firebrick")

p +
  theme_sub_axis_bottom(title = rot_text, text = rot_text,
                        line = rot_linie, ticks = rot_linie) +
  theme_sub_panel(background = element_rect(fill = "grey97"),
                  grid.minor = element_blank())

10.4.7 Panelgröße festlegen

panel.widths und panel.heights legen die Größe der Panels absolut fest – unabhängig von der Gesamtgröße der Grafik. Ein Vektor gilt pro Panel, ein Einzelwert für die gesamte Panelfläche (einschließlich der Abstände zwischen Panels).

p_disk +
  facet_wrap(~ year) +
  theme_sub_panel(widths = unit(c(3, 4.5), "cm"), heights = unit(4, "cm"))

Hinweis

Das Grafikdevice muss groß genug sein (hier fig-width: 5), sonst wird abgeschnitten. Achsen, Titel und Legenden kommen zur Panelgröße hinzu. Wird bei einem Einzelpanel nur eine der beiden Angaben gesetzt, bleibt das Seitenverhältnis erhalten.

10.5 Layer-Defaults und Paletten im Theme

Auch das Standardaussehen der Layer (Punktfarbe, Balkenfüllung, Linienstärke) und die Standardpaletten der Skalen gehören zum Theme. Das zuständige Theme-Element heißt geom und wird mit element_geom() befüllt.

Die Theme-Defaults beschreiben Rollen statt einzelner Eigenschaften: ink ist der Vordergrund, paper der Hintergrund. Bei einem Boxplot ist ink daher die Linienfarbe, bei einem Balken die Füllung (Balken sind „Tinte“).

10.5.1 element_geom()

Gruppe Argument Bedeutung wirkt z. B. auf
Farben ink Vordergrundfarbe Punkte, Linien, Text; Balkenfüllung (gemischt mit paper)
paper Hintergrundfarbe Mischfarben, z. B. das Konfidenzband von geom_smooth()
accent Akzentfarbe geom_smooth(), geom_contour(), geom_quantile()
colour, fill feste Farben ohne Mischung; Vorrang vor ink/paper alle Layer bzw. gezielt einzelne Geoms
Linien linewidth, linetype Linien, die Daten darstellen geom_line(), geom_path(), geom_smooth()
Umrisse borderwidth, bordertype Umrisse geschlossener Flächen geom_bar(), geom_rect(), geom_polygon()
Punkte pointsize, pointshape Punktgröße (mm) und Punktform geom_point()
Text family, fontsize Schriftfamilie und Schriftgröße (pt) geom_text(), geom_label()

In der oberen Reihe steht jeweils der Standard, darunter die Änderung:

p_bar1 <- ggplot(mpg, aes(drv)) + geom_bar()

p_lm   + labs(title = "Standard")
p_bar1 + labs(title = "Standard")
p      + labs(title = "Standard")
p_lm + labs(title = "ink, paper, accent") +
  theme(geom = element_geom(ink = "navy", paper = "cornsilk", accent = "tomato"))
p_bar1 + labs(title = "fill, colour, borderwidth") +
  theme(geom = element_geom(fill = "steelblue", colour = "grey20", borderwidth = 0.3))
p + labs(title = "pointsize, pointshape") +
  theme(geom = element_geom(ink = "darkgreen", pointsize = 2.5, pointshape = 17))

Linien, die Daten zeigen, und Umrisse von Flächen werden getrennt gesteuert:

ggplot(faithful, aes(waiting)) +
  geom_histogram(bins = 30, colour = "black") +
  geom_freqpoly(bins = 30) +
  theme(geom = element_geom(
    borderwidth = 0.2, bordertype = "dashed",   # Umrisse der Balken
    linewidth   = 1.5, linetype   = "solid"     # Linie des Häufigkeitspolygons
  ))

10.5.2 Einzelne Geom-Typen gezielt einstellen

Für einen bestimmten Geom-Typ wird der Funktionsname in Punktschreibweise verwendet: geom_point() → geom.point, geom_boxplot() → geom.boxplot.

ggplot(mpg, aes(class, hwy)) +
  geom_boxplot(outliers = FALSE) +
  geom_jitter(width = 0.2, height = 0, size = 0.7) +
  theme(
    geom.point   = element_geom(colour = "dodgerblue"),
    geom.boxplot = element_geom(fill = "grey95", colour = "grey40")
  )

10.5.3 Theme-Werte im Layer nutzen: from_theme()

from_theme() greift innerhalb von aes() auf die Felder von element_geom() zu – auch in Ausdrücken:

ggplot(mpg, aes(drv, hwy)) +
  geom_boxplot(aes(colour = from_theme(accent))) +
  theme(geom = element_geom(accent = "tomato", paper = "cornsilk"))
p + aes(colour = from_theme(scales::col_darker(accent, 20))) +
  theme_grey(accent = "forestgreen")

10.5.4 Wo stelle ich das Aussehen der Layer ein?

ein Plot alle Plots der Sitzung
ein Layer geom_point(colour = "blue") update_theme(geom.point = element_geom(colour = "blue"))
alle Layer + theme(geom = element_geom(ink = "blue")) update_theme(geom = element_geom(ink = "blue")) oder set_theme(theme_grey(ink = "blue"))

10.6 Standardpaletten im Theme

Die Theme-Einstellungen folgen dem Muster palette.<Ästhetik>.<discrete|continuous> (gebinnte Skalen nutzen die kontinuierliche Palette). Sie greifen immer dann, wenn eine Skala palette = NULL hat – das ist bei den Standardskalen der Fall. Erlaubt sind Farbvektoren, Palettennamen und Palettenfunktionen aus scales.

p_disk + theme(palette.colour.discrete = "Okabe-Ito")
p_kont + theme(palette.colour.continuous = c("#FEE0D2", "#FC9272", "#A50F15"))
ggplot(mpg, aes(displ, hwy, shape = drv)) +
  geom_point() +
  theme(palette.shape.discrete = c("circle", "triangle open", "square"))

Art des Werts Beispiel
Palettenname theme(palette.colour.discrete = "Okabe-Ito"), theme(palette.colour.continuous = "viridis")
Farbvektor theme(palette.colour.continuous = c("#FEE0D2", "#A50F15"))
Palettenfunktion theme(palette.colour.discrete = scales::pal_brewer(palette = "Dark2")), theme(palette.fill.continuous = scales::pal_viridis())
eigene, benannte Palette scales::set_palette("hausfarben", c("#003C71", "#E87722", "#6CACE4")), danach theme(palette.colour.discrete = "hausfarben")

Alle bekannten Namen liefert scales::palette_names(). Rangfolge: scale_*(palette = …) im Plot schlägt die Theme-Palette.

10.7 Skalen: scale_*()

10.7.1 Gemeinsame Argumente

Zweck Argument Bedeutung
Titel und Darstellung name Titel der Achse bzw. Legende; NULL entfernt ihn; auch eine Funktion ist erlaubt
guide Darstellung: guide_axis(), guide_legend(), guide_colourbar() … oder "none"
position Achsenlage: "bottom"/"top" bzw. "left"/"right"
Marken und Labels breaks Hauptmarken: NULL, Vektor oder Funktion der Grenzen (z. B. scales::breaks_width(2))
minor_breaks Nebenmarken (Nebengitter, kleine Ticks); eine Funktion kann Grenzen und Hauptmarken erhalten
n.breaks gewünschte Anzahl Hauptmarken (Richtwert)
labels Beschriftung: NULL, Vektor (am besten benannt oder zusammen mit breaks) oder Funktion (z. B. scales::label_number())
Wertebereich limits Wertebereich; NA = automatisch. Werte außerhalb werden entfernt (siehe oob)
expand Luft um den Datenbereich: expansion(mult = , add = )
oob Werte außerhalb von limits: scales::censor (Standard, wird NA), scales::squish (auf Grenze setzen), scales::oob_keep (behalten)
na.value Ersatzwert für fehlende Werte
Übersetzung transform Transformation, z. B. "log10", "sqrt", "reverse" oder scales::transform_*()
palette Palette (Farbskalen und diskrete Positionsskalen)
aesthetics Ästhetiken, für die die Skala gilt, z. B. c("colour", "fill")
Zweitachse sec.axis sec_axis() oder dup_axis()

10.7.2 Kontinuierliche Positionsskalen

scale_x_continuous(), scale_y_continuous() sowie die Kurzformen scale_*_log10(), scale_*_sqrt(), scale_*_reverse().

Breaks und Labels

Breaks lassen sich als feste Werte oder als Funktion angeben. Funktionen erhalten die Grenzen (bei Positionsskalen nach der Expansion):

p + labs(title = "Standard")
p + scale_x_continuous(breaks = 2:7, minor_breaks = NULL) +
  labs(title = "breaks = 2:7")
p + scale_x_continuous(breaks = c(2, 4, 6), labels = c("zwei", "vier", "sechs")) +
  labs(title = "labels als Vektor")
p + scale_y_continuous(n.breaks = 10) +
  labs(title = "n.breaks = 10")
p + scale_x_continuous(breaks = scales::breaks_pretty(n = 3)) +
  labs(title = "breaks_pretty(n = 3)")
p + scale_x_continuous(
  breaks       = \(lim) seq(ceiling(lim[1]), floor(lim[2]), by = 1),
  minor_breaks = scales::breaks_width(0.25)
) +
  labs(title = "eigene Funktion")

Grenzen: Skala oder Koordinatensystem?

Methode Code Daten außerhalb Statistik (z. B. Regression)
Grenzen der Skala scale_x_continuous(limits = c(2, 4)), xlim(2, 4), lims(x = c(2, 4)) werden entfernt (mit Warnung) nur aus den verbleibenden Daten
Zoom im Koordinatensystem coord_cartesian(xlim = c(2, 4)) bleiben erhalten, werden abgeschnitten aus allen Daten
Bereich erweitern expand_limits(x = 0) bleiben erhalten unverändert
p_lm + labs(title = "Standard")
p_lm + scale_x_continuous(limits = c(2, 4)) + labs(title = "Skala: limits")
Warning: Removed 93 rows containing non-finite outside the scale range
(`stat_smooth()`).
Warning: Removed 93 rows containing missing values or values outside the scale range
(`geom_point()`).
p_lm + coord_cartesian(xlim = c(2, 4)) + labs(title = "Koordinaten: xlim")

p + scale_y_continuous(limits = c(0, NA)) + labs(title = "limits = c(0, NA)")
p + expand_limits(x = 0, y = 0) + labs(title = "expand_limits()")
p + lims(x = c(1, 8), y = c(10, 50)) + labs(title = "lims()")

Luft an den Rändern: expand

Standard sind 5 % pro Seite bei kontinuierlichen und 0,6 Einheiten bei diskreten Skalen. expansion(mult = c(unten, oben), add = c(unten, oben)) setzt relative bzw. absolute Werte; coord_*(expand = ) akzeptiert einen benannten logischen Vektor für die Seiten top, right, bottom, left.

p_bar1 + labs(title = "Standard")
p_bar1 + scale_y_continuous(expand = expansion(mult = c(0, 0.05))) +
  labs(title = "expansion(mult = c(0, 0.05))")
p_bar1 + coord_cartesian(expand = c(bottom = FALSE)) +
  labs(title = "coord: expand = c(bottom = FALSE)")

Werte außerhalb der Grenzen: oob

p_kont + labs(title = "Standard")
p_kont + scale_colour_continuous(limits = c(10, 25)) +
  labs(title = "oob = censor")
p_kont + scale_colour_continuous(limits = c(10, 25), oob = scales::squish) +
  labs(title = "oob = squish")

Mit censor werden Werte außerhalb zu NA (grau, siehe na.value), mit squish erhalten sie die Farbe der nächstgelegenen Grenze.

Transformationen

Bei einer Skalentransformation werden die Daten vor der Statistik transformiert; die Achse wird trotzdem in Originaleinheiten beschriftet. Logarithmische Achsen zeigt Kapitel 10.3.4 ausführlich.

Gruppe eingebaute Namen bzw. Funktionen
Logarithmen "log10", "log2", "log", "log1p", "pseudo_log"; mit Parameter: scales::transform_pseudo_log(sigma = 1)
Potenzen und Wurzeln "sqrt", "reciprocal", "exp", "modulus"; mit Parameter: scales::transform_boxcox(p = 2)
Wahrscheinlichkeiten "logit", "probit", "probability", "asn", "atanh"
Richtung "reverse"
Zeit "date", "time", "hms"
Kombination, eigene "identity", scales::transform_compose("log10", "reverse"), scales::new_transform()
p + labs(title = "Standard")
p + scale_y_reverse() + labs(title = "scale_y_reverse()")
p + scale_x_sqrt(breaks = c(2, 3, 5, 7)) + labs(title = "scale_x_sqrt()")

Achsenposition und Zweitachsen

sec_axis() rechnet die Hauptachse mit einer streng monotonen Funktion um; dup_axis() spiegelt sie.

p + scale_x_continuous(position = "top") +
  scale_y_continuous(position = "right") +
  labs(title = "position")
p + scale_y_continuous(
  name     = "Autobahn (mpg)",
  sec.axis = sec_axis(transform = ~ 235.215 / ., name = "l/100 km",
                      breaks = c(6, 8, 10, 12, 15, 20))
) +
  labs(title = "sec_axis()")

10.7.3 Diskrete Positionsskalen

scale_x_discrete() und scale_y_discrete() steuern kategoriale Achsen.

Zweck Argument Bedeutung
Stufen limits erlaubte Stufen und ihre Reihenfolge (nicht aufgeführte Stufen werden entfernt)
drop ungenutzte Faktorstufen weglassen (Standard TRUE)
na.translate NA als eigene Kategorie zeigen
Beschriftung breaks welche Stufen beschriftet werden; benannte breaks liefern die Labels mit
labels wie sie beschriftet werden; am besten als benannter Vektor oder Funktion
minor_breaks numerische Nebenmarken, z. B. zwischen den Stufen
sec.axis Zweitachse mit dup_axis()
Lage palette Positionen der Stufen, z. B. Lücken zwischen Gruppen
continuous.limits fester kontinuierlicher Anzeigebereich
p_klasse <- ggplot(mpg, aes(class)) + geom_bar()

p_klasse + labs(title = "Standard")
p_klasse +
  scale_x_discrete(
    limits = c("compact", "midsize", "suv", "pickup"),
    labels = c(compact = "Kompakt", midsize = "Mittel", suv = "SUV", pickup = "Pickup")
  ) +
  labs(title = "limits + benannte labels")
Warning: Removed 51 rows containing non-finite outside the scale range
(`stat_count()`).
p_klasse +
  scale_x_discrete(labels = toupper, guide = guide_axis(n.dodge = 2)) +
  labs(title = "labels als Funktion")

Die Reihenfolge der Stufen lässt sich alternativ im Datensatz festlegen (factor(x, levels = …), forcats::fct_reorder(), reorder()).

Benannte breaks liefern die Labels gleich mit – so können Breaks und Labels nicht versehentlich auseinanderlaufen. Mit palette lassen sich Stufen auf beliebige Positionen legen:

ggplot(mpg, aes(drv, hwy)) +
  geom_boxplot() +
  scale_x_discrete(name = "Antrieb", breaks = c(Allrad = "4", Front = "f", Heck = "r"))
ggplot(ToothGrowth, aes(interaction(dose, supp, sep = "\n"), len)) +
  geom_boxplot() +
  scale_x_discrete(name = NULL, palette = scales::pal_manual(c(1:3, 5:7)))

continuous.limits fixiert den Anzeigebereich, etwa damit Balken in freien Facetten gleich breit bleiben:

p_frei <- ggplot(mpg, aes(class)) +
  geom_bar() +
  facet_wrap(~ drv, ncol = 1, scales = "free_x") +
  theme(axis.text.x = element_text(size = rel(0.6)))

p_frei + labs(title = "Standard")
p_frei + scale_x_discrete(continuous.limits = c(1, 5)) +
  labs(title = "continuous.limits = c(1, 5)")

minor_breaks bei diskreten Achsen eignen sich als Trennlinien zwischen Kategorien:

ggplot(mpg, aes(drv, hwy)) +
  geom_jitter(width = 0.25, height = 0, size = 0.8) +
  scale_x_discrete(
    minor_breaks = scales::breaks_width(1, offset = 0.5),
    guide = guide_axis(minor.ticks = TRUE)
  ) +
  theme_sub_panel(grid.major.x = element_blank(),
                  grid.minor.x = element_line(colour = "grey60")) +
  theme_sub_axis_bottom(ticks = element_blank(), minor.ticks = element_line())

Eine diskrete Zweitachse kann z. B. Fallzahlen anzeigen:

ggplot(mpg, aes(class, hwy)) +
  geom_boxplot() +
  scale_x_discrete(
    sec.axis = dup_axis(
      name   = NULL,
      breaks = seq_along(unique(mpg$class)),
      labels = paste0("n = ", table(mpg$class))
    )
  )

10.7.4 Datum und Zeit

scale_*_date(), scale_*_datetime() und scale_*_time() haben zusätzlich:

Argument Bedeutung Beispiel
date_breaks Abstand der Hauptmarken als Text "1 month", "2 years", "6 hours"
date_minor_breaks Abstand der Nebenmarken "3 months"
date_labels Format als strftime-Code "%d.%m.%Y", "%b %Y"
breaks alternativ als Funktion scales::breaks_width("3 months")
labels alternativ als Funktion scales::label_date_short()
Einheit Code Ausgabe
Jahr %Y / %y 2026 / 26
Monat %m / %B / %b 09 / September / Sep
Tag %d 25
Wochentag %A / %a Freitag / Fr
Uhrzeit %H:%M / %H:%M:%S 14:30 / 14:30:05
p_zeit <- ggplot(economics, aes(date, unemploy)) + geom_line()

p_zeit + labs(title = "Standard")
p_zeit +
  scale_x_date(date_breaks = "10 years", date_labels = "%Y") +
  labs(title = "date_breaks + date_labels")
p_zeit +
  scale_x_date(
    limits = as.Date(c("2000-01-01", "2010-12-31")),
    date_breaks = "2 years", date_minor_breaks = "6 months",
    labels = scales::label_date_short()
  ) +
  labs(title = "label_date_short()")
Warning: Removed 442 rows containing missing values or values outside the scale range
(`geom_line()`).

Monats- und Wochentagsnamen folgen der Locale der R-Sitzung. Unabhängig davon setzt locale in scales::label_date() die Sprache (benötigt das Paket stringi):

p_zeit + scale_x_date(
  limits      = as.Date(c("2008-01-01", "2009-12-31")),
  date_breaks = "6 months",
  labels      = scales::label_date("%b %Y", locale = "de")
)
Warning: Removed 550 rows containing missing values or values outside the scale range
(`geom_line()`).

10.7.5 Beschriftungen formatieren: scales::label_*()

Alle label_*()-Funktionen liefern eine Funktion, die an labels = übergeben wird. Man kann sie auch direkt auf Zahlen anwenden und so das Ergebnis testen:

de_zahl <- scales::label_number(big.mark = ".", decimal.mark = ",")
de_zahl(c(1234.5, 1e6))
[1] "1.234"     "1.000.000"
scales::label_percent(accuracy = 0.1, decimal.mark = ",", suffix = " %")(c(0.123, 0.5))
[1] "12,3 %" "50,0 %"
scales::label_currency(prefix = "", suffix = " €", big.mark = ".", decimal.mark = ",")(c(1234, 99.5))
[1] "1.234,00 €" "99,50 €"   
scales::label_number(scale_cut = scales::cut_short_scale())(c(1500, 2e6, 3e9))
[1] "2K" "2M" "3B"
scales::label_scientific()(c(1e5, 0.00012))
[1] "1.0e+05" "1.2e-04"
scales::label_pvalue()(c(0.0001, 0.034, 0.5))
[1] "<0.001" "0.034"  "0.500" 
scales::label_wrap(10)("ein sehr langer Kategorienname")
[1] "ein sehr\nlanger\nKategorienname"
Gruppe Funktion Ergebnis (Beispiel) wichtige Argumente
Zahlen label_number() 1234.5 → „1.234,5“ accuracy, scale, prefix, suffix, big.mark, decimal.mark, scale_cut
label_comma() 1234567 → „1,234,567“ wie label_number()
label_percent() 0.123 → „12,3 %“ accuracy, scale (Standard 100), suffix
label_currency() 1234 → „1.234 €“ prefix, suffix, big.mark, decimal.mark
label_scientific() 100000 → „1e+05“ digits
label_log() 1000 → 10³ base, digits
label_pvalue() 0.0001 → „<0.001“ accuracy, prefix
label_bytes() 1e6 → „1 MB“ units
Datum label_date() „25.09.2026“ format, locale
label_date_short() nur geänderte Teile, mehrzeilig format
Text label_wrap() Zeilenumbruch nach width Zeichen width
label_dictionary() „f“ → „Front“ dictionary
label_parse(), label_math() mathematische Ausdrücke (plotmath) –
p_zeit + scale_y_continuous(
  name   = "Arbeitslose",
  labels = scales::label_number(scale = 1000, big.mark = ".", decimal.mark = ",")
)
ggplot(mpg, aes(factor(cyl), fill = drv)) +
  geom_bar(position = "fill") +
  scale_y_continuous(name = "Anteil", labels = scales::label_percent(suffix = " %")) +
  labs(x = "Zylinder")

ggplot(mpg, aes(drv, hwy)) +
  geom_boxplot() +
  scale_x_discrete(name = "Antrieb", labels = scales::label_dictionary(antrieb_de))

TippDeutsches Zahlenformat für die ganze Sitzung

scales::number_options(decimal.mark = ",", big.mark = ".") setzt die Voreinstellungen von label_number() und verwandten Formatierern für alle folgenden Aufrufe.

10.7.6 Farbskalen

Die Farbskalen lassen sich nach zwei Fragen ordnen: Welche Art von Daten? (Spalten) und Welche Palettenfamilie? (Zeilen).

Palettenfamilie diskret kontinuierlich gebinnt wichtige Argumente
Standard (Theme-Palette) _discrete() _continuous() _binned() palette, na.value
Farbkreis _hue() – – h, c, l, h.start, direction
ColorBrewer _brewer() _distiller() _fermenter() palette (z. B. "Set1", "Dark2", "Blues"), direction
viridis _viridis_d() _viridis_c() _viridis_b() option ("viridis", "magma", "plasma", "cividis" …), begin, end, direction
Verlauf zwischen 2 Farben – _gradient() _steps() low, high
divergierender Verlauf – _gradient2() _steps2() low, mid, high, midpoint
Verlauf über n Farben – _gradientn() _stepsn() colours, values
Graustufen _grey() – – start, end
geordnete Faktoren _ordinal() – – wie viridis
eigene Farben _manual() – – values (am besten benannt), breaks, labels
Farben stehen in den Daten _identity() _identity() – guide

Alle Funktionen beginnen mit scale_colour bzw. scale_fill (auch in amerikanischer Schreibweise scale_color), z. B. scale_fill_viridis_c().

Diskrete Daten

p_disk + labs(title = "Standard")
p_disk + scale_colour_brewer(palette = "Dark2") + labs(title = "brewer()")
p_disk + scale_colour_viridis_d(option = "plasma", end = 0.85) +
  labs(title = "viridis_d()")
p_disk + scale_colour_grey(start = 0.1, end = 0.7) + labs(title = "grey()")
p_disk +
  scale_colour_manual(
    name   = "Antrieb",
    values = c("4" = "#1B9E77", f = "#D95F02", r = "#7570B3"),
    labels = antrieb_de
  ) +
  labs(title = "manual()")
p_disk + scale_colour_discrete(palette = "Okabe-Ito") +
  labs(title = 'discrete(palette = "Okabe-Ito")')

Kontinuierliche und gebinnte Daten

p_raster <- ggplot(faithfuld, aes(waiting, eruptions, fill = density)) +
  geom_raster()

p_raster + labs(title = "Standard")
p_raster + scale_fill_gradient(low = "white", high = "darkred") +
  labs(title = "gradient()")
p_raster + scale_fill_gradient2(low = "steelblue", mid = "white", high = "firebrick",
                                midpoint = 0.02) +
  labs(title = "gradient2()")
p_raster + scale_fill_distiller(palette = "Spectral") +
  labs(title = "distiller()")
p_raster + scale_fill_viridis_c(option = "magma") +
  labs(title = "viridis_c()")
p_raster + scale_fill_continuous(palette = c("#EFEDF5", "#BCBDDC", "#54278F")) +
  labs(title = "continuous(palette = )")

p_raster + scale_fill_binned() +
  labs(title = "binned()")
p_raster + scale_fill_steps(low = "white", high = "darkgreen", n.breaks = 6) +
  labs(title = "steps()")
p_raster + scale_fill_fermenter(palette = "YlGnBu", direction = 1) +
  labs(title = "fermenter()")

10.7.7 Größe, Form, Linientyp, Transparenz

ggplot(mpg, aes(displ, hwy, size = cyl)) +
  geom_point(alpha = 0.4) +
  scale_size_area(max_size = 4, breaks = c(4, 6, 8)) +
  labs(title = "scale_size_area()")
ggplot(mpg, aes(displ, hwy, shape = drv)) +
  geom_point() +
  scale_shape_manual(values = c("4" = 16, f = 1, r = 17), labels = antrieb_de) +
  labs(title = "scale_shape_manual()")
ggplot(economics_long, aes(date, value01, linetype = variable)) +
  geom_line(linewidth = 0.3) +
  scale_linetype_manual(values = c("solid", "dashed", "dotted", "dotdash", "longdash")) +
  labs(title = "scale_linetype_manual()")
ggplot(mpg, aes(displ, hwy, alpha = cty)) +
  geom_point() +
  scale_alpha(range = c(0.1, 1)) +
  labs(title = "scale_alpha()")

Ästhetik Skala wichtige Argumente Hinweis
Größe scale_size() range = c(min, max) skaliert die Fläche
scale_size_area() max_size bildet 0 auf Größe 0 ab
scale_radius() range skaliert den Radius
Linienstärke scale_linewidth() range = c(0.2, 2)
Form scale_shape_manual() values Zahlen 0–25 (21–25 zusätzlich mit fill) oder Namen wie "circle", "circle open", "square", "triangle", "diamond", "plus", "cross"
Linientyp scale_linetype_manual() values Werte wie bei element_line(linetype = )
Transparenz scale_alpha() range = c(0.1, 1)

10.7.8 Eine Skala für mehrere Ästhetiken

Mit aesthetics gilt eine Skala für colour und fill zugleich – und es entsteht nur eine Legende:

ggplot(mpg, aes(hwy, colour = drv, fill = drv)) +
  geom_density(alpha = 0.3) +
  scale_colour_brewer(palette = "Dark2", aesthetics = c("colour", "fill"),
                      name = "Antrieb", labels = antrieb_de)

10.8 Titel und Beschriftungen: labs()

Gruppe Argument Bedeutung
Grafik title, subtitle, caption Titel, Untertitel, Fußnote
tag Kennzeichnung, z. B. „A“ für Teilabbildungen
Achsen und Legenden x, y, colour, fill, size, shape … Titel der jeweiligen Achse bzw. Legende; NULL entfernt ihn samt Platz, "" lässt den Platz frei; auch eine Funktion ist erlaubt
dictionary benannter Vektor: Variablenname → Beschriftung
Barrierefreiheit alt, alt_insight Alternativtext
p_titel

Kurzformen: xlab(), ylab(), ggtitle(label, subtitle).

10.8.1 Labels aus Wörterbuch und Variablenattributen

Beschriftungen können an Variablen statt an Ästhetiken hängen – praktisch mit einem Codebuch oder mit gelabelten Daten (etwa aus haven, labelled oder sjlabelled):

woerterbuch <- c(displ = "Hubraum (l)", hwy = "Autobahn (mpg)",
                 cty = "Stadt (mpg)", drv = "Antrieb")
ggplot(mpg, aes(displ, hwy, colour = cty)) +
  geom_point() +
  labs(dictionary = woerterbuch, title = "labs(dictionary = )")
mpg_attr <- mpg
attr(mpg_attr$displ, "label") <- "Hubraum (l)"
attr(mpg_attr$hwy,   "label") <- "Autobahn (mpg)"
ggplot(mpg_attr, aes(displ, hwy)) +
  geom_point() +
  labs(title = 'Attribut "label"')

Beide Wege greifen nur bei reinen Variablennamen in aes() – bei aes(sqrt(displ)) nicht. Welche Angabe gewinnt, regelt eine feste Rangfolge (von niedrig nach hoch):

  1. der Ausdruck in aes() (z. B. displ)
  2. labs(dictionary = )
  3. das Attribut label der Variablen
  4. labs(x = )
  5. scale_*(name = )
  6. guide_*(title = )

10.8.2 Funktionen als Labels

labs(), Skalennamen und Guide-Titel akzeptieren Funktionen, die das Label der darunterliegenden Ebene umformen:

ggplot(mpg, aes(displ, hwy, colour = drv)) +
  geom_point() +
  labs(x = toupper, y = \(x) paste0(x, " [mpg]"), colour = "Antrieb")

10.8.3 Ausrichtung von Titel, Untertitel, Caption und Tag

Einstellung Werte
plot.title.position "panel" (Standard, bündig mit dem Panel) oder "plot" (bündig mit der ganzen Grafik); gilt auch für den Untertitel
plot.caption.position "panel" oder "plot"
plot.tag.position "topleft", "top", "topright", "left", "right", "bottomleft", "bottom", "bottomright" oder c(x, y)
plot.tag.location "margin", "plot" oder "panel"
p_titel + theme(plot.title.position = "plot", plot.caption.position = "plot")
p_titel + theme_sub_plot(
  title        = element_text(hjust = 0.5, face = "bold"),
  subtitle     = element_text(hjust = 0.5, colour = "grey40"),
  caption      = element_text(face = "italic"),
  tag.position = "topright",
  tag.location = "panel"
)

10.8.4 Mehrzeilige Labels und Formeln

p + labs(
  x     = "Hubraum\n(Liter)",
  y     = expression(Verbrauch ~ (mi %.% gal^{-1})),
  title = expression(paste("Modell: ", hat(y) == beta[0] + beta[1] * x))
)

Die Syntax für mathematische Ausdrücke steht in ?plotmath. Für Achsen-Beschriftungen (Ticks) gibt es scales::label_parse() und scales::label_math().

10.9 Achsen: weitere Einstellungen

Achsentitel und Tick-Beschriftungen, Ticks, logarithmische Achsen und überlappende Beschriftungen stehen in Kapitel 10.3. Hier folgen die übrigen Einstellungen.

Achsen sind Guides. Drei Stellen wirken zusammen:

zuständig regelt Funktionen und Elemente
Skala Lage und Anzahl der Marken, Beschriftungstext, Achsenseite breaks, minor_breaks, n.breaks, labels, position
Theme Aussehen: Schrift, Farbe, Ticklänge, Achsenlinie axis.title, axis.text, axis.ticks, axis.ticks.length, axis.line, axis.minor.ticks.* bzw. theme_sub_axis*()
Guide Darstellungslogik: Drehung, Staffelung, kleine Ticks, gekürzte Linie guide_axis(), guide_axis_logticks()
Zweck Argument von guide_axis() Bedeutung
Beschriftung angle Drehwinkel; wählt hjust/vjust automatisch
n.dodge Beschriftungen auf mehrere Zeilen verteilen
check.overlap überlappende Beschriftungen weglassen (Rand und Mitte haben Vorrang)
Ticks und Linie minor.ticks kleine Ticks an den minor_breaks zeichnen
cap Achsenlinie kürzen: "none", "both", "upper", "lower"
Titel und Lage title Achsentitel
position "top", "bottom", "left", "right"
order Reihenfolge bei mehreren Guides an derselben Seite
Aussehen theme lokales Theme nur für diese Achse

Ein Guide wird entweder in der Skala (scale_x_continuous(guide = guide_axis(...))) oder über guides(x = guide_axis(...)) gesetzt.

10.9.1 Achsenlinien

p + theme_classic() + labs(title = "theme_classic()")
p + theme_classic() +
  guides(x = guide_axis(cap = "both"), y = guide_axis(cap = "both")) +
  labs(title = 'cap = "both"')
p + theme_sub_axis(line = element_line(colour = "grey30")) +
  theme_sub_axis_y(line = element_line(arrow = arrow(length = unit(2, "mm")))) +
  labs(title = "Achsenlinie mit Pfeil")

10.9.2 Eigenes Theme für eine einzelne Achse

Das lokale Theme im Guide überlagert das Plot-Theme nur für diese Achse. Hier erscheint zusätzlich eine Achsenlinie, weil theme_classic() sie zeichnet:

p + guides(x = guide_axis(theme = theme_classic(ink = "firebrick")))

10.9.3 Achsen in Facetten

axes steuert, wo Achsen gezeichnet werden ("margins", "all_x", "all_y", "all"), axis.labels, wo sie beschriftet werden ("all", "margins", "all_x", "all_y"):

p_disk + facet_wrap(~ year, axes = "all", axis.labels = "margins")

10.10 Legenden

Legenden sind Guides für alle Nicht-Positionsskalen. Das Theme (legend.* bzw. theme_sub_legend()) regelt Aussehen und Lage aller Legenden; guide_*(theme = ) gestaltet eine einzelne Legende abweichend.

Skalentyp Guide wichtige Argumente
diskret (Farbe, Form, Größe …) guide_legend() title, position, direction, nrow, ncol, reverse, override.aes, theme, order
kontinuierliche Farbe guide_colourbar() display ("raster", "rectangles", "gradient"), nbin, angle, draw.ulim, draw.llim, reverse, theme
gebinnte Farbe guide_coloursteps() even.steps, show.limits, angle, theme
gebinnte Größe usw. guide_bins() show.limits, angle, direction, theme
beliebiges Grafikobjekt guide_custom() grob, width, height
keine Legende "none" –

10.10.1 Position

Zweck Einstellung Werte
Lage legend.position "right" (Standard), "left", "top", "bottom", "inside", "none"
legend.position.inside c(x, y) zwischen 0 und 1 (nur bei "inside")
legend.location "panel" (Standard) oder "plot"
Ausrichtung legend.justification (.top, .bottom, .left, .right, .inside) "center", "top", "left" … oder c(x, y)
legend.direction "vertical" oder "horizontal"
mehrere Legenden legend.box "vertical" oder "horizontal"
legend.box.just Ausrichtung der Legenden zueinander
p_disk + labs(title = "Standard")
p_disk + theme(legend.position = "bottom") + labs(title = "bottom")
p_disk + theme(
  legend.position             = "inside",
  legend.position.inside      = c(0.98, 0.98),
  legend.justification.inside = c(1, 1),
  legend.background           = element_rect(colour = "grey50")
) + labs(title = "inside")
p_disk + theme_sub_legend(
  position          = "top",
  location          = "plot",
  justification.top = "left",
  title.position    = "top"
) + labs(title = "oben links")

Über guide_*(position = ) lassen sich Legenden auf verschiedene Seiten verteilen:

ggplot(mpg, aes(displ, hwy, colour = drv, size = cyl)) +
  geom_point(alpha = 0.6) +
  guides(colour = guide_legend(position = "inside"),
         size   = guide_legend(position = "bottom")) +
  theme(legend.position.inside      = c(0.98, 0.98),
        legend.justification.inside = c(1, 1))

10.10.2 Titel und Beschriftungen

p_disk + theme_sub_legend(
  title = element_text(face = "bold", colour = "steelblue"),
  text  = element_text(size = rel(0.8), family = "mono")
)
p_disk + theme_sub_legend(
  title.position = "top",
  text.position  = "left",
  text           = element_text(hjust = 1)
)

10.10.3 Schlüssel

Einstellung Bedeutung
legend.key Hintergrund der Schlüssel (erbt von panel.background)
legend.key.size, .width, .height Größe der Schlüssel
legend.key.spacing, .x, .y Abstand zwischen den Schlüsseln
legend.key.justification Ausrichtung, wenn die Beschriftung höher ist als der Schlüssel
legend.byrow Füllrichtung bei mehreren Spalten
p_disk + theme_sub_legend(
  key         = element_rect(fill = "white", colour = "grey70"),
  key.size    = unit(7, "mm"),
  key.spacing = unit(1.5, "mm")
)
p_disk +
  scale_colour_discrete(labels = c("4" = "Allrad-\nantrieb", f = "Front-\nantrieb",
                                   r = "Heck-\nantrieb")) +
  theme_sub_legend(key.justification = "top", key.spacing.y = unit(2, "mm"))

10.10.4 Reihenfolge, Anordnung, Symbole

reverse = TRUE bringt die Legende in die Reihenfolge der Stapel; override.aes ändert nur die Symbole in der Legende:

p_balken <- ggplot(mpg, aes(factor(cyl), fill = drv)) +
  geom_bar() +
  labs(x = "Zylinder")

p_balken + guides(fill = guide_legend(reverse = TRUE)) +
  labs(title = "reverse = TRUE")
p_disk + guides(colour = guide_legend(
  position = "bottom", nrow = 1,
  override.aes = list(size = 4, shape = 15)
)) +
  labs(title = "nrow + override.aes")

10.10.5 Farbleisten und gebinnte Legenden

Die Länge einer Farbleiste beträgt standardmäßig das Fünffache der Schlüsselgröße. Über das Guide-Theme wird sie direkt gesetzt; mit der Einheit "null" füllt sie die verfügbare Breite:

p_kont + guides(colour = guide_colourbar(
  theme = theme(legend.key.height = unit(3, "cm"), legend.key.width = unit(3, "mm"))
)) +
  labs(title = "lange Leiste")
p_kont + guides(colour = guide_colourbar(
  position = "bottom",
  theme = theme_sub_legend(
    key.width      = unit(1, "null"),
    title.position = "top",
    frame          = element_rect(colour = "black"),
    ticks          = element_line(colour = "white")
  )
)) +
  labs(title = "unten, volle Breite")
p_kont + scale_colour_binned(guide = guide_coloursteps(show.limits = TRUE)) +
  labs(title = "coloursteps")

10.10.6 Legenden entfernen oder zusammenführen

Ziel Code
eine bestimmte Legende entfernen guides(colour = "none")
alle Legenden entfernen theme(legend.position = "none")
einen Layer aus der Legende nehmen geom_point(show.legend = FALSE)
Legendentitel entfernen labs(colour = NULL)

Legenden verschiedener Ästhetiken werden zusammengeführt, wenn Titel und Beschriftungen übereinstimmen:

ggplot(mpg, aes(displ, hwy, colour = drv, shape = drv)) +
  geom_point() +
  labs(colour = "Antrieb", title = "unterschiedliche Titel")
ggplot(mpg, aes(displ, hwy, colour = drv, shape = drv)) +
  geom_point() +
  labs(colour = "Antrieb", shape = "Antrieb", title = "gleiche Titel")

10.11 Schriften

10.11.1 Wo Schriften festgelegt werden

Ebene Code
alle Texte theme_grey(base_family = "serif") oder theme(text = element_text(family = "serif"))
Überschriften theme_grey(header_family = "serif")
einzelne Elemente theme(axis.text = element_text(family = "mono"))
Texte in Layern geom_text(family = "serif") oder theme(geom = element_geom(family = "serif"))

Die Namen "sans", "serif" und "mono" funktionieren immer; welche Schrift dahintersteht, entscheiden Betriebssystem und Grafikdevice (unter Linux: fontconfig). Als Schnitt (face) sind nur "plain", "bold", "italic" und "bold.italic" vorgesehen.

p_titel + theme_grey(base_family = "serif")
p_titel + theme_grey(base_family = "sans", header_family = "serif") +
  theme(axis.text = element_text(family = "mono"))

10.11.2 Schriftgrößen: pt im Theme, mm im Layer

Theme-Texte werden in pt angegeben, geom_text() und geom_label() in mm. Umrechnung: size = 10 / .pt entspricht 10 pt. Einfacher geht es mit size.unit = "pt" oder über das Theme:

ggplot(mtcars, aes(wt, mpg, label = rownames(mtcars))) +
  geom_text(size = 7, size.unit = "pt", family = "serif", check_overlap = TRUE) +
  labs(title = 'geom_text(size.unit = "pt")')
ggplot(mtcars, aes(wt, mpg, label = rownames(mtcars))) +
  geom_text(check_overlap = TRUE) +
  theme(geom = element_geom(family = "mono", fontsize = 7)) +
  labs(title = "element_geom(fontsize = 7)")

10.11.3 Systemschriften und Google Fonts

Devices, die auf systemfonts aufbauen (ragg für PNG, svglite für SVG), finden alle installierten Schriften unter ihrem Familiennamen:

# installierte Schriftfamilien auflisten
sort(unique(systemfonts::system_fonts()$family))

# Schrift bei Bedarf herunterladen und für die Sitzung registrieren
# (Internetzugang nötig)
systemfonts::require_font("Fira Sans")
systemfonts::require_font("Fira Sans Condensed")

p_titel + theme_minimal(base_family = "Fira Sans",
                        header_family = "Fira Sans Condensed")

# weitere Schnitte (z. B. Light) als eigene Familie registrieren
systemfonts::register_variant(
  name = "Fira Sans Light", family = "Fira Sans", weight = "light"
)
p_titel + theme(text = element_text(family = "Fira Sans Light"))
HinweisDevices in Quarto und beim Speichern
  • HTML: ragg als Device, z. B. im Projekt-YAML:

    knitr:
      opts_chunk:
        dev: "ragg_png"
  • ggsave(): PNG, JPEG und TIFF laufen automatisch über ragg, sofern installiert.

  • PDF: ggsave("abb.pdf", device = cairo_pdf) bzw. dev: "cairo_pdf" bettet Systemschriften ein; alternativ das Paket showtext.

10.12 Hintergründe, Panels, Facetten

Gitterlinien stehen in Kapitel 10.3.6.

10.12.1 Hintergrund der ganzen Grafik und Außenrand

p_titel
p_titel + theme(
  plot.background   = element_rect(fill = "#F5F1E8", colour = NA),
  panel.background  = element_rect(fill = "white"),
  legend.background = element_rect(fill = NA),
  plot.margin       = margin_auto(12)
)

legend.key erbt von panel.background, deshalb sind die Legendenschlüssel rechts ebenfalls weiß.

10.12.2 Facettenstreifen

p +
  facet_grid(drv ~ year, labeller = labeller(drv = antrieb_de)) +
  theme_sub_strip(
    background   = element_rect(fill = "grey25"),
    text         = element_text(colour = "white", face = "bold"),
    text.y.right = element_text(angle = 0),
    placement    = "outside"
  ) +
  theme_sub_panel(spacing = unit(3, "mm"), border = element_rect(colour = "grey25"))

Bereich Einstellung Bedeutung
Streifen strip.background, .x, .y Hintergrund der Streifen
strip.text, .x, .y, .x.top, .x.bottom, .y.left, .y.right Streifentext; Drehungen gehören an die seitenspezifischen Elemente
strip.placement "inside" oder "outside" (Streifen außerhalb der Achse)
strip.clip Streifen auf ihren Hintergrund zuschneiden ("on"/"off")
strip.switch.pad.grid, strip.switch.pad.wrap Abstand zwischen Achse und Streifen bei switch
Panels panel.spacing, .x, .y Abstand zwischen den Panels

Die Streifentexte selbst kommen aus dem labeller der Facette: labeller(drv = antrieb_de) übersetzt über einen benannten Vektor, label_both zeigt „Variable: Wert“, label_wrap_gen(10) bricht lange Texte um.

facet_wrap(dir = ) kennt acht Füllrichtungen als Zwei-Buchstaben-Codes: Der erste Buchstabe gibt die Füllrichtung an, beide zusammen die Startecke.

Startecke zeilenweise spaltenweise
links oben "lt" (Standard) "tl"
links unten "lb" "bl"
rechts oben "rt" "tr"
rechts unten "rb" "br"
p + facet_wrap(~ class, ncol = 4, dir = "tl")

10.12.3 Seitenverhältnis

p + labs(title = "Standard")
p + theme(aspect.ratio = 1) + labs(title = "theme(aspect.ratio = 1)")
p + coord_cartesian(ratio = 0.15) + labs(title = "coord_cartesian(ratio = 0.15)")

Einstellung legt fest Beispiel
theme(aspect.ratio = ) Form des Panels (Höhe / Breite) aspect.ratio = 1 = quadratisch
coord_cartesian(ratio = ) Verhältnis der Dateneinheiten: eine Einheit auf y ist ratio-mal so lang wie eine Einheit auf x ratio = 1 = gleiche Einheiten
coord_fixed(), coord_equal() Kurzformen für coord_cartesian(ratio = ) coord_fixed(ratio = 1)

10.13 Koordinatensysteme

Zweck Argument von coord_cartesian() Bedeutung
Ausschnitt xlim, ylim Zoom ohne Datenverlust
expand Luft an den Rändern; auch pro Seite, z. B. c(bottom = FALSE)
Darstellung reverse "none", "x", "y", "xy" – funktioniert auch bei diskreten Achsen
ratio Seitenverhältnis der Dateneinheiten
clip "on" (Standard) oder "off": darf außerhalb des Panels gezeichnet werden?
Sonstiges default Meldung beim Ersetzen unterdrücken
p + coord_cartesian(reverse = "xy") + labs(title = 'reverse = "xy"')
p + coord_transform(x = "log10", y = "log10") + labs(title = "coord_transform()")
ggplot(mpg, aes(hwy, drv)) + geom_boxplot() + labs(title = "horizontal: aes getauscht")

  • coord_transform() transformiert nach der Statistik: Gerade Linien können gekrümmt erscheinen. Eine Skalentransformation (scale_x_log10()) wirkt dagegen vor der Statistik (Vergleich in Kapitel 10.3.4).
  • Horizontale Balken oder Boxplots entstehen, indem man x und y in aes() vertauscht; die Layer erkennen die Orientierung selbst.
  • Für Polarkoordinaten gibt es coord_radial() mit inner.radius, start, end und reverse = "theta".

Mit clip = "off" lassen sich Anmerkungen außerhalb des Panels platzieren (Außenrand vergrößern):

p +
  annotate("text", x = 7.4, y = 44, label = "Ausreißer?", hjust = 0, size = 3) +
  coord_cartesian(xlim = c(1.6, 7), clip = "off") +
  theme(plot.margin = margin_part(r = 45))

10.14 Globale Einstellungen und eigene Themes

10.14.1 Theme für alle folgenden Plots

Funktion Wirkung
set_theme(theme_bw()) komplettes Theme setzen; Rückgabewert ist das bisherige Theme
update_theme(...) einzelne Elemente verschmelzen – auch Paletten und Layer-Defaults
replace_theme(...) einzelne Elemente vollständig ersetzen
get_theme() aktuelles Theme abfragen
reset_theme_settings() zurück auf die Werkseinstellung
alt <- set_theme(theme_bw(base_size = 12, base_family = "serif"))

update_theme(
  panel.grid.minor        = element_blank(),
  palette.colour.discrete = "Okabe-Ito",
  geom                    = element_geom(pointsize = 2)
)

replace_theme(plot.title = element_text(face = "bold", hjust = 0))

get_theme()              # aktuelles Theme
set_theme(alt)           # vorheriges Theme wiederherstellen
reset_theme_settings()   # zurück auf Werkseinstellung

In einem Quarto-Projekt gehört ein solcher Aufruf in einen Setup-Chunk oder in ein gemeinsames R-Skript, das jedes Kapitel per source() lädt.

10.14.2 Eigenes Theme als Funktion

Bewährte Regeln: Das eigene Theme ist eine Funktion, baut auf einem kompletten Theme auf und ergänzt es mit + theme() (nicht per $<-). So bleibt es vollständig, auch wenn ggplot2 neue Theme-Elemente einführt.

theme_skript <- function(base_size = 11, base_family = "", ...) {
  theme_minimal(base_size = base_size, base_family = base_family, ...) +
    theme(
      plot.title.position      = "plot",
      plot.title               = element_text(face = "bold"),
      plot.caption             = element_text(colour = "grey40", hjust = 0),
      panel.grid.minor         = element_blank(),
      axis.line                = element_line(colour = "grey30"),
      legend.position          = "top",
      legend.location          = "plot",
      legend.justification.top = "left",
      palette.colour.discrete  = "Okabe-Ito",
      palette.fill.discrete    = "Okabe-Ito"
    )
}

p_titel + theme_skript()

Über ... werden header_family, ink, paper und accent an theme_minimal() durchgereicht, z. B. theme_skript(ink = "navy").

Auch Teil-Themes lassen sich als Bausteine speichern – eine Liste darf Theme- und andere Komponenten kombinieren:

balken_einstellungen <- function() {
  list(
    theme(panel.grid.major.x = element_blank()),
    coord_cartesian(expand = c(bottom = FALSE))
  )
}

ggplot(mpg, aes(class)) + geom_bar() + balken_einstellungen()

10.15 Kurzreferenz: theme()-Argumente

Die Endungen .x/.y und .x.bottom, .x.top, .y.left, .y.right sind jeweils in Klammern zusammengefasst; für Polarkoordinaten gibt es zusätzlich .theta und .r. Typ text, line, rect steht für element_text(), element_line(), element_rect().

Element Typ Bedeutung
text text Basis aller Texte
title text Basis aller Titel (erbt von text)
line line Basis aller Linien
rect rect Basis aller Flächen und Rahmen
spacing unit Basis aller Abstände
margins margin Basis aller Nicht-Text-Ränder
geom element_geom() Standardaussehen der Layer; geom.<name> für einzelne Geoms
palette.<Ästhetik>.<discrete/continuous> Palette Standardpaletten
aspect.ratio Zahl Seitenverhältnis des Panels (Höhe / Breite)
point, polygon Element nur für Erweiterungspakete

Kurzform: theme_sub_axis(), theme_sub_axis_x(), theme_sub_axis_bottom() … (Kapitel 10.4.6)

Element Typ Bedeutung
axis.title (.x, .y, …) text Achsentitel
axis.text (.x, .y, …) text Tick-Beschriftungen
axis.ticks (.x, .y, …) line Tickmarken
axis.ticks.length (.x, .y, …) unit/rel Ticklänge; negativ = nach innen
axis.minor.ticks.x.bottom, .x.top, .y.left, .y.right line kleine Ticks (erben vom Major-Tick)
axis.minor.ticks.length (.x, .y, …) unit/rel Länge kleiner Ticks; rel() relativ zur Major-Länge
axis.line (.x, .y, …) line Achsenlinie

Kurzform: theme_sub_legend()

Element Typ Bedeutung
legend.position Text "right", "left", "top", "bottom", "inside", "none"
legend.position.inside c(x, y) Lage bei "inside"
legend.location Text "panel" oder "plot"
legend.justification (.top, .bottom, .left, .right, .inside) Position Ausrichtung
legend.direction Text "horizontal" oder "vertical"
legend.byrow logisch zeilenweise füllen
legend.title, legend.title.position text / Seite Titel und seine Lage
legend.text, legend.text.position text / Seite Beschriftung und ihre Lage
legend.key rect Hintergrund der Schlüssel
legend.key.size, legend.key.height, legend.key.width unit Schlüsselgröße
legend.key.spacing (.x, .y) unit Abstand zwischen Schlüsseln
legend.key.justification Position Ausrichtung der Schlüssel
legend.frame rect Rahmen um die Farbleiste
legend.ticks, legend.ticks.length line / unit Ticks an Farbleiste und Bins
legend.axis.line line Achsenlinie in guide_bins()
legend.background rect Hintergrund jeder Legende
legend.margin margin Rand um jede Legende
legend.spacing (.x, .y) unit Abstand zwischen Legenden
legend.box, legend.box.just Text Anordnung mehrerer Legenden
legend.box.margin, legend.box.background, legend.box.spacing margin / rect / unit Box um alle Legenden

Kurzform: theme_sub_panel()

Element Typ Bedeutung
panel.background rect Hintergrund unter den Daten
panel.border rect Rahmen über den Daten (fill wird ignoriert)
panel.grid, .major, .minor, .major.x, .major.y, .minor.x, .minor.y line Gitterlinien
panel.ontop logisch Panel über den Daten zeichnen
panel.spacing (.x, .y) unit Abstand zwischen Facetten
panel.widths, panel.heights unit absolute Panelgröße

Kurzform: theme_sub_plot()

Element Typ Bedeutung
plot.title, plot.subtitle, plot.caption, plot.tag text Titel, Untertitel, Fußnote, Kennzeichen
plot.title.position, plot.caption.position Text "panel" oder "plot"
plot.tag.position Text / c(x, y) Lage des Tags
plot.tag.location Text "margin", "plot" oder "panel"
plot.background rect Hintergrund der ganzen Grafik
plot.margin margin Außenrand

Kurzform: theme_sub_strip()

Element Typ Bedeutung
strip.background (.x, .y) rect Hintergrund
strip.text (.x, .y, .x.top, .x.bottom, .y.left, .y.right) text Streifentext
strip.placement Text "inside" oder "outside"
strip.clip Text "on", "off", "inherit"
strip.switch.pad.grid, strip.switch.pad.wrap unit Abstand bei switch

10.16 Kurzreferenz: Skalen und Hilfsfunktionen

10.16.1 Skalen und Guides

Gruppe Bereich Funktionen
Position kontinuierlich scale_x_continuous(), scale_x_log10(), scale_x_sqrt(), scale_x_reverse(), scale_x_binned() (analog y)
diskret scale_x_discrete(), scale_y_discrete()
Zeit scale_x_date(), scale_x_datetime(), scale_x_time() (analog y)
Farbe diskret scale_colour_discrete(), _hue(), _brewer(), _viridis_d(), _grey(), _manual(), _identity(), _ordinal()
kontinuierlich scale_colour_continuous(), _gradient(), _gradient2(), _gradientn(), _distiller(), _viridis_c()
gebinnt scale_colour_binned(), _steps(), _steps2(), _stepsn(), _fermenter(), _viridis_b()
Füllfarbe alle Farbskalen als scale_fill_*()
Weitere Ästhetiken Transparenz scale_alpha(), _continuous(), _discrete(), _binned(), _manual(), _identity(), _ordinal()
Größe scale_size(), scale_size_area(), scale_size_binned(), scale_size_binned_area(), scale_radius(), _manual(), _identity(), _ordinal()
Linienstärke scale_linewidth(), _binned(), _manual(), _identity(), _ordinal()
Form scale_shape(), _binned(), _manual(), _identity()
Linientyp scale_linetype(), _binned(), _manual(), _identity()
Bereich Grenzen lims(), xlim(), ylim(), expand_limits(), expansion()
Zweitachsen sec_axis(), dup_axis()
Guides Achsen guide_axis(), guide_axis_logticks(), guide_axis_stack(), guide_axis_theta()
Legenden guide_legend(), guide_colourbar(), guide_coloursteps(), guide_bins(), guide_custom(), guide_none()
setzen guides()

10.16.2 Hilfsfunktionen aus scales

Zweck Funktionen
Breaks breaks_width(), breaks_pretty(), breaks_extended(), breaks_log(), minor_breaks_width()
Labels label_number(), label_comma(), label_percent(), label_currency(), label_scientific(), label_log(), label_pvalue(), label_date(), label_date_short(), label_wrap(), label_parse(), label_math(), label_dictionary()
Werte außerhalb censor(), squish(), squish_infinite(), oob_keep()
Transformationen transform_log10(), transform_sqrt(), transform_reverse(), transform_pseudo_log(), transform_boxcox(), transform_compose(), new_transform()
Paletten pal_brewer(), pal_viridis(), pal_hue(), pal_grey(), pal_manual(), palette_names(), set_palette()
Farben col_mix(), col_darker(), col_lighter(), alpha(), show_col()

10.17 Wie ändere ich …?

10.17.1 Titel und Achsenbeschriftungen

Aufgabe Code Details
Achsentitel ändern labs(x = "Hubraum (l)") Kapitel 10.8
Achsentitel entfernen (samt Platz) labs(x = NULL) Kapitel 10.8
Titel zentrieren theme(plot.title = element_text(hjust = 0.5)) Kapitel 10.8
Titel bündig mit dem linken Grafikrand theme(plot.title.position = "plot") Kapitel 10.8
Achsentitel fett oder farbig theme(axis.title = element_text(face = "bold", colour = "steelblue")) Kapitel 10.3.2
Tick-Beschriftungen größer theme(axis.text = element_text(size = 12)) Kapitel 10.3.2
y-Achsentitel waagrecht theme(axis.title.y = element_text(angle = 0, vjust = 0.5)) Kapitel 10.3.2
Tick-Beschriftungen drehen guides(x = guide_axis(angle = 45)) Kapitel 10.3.7
Überlappende Achsenbeschriftungen vermeiden guides(x = guide_axis(n.dodge = 2)) oder x und y tauschen Kapitel 10.3.7
Überlappende Punktbeschriftungen vermeiden ggrepel::geom_text_repel(seed = 1) Kapitel 10.3.7

10.17.2 Ticks und Achsen

Aufgabe Code Details
Anzahl der Achsenmarken scale_y_continuous(n.breaks = 8) Kapitel 10.3.3
Achsenmarken in festem Abstand scale_x_continuous(breaks = scales::breaks_width(0.5)) Kapitel 10.3.3
Ticks länger theme(axis.ticks.length = unit(3, "mm")) Kapitel 10.3.3
Ticks nach innen theme(axis.ticks.length = unit(-2, "mm")) Kapitel 10.3.3
Kleine Ticks zeigen guides(x = guide_axis(minor.ticks = TRUE)) Kapitel 10.3.3
Ticks entfernen theme(axis.ticks = element_blank()) Kapitel 10.3.3
Achsenlinie zeichnen theme(axis.line = element_line(colour = "black")) Kapitel 10.9
Zweite y-Achse scale_y_continuous(sec.axis = sec_axis(~ . * 2.54, name = "cm")) Kapitel 10.7

10.17.3 Skalen und Wertebereich

Aufgabe Code Details
Logarithmische Achse scale_y_log10() bzw. scale_y_continuous(transform = "log10") Kapitel 10.3.4
Log-Achse mit normalen Zahlen scale_x_log10(labels = scales::label_number(big.mark = ".", decimal.mark = ",")) Kapitel 10.3.4
Dezimalkomma und Tausenderpunkt scale_y_continuous(labels = scales::label_number(big.mark = ".", decimal.mark = ",")) Kapitel 10.7.5
Prozentachse scale_y_continuous(labels = scales::label_percent(suffix = " %")) Kapitel 10.7.5
y-Achse bei 0, ohne Luft unten scale_y_continuous(limits = c(0, NA), expand = expansion(mult = c(0, 0.05))) Kapitel 10.7
Zoomen ohne Datenverlust coord_cartesian(xlim = c(2, 4)) Kapitel 10.7
Achse umkehren scale_y_reverse() oder coord_cartesian(reverse = "y") Kapitel 10.13

10.17.4 Gitter und Hintergrund

Aufgabe Code Details
Nebengitter entfernen theme(panel.grid.minor = element_blank()) Kapitel 10.3.6
Nur waagrechte Gitterlinien theme(panel.grid.major.x = element_blank(), panel.grid.minor = element_blank()) Kapitel 10.3.6
Gitter gestrichelt theme(panel.grid.major = element_line(linetype = "dashed")) Kapitel 10.3.6
Gitter ganz entfernen theme(panel.grid = element_blank()) Kapitel 10.3.6
Weißer Hintergrund theme_bw() oder theme(panel.background = element_rect(fill = "white")) Kapitel 10.3.1
Rahmen um das Panel theme(panel.border = element_rect(colour = "black")) Kapitel 10.4

10.17.5 Legende

Aufgabe Code Details
Legende unten theme(legend.position = "bottom") Kapitel 10.10
Legende in der Grafik theme(legend.position = "inside", legend.position.inside = c(0.95, 0.95), legend.justification.inside = c(1, 1)) Kapitel 10.10
Legende entfernen guides(colour = "none") bzw. theme(legend.position = "none") Kapitel 10.10
Legendentitel entfernen labs(colour = NULL) Kapitel 10.10
Legendenreihenfolge umkehren guides(fill = guide_legend(reverse = TRUE)) Kapitel 10.10
Größere Legendensymbole guides(colour = guide_legend(override.aes = list(size = 4))) Kapitel 10.10

10.17.6 Farben

Aufgabe Code Details
Eigene Farben scale_colour_manual(values = c(a = "#1B9E77", b = "#D95F02")) Kapitel 10.7.6
Farbfehlsichtigkeit berücksichtigen scale_colour_discrete(palette = "Okabe-Ito") oder scale_colour_viridis_d() Kapitel 10.7.6
Standardpalette für alle Plots update_theme(palette.colour.discrete = "Okabe-Ito") Kapitel 10.5
Farbe aller Punkte, Linien, Balken theme(geom = element_geom(ink = "navy")) Kapitel 10.5
Dunkler Hintergrund theme_bw(ink = "grey85", paper = "grey15") Kapitel 10.3.1

10.17.7 Schriften und Größen

Aufgabe Code Details
Alles größer theme_grey(base_size = 14) Kapitel 10.3.1
Schrift für alles theme_grey(base_family = "serif") Kapitel 10.11
Andere Schrift für Überschriften theme_grey(header_family = "serif") Kapitel 10.11
Textgröße in Layern in pt geom_text(size = 8, size.unit = "pt") Kapitel 10.11

10.17.8 Panel und Layout

Aufgabe Code Details
Panelgröße festlegen theme(panel.widths = unit(8, "cm"), panel.heights = unit(5, "cm")) Kapitel 10.4
Quadratisches Panel theme(aspect.ratio = 1) Kapitel 10.12
Gleiche Einheiten auf x und y coord_cartesian(ratio = 1) bzw. coord_fixed() Kapitel 10.12
Text außerhalb des Panels coord_cartesian(clip = "off") plus theme(plot.margin = margin_part(r = 40)) Kapitel 10.13