8. ggforce

Zooming, Annotationen und Gruppenmarkierung

Author
Zugehörigkeit

Dr. Paul Schmidt

Last updated

13. August 2026

for (pkg in c("tidyverse", "gapminder", "ggforce")) {
  if (!require(pkg, character.only = TRUE)) install.packages(pkg)
}

Das Paket {ggforce} von Thomas Lin Pedersen erweitert ggplot2 um spezialisierte Geoms und Facets, die sich mit Bordmitteln nur schwer umsetzen lassen. Während ggplot2 den Großteil alltäglicher Visualisierungsaufgaben abdeckt, erfordern bestimmte Darstellungen - etwa das Hineinzoomen in einen überfüllten Plotbereich oder das Zeichnen von Formen um Punktgruppen - dedizierte Werkzeuge.

Dieses Kapitel konzentriert sich auf drei besonders nützliche Features von ggforce: das Zoomen in Plotbereiche mit facet_zoom(), das Markieren von Gruppen mit statistischen Ellipsen über geom_mark_ellipse() und das Umranden von Gruppen mit konvexen Hüllen mittels geom_mark_hull(). Diese Werkzeuge sind besonders wertvoll für explorative Analysen und Präsentationen, bei denen man die Aufmerksamkeit auf bestimmte Cluster oder Teilmengen der Daten lenken möchte.

Für die Zoom-Beispiele verwenden wir den gapminder-Datensatz (gefiltert auf 2007) und für die Gruppenmarkierung den klassischen iris-Datensatz, da seine drei gut getrennten Arten die visuellen Unterschiede besonders deutlich machen.

facet_zoom

Streudiagramme realer Daten enthalten oft Bereiche, in denen sich viele Punkte überlagern, während andere Bereiche dünn besiedelt sind. Ein klassisches Beispiel ist das BIP pro Kopf: Eine Handvoll wohlhabender Länder streckt die x-Achse so weit, dass die Unterschiede zwischen einkommensschwachen Ländern unsichtbar werden. facet_zoom() löst dieses Problem, indem sowohl der vollständige Plot als auch ein vergrößerter Ausschnitt nebeneinander angezeigt werden.

Basis-Plot

Man beginnt mit einem Streudiagramm von BIP pro Kopf gegen Lebenserwartung für das Jahr 2007, eingefärbt nach Kontinent. Da BIP-Werte stark rechtsschief verteilt sind, verwendet man eine logarithmische x-Achse, um die Punkte gleichmäßiger zu verteilen.

gap07 <- gapminder::gapminder %>%
  filter(year == 2007)

p_base <- ggplot(gap07, aes(x = gdpPercap, y = lifeExp, color = continent)) +
  geom_point(alpha = 0.7, size = 2) +
  scale_x_log10(labels = scales::label_dollar()) +
  labs(
    x = "BIP pro Kopf (log-Skala)",
    y = "Lebenserwartung (Jahre)",
    color = "Kontinent"
  ) +
  theme_minimal()

p_base

Selbst mit logarithmischer Skalierung ist der Bereich niedriger BIP-Werte (unter $5.000) dicht gedrängt und schwer lesbar. Genau in dieser Situation zeigt facet_zoom() seine Stärke.

Einfacher Zoom

Die einfachste Verwendung gibt ein xlim an, um den interessierenden Bereich zu definieren. Das Ergebnis ist ein Zwei-Panel-Plot: das Original auf einer Seite und die vergrößerte Ansicht auf der anderen.

p_base +
  facet_zoom(xlim = c(100, 5000))

Das Zoom-Panel zeigt nur Länder mit einem BIP pro Kopf zwischen $100 und $5.000, was es deutlich einfacher macht, einzelne Punkte in diesem dichten Bereich zu unterscheiden. Ein schattiertes Rechteck im Übersichtspanel zeigt an, welcher Bereich vergrößert wird.

Gestylter Zoom

Zwei nützliche Parameter steuern das Erscheinungsbild: zoom.size passt die relative Größe des Zoom-Panels an (Werte größer als 1 machen es größer als die Übersicht), und show.area = TRUE hebt den gezoomten Bereich im Übersichtspanel durch ein schattiertes Rechteck hervor.

p_base +
  facet_zoom(
    xlim = c(100, 5000),
    zoom.size = 1.5,
    show.area = TRUE
  )

facet_zoom() akzeptiert auch einen ylim-Parameter für vertikales Zoomen, und beide können kombiniert werden, um in einen rechteckigen Teilbereich zu zoomen. Für die meisten Anwendungsfälle reicht das Zoomen entlang einer einzelnen Achse aus und ist leichter zu interpretieren.

geom_mark_ellipse

Wenn ein Streudiagramm deutliche Cluster enthält, kann es hilfreich sein, jede Gruppe visuell zu umranden. geom_mark_ellipse() zeichnet eine statistische Ellipse (basierend auf der Kovarianzmatrix) um die Punkte jeder Gruppe. Dies ist besonders effektiv für Präsentationen, bei denen man die Gruppentrennung hervorheben möchte.

Einfache Ellipse

Der iris-Datensatz enthält Messungen von Kelch- und Blütenblattdimensionen für drei Arten. Man mappt Species sowohl auf color als auch auf group und fügt Labels über die label-Aesthetic hinzu.

p_iris <- ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width, color = Species)) +
  geom_point(size = 2, alpha = 0.7) +
  theme_minimal()

p_iris +
  geom_mark_ellipse(aes(label = Species, group = Species))

Jede Ellipse umschließt die Punkte einer Art, und ein Label wird außerhalb der Ellipse mit einer Verbindungslinie platziert. Die Ellipsenform spiegelt die bivariate Verteilung jeder Gruppe wider - längliche Ellipsen deuten auf korrelierte Variablen innerhalb dieser Gruppe hin.

Gestylte Ellipse

Mehrere Parameter steuern das Erscheinungsbild. expand fügt Abstand um die Ellipse hinzu, con.type ändert den Verbindungslinienstil (“elbow”, “straight” oder “none”), und die description-Aesthetic fügt ein sekundäres Label unterhalb des Hauptlabels hinzu. Hier ergänzt man die Anzahl der Beobachtungen pro Art als Beschreibung.

iris_desc <- iris %>%
  group_by(Species) %>%
  mutate(desc = glue::glue("n = {n()}")) %>%
  ungroup()

ggplot(iris_desc, aes(x = Sepal.Length, y = Sepal.Width, color = Species)) +
  geom_point(size = 2, alpha = 0.7) +
  geom_mark_ellipse(
    aes(label = Species, group = Species, description = desc),
    expand = unit(3, "mm"),
    con.type = "straight"
  ) +
  theme_minimal()

Die geraden Verbindungslinien wirken aufgeräumter, und die Beschreibungszeile liefert zusätzlichen Kontext, ohne den Plot zu überladen.

geom_mark_hull

Während Ellipsen eine annähernd normale Verteilung voraussetzen, zeichnen konvexe Hüllen die tatsächliche Grenze der Punkte jeder Gruppe nach. Das macht geom_mark_hull() zur besseren Wahl, wenn Gruppen unregelmäßige Formen haben oder wenn man die präzise Ausdehnung der Daten hervorheben möchte, statt einer idealisierten statistischen Form.

Einfache Hülle

Die Syntax entspricht der von geom_mark_ellipse():

p_iris +
  geom_mark_hull(aes(label = Species, group = Species))

Die Hülle umschließt eng die äußersten Punkte jeder Gruppe. Im Vergleich zu den Ellipsen folgt die Hülle der tatsächlichen Datengrenze - man beachte, wie die Setosa-Hülle kompakter ist, weil die Punkte eng beieinander liegen.

Gestylte Hülle

Die Parameter expand und radius steuern den Abstand und die Eckenrundung. Erhöhen beider Werte erzeugt eine glattere, optisch ansprechendere Form.

p_iris +
  geom_mark_hull(
    aes(label = Species, group = Species),
    expand = unit(3, "mm"),
    radius = unit(3, "mm")
  )

Die abgerundeten Ecken lassen die Hüllen weniger kantig und polierter wirken, was für Präsentationen und Publikationen oft bevorzugt wird.

TippEllipse vs. Hülle vs. Rechteck - wann nutzt man was?

Das ggforce-Paket bietet drei Geoms zur Gruppenmarkierung, die jeweils für unterschiedliche Situationen geeignet sind:

  • geom_mark_ellipse(): Am besten geeignet, wenn Gruppen annähernd normalverteilt sind. Die Ellipse spiegelt die statistische Streuung und Orientierung jedes Clusters wider. Nützlich, um Verteilungseigenschaften zu vermitteln.
  • geom_mark_hull(): Am besten geeignet, wenn man die tatsächliche Ausdehnung der Daten hervorheben möchte, ohne Verteilungsannahmen zu treffen. Die Hülle folgt exakt den äußersten Punkten (mit optionaler Glättung).
  • geom_mark_rect(): Die einfachste Option - ein rechteckiger Begrenzungsrahmen um jede Gruppe. Nützlich, wenn Gruppen gut getrennt sind und eine einfache Hervorhebung genügt.

Alle drei akzeptieren dieselben Kern-Aesthetics (label, group, description) und Styling-Parameter (expand, con.type), sodass man leicht zwischen ihnen wechseln kann.

Zitat

Mit BibTeX zitieren:
@online{schmidt2026,
  author = {{Dr. Paul Schmidt}},
  publisher = {BioMath GmbH},
  title = {8. ggforce},
  date = {2026-08-13},
  url = {https://biomathcontent.netlify.app/de/content/ggplot2/08_ggforce.html},
  langid = {de}
}
Bitte zitieren Sie diese Arbeit als:
Dr. Paul Schmidt. 2026. “8. ggforce.” BioMath GmbH. August 13, 2026. https://biomathcontent.netlify.app/de/content/ggplot2/08_ggforce.html.