Rainclouds

Sogenannte Rainclouds beinhalten nicht nur die Verteilungsinformationen aus einem Boxplot, sondern auch die Verteilung der Rohwerte. Denn verschiedene Verteilungen können zu einem gleichen Boxplot führen. Das folgende Beispiel ist aus einem Blogbeitrag con Cédric Scherer, in dem (auf Englisch) sehr gut erklärt wird, warum Boxplots manchmal nicht so gut sind.

Code zum Erstellen des fiktiven Datensatze

Wir haben einen fiktiven Datensatz, der folgendes Boxplot ergibt: Es sieht also erstmal von den Kennzahlen des Boxplots so aus, dass die Daten ähnlich sind. Fügen wir jetzt mal die Fallzahlen hinzu:

Obwohl dasselbe Boxplot entsteht, sind die Fallzahlen pro Gruppe sehr unterschiedlich. Jetzt fügen wir mal die Rohwerte (geom_point()) hinzu:

ggplot(
  data, 
  aes(
    x = group, 
    y = value
  )
) +
  geom_boxplot(fill = "grey92") +
  geom_point(
    size = 2,
    alpha = .3,
    position = position_jitter(
      seed = 1,
      width = .2
    )
  )

Beim ersten Anblick wird schon deutlich, dass die Verteilung zwischen den Gruppen gar nicht so ähnlich ist, wie es die Boxplots möglicherweise angedeutet haben.

Um diese Informationen in einem Raincloud-Plot einzuschließen, werden sowohl die Rohdaten eingezeichnet als auch die Verteilung. Dazu musst du die library ggdist installieren und aktivieren:

install.packages("ggdist")
library("ggdist")

Aus der library ggdist nutzt du die Funktion stat_halfeye() um die Verteilung auszugeben. Machen wir diesen ersten Schritt:

ggplot(data, aes(x = group, y = value)) + 
  ## add half-violin from {ggdist} package
  stat_halfeye(
    ## custom bandwidth
    adjust = .5, 
    ## adjust height
    width = .6, 
    ## move geom to the right
    justification = -.2, 
    ## remove slab interval
    .width = 0, 
    point_colour = NA
  ) + 
  geom_boxplot(
    width = .12, 
    ## remove outliers
    outlier.color = NA ## `outlier.shape = NA` works as well
  )

Du siehst jetzt also neben dem Boxplot noch die Verteilung. Aber die Information der Rohdatenpunkte war ebenfalls sehr hilfreich um die Daten visuell zu verstehen. Dazu nutzt du die Funktion stat_dots() aus ggdist.

ggplot(
  data, 
  aes(
    x = group, 
    y = value
    )
  ) + 
  stat_halfeye(
    adjust = .5, 
    width = .6, 
    justification = -.2, 
    .width = 0, 
    point_colour = NA
  ) + 
  geom_boxplot(
    width = .12, 
    outlier.color = NA 
  ) +
  ## Rohdatenpunkte hinzfügen
  stat_dots(
    # in welche Richtung die Punkt sich türmen sollen, probiere right einfach aus!
    side = "left", 
    # leichtes Einrücken von geom_boxplot()
    justification = 1.1, 
    # Größe der Punkte
    binwidth = .25
  )

Als letztes kann man noch den white space entfernen, indem du die x-Achse beschränkst:

ggplot(
  data, 
  aes(
    x = group, 
    y = value
    )
  ) + 
  stat_halfeye(
    adjust = .5, 
    width = .6, 
    justification = -.2, 
    .width = 0, 
    point_colour = NA
  ) + 
  geom_boxplot(
    width = .12, 
    outlier.color = NA 
  ) +
  ## Rohdatenpunkte hinzfügen
  stat_dots(
    # in welche Richtung die Punkt sich türmen sollen, probiere right einfach aus!
    side = "left", 
    # leichtes Einrücken von geom_boxplot()
    justification = 1.1, 
    # Größe der Punkte
    binwidth = .25
  ) + 
  # Entferne white space
  coord_cartesian(
  xlim = c(
      1.2,
      NA
    )
  )

Wenn du viele Datenpunkte hast und viele Gruppen, ist die Ansicht mit stat_dots() manchmal zu unübersichtlich. Alternativ eignet sich: geom_halfpoint()!

ggplot(
  data, 
  aes(
    x = group, 
    y = value
    )
  ) + 
  stat_halfeye(
    adjust = .5, 
    width = .6, 
    justification = -.2, 
    .width = 0, 
    point_colour = NA
  ) + 
  geom_boxplot(
    width = .12, 
    outlier.color = NA 
  ) +
  geom_half_point(
    # links ausgerichtet
    side = "l", 
    ## horizontale Linien anstatt Punkten
    shape = 95,
    # kein jittern
    range_scale = 0,
    size = 10, 
    alpha = .2
  ) + 
  # Entferne white space
  coord_cartesian(
  xlim = c(
      1.2,
      NA
    )
  )

Oder aber mit gejitterten Punkten:

ggplot(
  data, 
  aes(
    x = group, 
    y = value
    )
  ) + 
  stat_halfeye(
    adjust = .5, 
    width = .6, 
    justification = -.2, 
    .width = 0, 
    point_colour = NA
  ) + 
  geom_boxplot(
    width = .12, 
    outlier.color = NA 
  ) +
  geom_half_point(
    # Ausrichtung links
    side = "l", 
    # jittering
    range_scale = .4, 
    # Transparenz
    alpha = .3
  ) + 
  coord_cartesian(
  xlim = c(
      1.2,
      NA
    )
  )

Eine Raincloud gibt dir also eine deutlich bessere Übersicht als ein Boxplot!