# ggplot2 installieren
install.packages("ggplot2", dependencies=T)
# ggplot2 aktivieren
library(ggplot2)
33 Diagramme mit ggplot()
Das Zusatzpaket ggplot
(für grammar of graphics plot) ist Hadley Wickhams1 R
-Implementation der Grammar of Graphics von Leland Wilkinson2. Es ist eines der ersten Pakete des Tidyverse (welches damals noch nicht so hieß). Die Funktion zum plotten heisst “ggplot()
”, das Installationspaket in R
lautet jedoch ggplot2
.
Da ggplot
aus dem Tidyverse stammt (siehe Kapitel @ref(Kapitel-Tidyverse)), ist es von Vorteil, wenn die zu verabreitenden Datensätze dem Prinzip “ein Fall pro Zeile” (tidy data bzw. long table) folgen. Das bedeutet, dass jede Beobachtung (auch Wiederholungen) in einer eigenen Zeile steht, und die jeweiligen Variablen durch die Spalten repräsentiert werden.
Die Idee einer Grammatik für Diagramme ist, dass man jedes Diagramm aus den selben Komponenten aufbauen kann:
einem tidy Datensatz
einem Koordinatensystem
und Geomen (Punkte, Balken, Linien, Flächen)
In der Praxis ist ja auch so: wir haben einen Datensatz, und wir haben eine Vorstellung darüber, was wir gerne plotten möchten, z.B. ein Boxplot des Alters der Probanden nach Geschlecht gruppiert. Das Plott soll so aussehen, dass die Boxplots nebeneinander stehen.
Übersetzt bedeutet das, dass auf der X-Achse die Boxplots ausgerichtet sind, und dass die Y-Achse das Alter darstellt.
Diese Angaben werden an ggplot
übergeben, wobei wir (ähnlich der Pipe
) unsere Angaben mit einem +
Zeichen aneinanderreihen können.
Die Zuweisung von Variablen auf das Koordinatensystem erfolgt über die Funktion aes()
(für aesthetics). In userem Beispiel würden wir so beginnen:
# Lade Testdatensatz
load(url("https://www.produnis.de/R/nw.RData"))
# Grundlegende Zuweisung an gglot()
ggplot(nw, aes(x=sex, y=age))
Dies produziert noch kein Diagramm, da noch wichtige Angaben fehlen, aber wir haben die grundlegenden Zuweisungen vorgenommen. Aus dem Datensatz nw
wurde die Variable sex
der X-Achse zugewiesen, und Variable age
wurde der Y-Achse zugewiesen. Jetzt muss ggplot()
noch wissen, was überhaupt gezeichnet werden soll, also welches “Geom” zum Einsatz kommen soll.
In unserem Beispiel ist das geom_boxplot()
, welches wir mit einem +
Zeichen an ggplot()
übergeben:
ggplot(nw, aes(x=sex, y=age)) +
geom_boxplot()
Weitere Beispiele zu Boxplots finden Sie in Abschnitt 33.5.
Über das +
Zeichen können beliebig viele Layer (Schichten) dem Plot hinzugefügt werden. Dabei werden die aesthetics übernommen, sie können aber in jedem Geom per aes()
neu definiert werden.
ggplot
biete hierfür viele nützliche Komponenten, unter anderem:
Geome (Flächen, Linien, Punkte, usw), beginnend mit geom_, z.B.:
gemo_area()
,gemo_density()
,gemo_smooth()
,gemo_histogram()
,gemo_point()
,gemo_jitter()
,gemo_line()
,gemo_boxplot()
,gemo_col()
,gemo_text()
statistische Funktionen (Häufigkeiten, Mittelwerte, Dichte, uws), beginnend mit stat_, z.B.:
stat_count()
,stat_density()
,stat_function()
,stat_summary()
Koordinatensystem, beginnend mit coor_, z.B.:
coord_flip()
,coord_trans()
Aussehen (Theme), beginnend mit theme_, z.B.:
theme()
,theme_bw()
,theme_classic()
…
Eigenschaft | Befehl |
---|---|
Plot Überschrift | ggtitle("Überschrift", subtitle="Unterschrift") |
theme(plot.title = element_text(size=8)) |
|
theme(plot.subtitle = element_text(size=8), face="bold")) |
|
Plot Untertitel | ggtitle(caption="Untertitel") |
theme(plot.caption = element_text(size=8), face="italic") |
|
Legende Titel | theme(legend.title.x = element_text(size=8)) |
Legende Text | theme(legend.text.x = element_text(size=8)) |
X-Achse Titel | xlab("Titel der X-Achse") |
theme(axis.title.x = element_text(size=8)) |
|
X-Achse Text | theme(axis.text.x = element_text(size=8)) |
X-Achse Ticks | theme(axis.ticks.x = element_text(size=8)) |
scale_x_continuous(breaks = c(0, 2, 6, 8, 15, 25)) |
|
X-Achse Länge | xlim(-3,3) |
Y-Achse Titel | ylab("Titel der Y-Achse") |
theme(axis.title.y = element_text(size=8)) |
|
Y-Achse Text | theme(axis.text.y = element_text(size=8)) |
Y-Achse Ticks | theme(axis.ticks.y = element_text(size=8)) |
scale_y_continuous(breaks = c(0, 2, 6, 8, 15, 25)) |
|
Y-Achse Länge | ylim(-3,3) |
Text | annotate(geom="text", x=0, y=1, label="Huhu", color="black") |
Plot aufteilen | facet_grid(. ~ Gruppe, scales="free", space="free") |
Plot drehen | coord_flip() |
Theme blank | theme_void() |
Theme klassisch | theme_classic() |
vertikale Linie | geom_vline(xintercept=0, linetype="dotted") |
horizontale Linie | geom_hline(yintercept=0, linetype="dashed") |
In RStudio ist ein “Cheatsheet” (siehe Abschnitt 28.1) zu ggplot
verlinkt. Hier finden Sie (fast) alle verfügbaren Komponenten zusammengefasst. Klicken Sie in der Menüzeile von RStudio auf Help
\(\rightarrow\) Cheatsheets
\(\rightarrow\) Data Visualization with ggplot2
.
33.1 Punktwolke
Schauen wir uns die Arbeitsjahre der Pflegenden im Nachtdienst an, indem wir eine Punktwolke erstellen. Auf der X-Achse sollen die Jahre als Pflegefachkraft abgebildet werden, auf der Y-Achse die Arbeitsjahre im Nachtdienst.
ggplot(nw, aes(x=workyear, y=worknight)) +
geom_point()
Als weitere aesthetic können wir festlegen, dass die Farben der Punkte nach Geschlecht unterschiedlich sein sollen. Im Geom geom_point()
können wir zudem das Aussehen der Punkte über den Parameter shape
ändern.
ggplot(nw, aes(x=workyear, y=worknight, col=sex)) +
geom_point(shape=8)
Beachten Sie, dass zwischen col
(Rahmen) und fill
(Füllung) unterschieden wird, wenn Sie Farben zuweisen.
Die Achsen möchten wir anders beschriften:
ggplot(nw, aes(x=workyear, y=worknight, col=sex)) +
geom_point(shape=8) +
# Beschriftung der X-Achse
xlab("Arbeitsjahre in der Pflege") +
# Beschriftung der Y-Achse
ylab("Arbeitsjahre als Nachtwache") +
# Beschriftung der Legendenbox
labs(color="Geschlecht")
Die Textgröße der Achsen könne angepasst werden:
ggplot(nw, aes(x=workyear, y=worknight, col=sex)) +
geom_point(shape=8) +
# Beschriftung der X-Achse
xlab("Arbeitsjahre in der Pflege") +
# Beschriftung der Y-Achse
ylab("Arbeitsjahre als Nachtwache") +
# Beschriftung der Legendenbox
labs(color="Geschlecht") +
# Textgröße X-Beschriftung
theme(axis.title.x = element_text(size=18)) +
# Textgröße der X-Ticks
theme(axis.text.x = element_text(size=10)) +
# Textgröße Y-Beschriftung
theme(axis.title.y = element_text(size=18)) +
# Textgröße der Y-Ticks
theme(axis.text.y = element_text(size=10))
Nun können wir noch eine Regressionsgerade mit geom_smooth()
hinzufügen:
ggplot(nw, aes(x=workyear, y=worknight, col=sex)) +
geom_point(shape=8) +
# Beschriftung der X-Achse
xlab("Arbeitsjahre in der Pflege") +
# Beschriftung der Y-Achse
ylab("Arbeitsjahre als Nachtwache") +
# Beschriftung der Legendenbox
labs(color="Geschlecht") +
# Textgröße X-Beschriftung
theme(axis.title.x = element_text(size=18)) +
# Textgröße der X-Ticks
theme(axis.text.x = element_text(size=10)) +
# Textgröße Y-Beschriftung
theme(axis.title.y = element_text(size=18)) +
# Textgröße der Y-Ticks
theme(axis.text.y = element_text(size=10)) +
# Regressionsgerade
geom_smooth(method="lm")
## `geom_smooth()` using formula = 'y ~ x'
Das Plot könne wir zudem in verschiedene Bereiche aufteilen. Hierzu nehmen wir die Variable timework
, die angibt, ob die Pflegefachpersonen in Voll- oder Teilzeit arbeiten. Die Variable übergeben wir der Komponente facet_grid()
.
ggplot(nw, aes(x=workyear, y=worknight, col=sex)) +
geom_point(shape=8) +
# Beschriftung der X-Achse
xlab("Arbeitsjahre in der Pflege") +
# Beschriftung der Y-Achse
ylab("Arbeitsjahre als Nachtwache") +
# Beschriftung der Legendenbox
labs(color="Geschlecht") +
# Textgröße X-Beschriftung
theme(axis.title.x = element_text(size=18)) +
# Textgröße der X-Ticks
theme(axis.text.x = element_text(size=10)) +
# Textgröße Y-Beschriftung
theme(axis.title.y = element_text(size=18)) +
# Textgröße der Y-Ticks
theme(axis.text.y = element_text(size=10)) +
# Regressionsgerade
geom_smooth(method="lm") +
# Plot aufteilen
facet_grid(. ~ timework, scales = "free", space = "free")
## `geom_smooth()` using formula = 'y ~ x'
Das Plot selbst kann jederzeit als Objekt gespeichert werden. So können Sie anschließend darauf zugreifen. Das ist sehr hilfreich, wenn man am Aussehen herumfeilt.
# Speichere als Objekt "p"
<- ggplot(nw, aes(x=workyear, y=worknight, col=sex)) +
p # Beschriftung der X-Achse
xlab("Arbeitsjahre in der Pflege") +
# Beschriftung der Y-Achse
ylab("Arbeitsjahre als Nachtwache") +
# Beschriftung der Legendenbox
labs(color="Geschlecht") +
# Textgröße X-Beschriftung
theme(axis.title.x = element_text(size=18)) +
# Textgröße der X-Ticks
theme(axis.text.x = element_text(size=10)) +
# Textgröße Y-Beschriftung
theme(axis.title.y = element_text(size=18)) +
# Textgröße der Y-Ticks
theme(axis.text.y = element_text(size=10)) +
geom_smooth(method="lm") +
# Plot aufteilen
facet_grid(. ~ timework, scales = "free", space = "free")
# was wurde gespeichert?
p
## `geom_smooth()` using formula = 'y ~ x'
Der gespeicherte Plot enthält bereits die Regressionsgeraden.
Von hier aus können Sie leichter “herumspielen”:
# spiele mit "p" herum
+ geom_point(shape=2) p
## `geom_smooth()` using formula = 'y ~ x'
# spiele mit "p" herum
+ geom_point(shape=10) p
## `geom_smooth()` using formula = 'y ~ x'
Hier eine Auflistung, welche shape
-Formen es gibt:
shape
nach Zahlenshape
nach FormenNatürlich funktioniert ggplot()
auch in Kombination mit der Pipe
.
%>%
nw drop_na() %>%
ggplot(aes(x=bed)) +
geom_bar(fill=rainbow(6)) +
coord_flip()
33.2 Diagramme speichern
Zum Speichern der Plots in eine Datei wird die Funktion ggsave()
verwendet. Sie speichert das zuletzt erzeugte Plot.
# Plot speichern in Datei "MeinPlot.png"
ggsave("MeinPlot.png", units="mm", width=400, height=200, dpi=300, pointsize=7)
Haben Sie ein Plot als Objekt zugewiesen, und möchten dieses nun in einer Datei speichern, übergeben Sie den Objektnamen mit dem Parameter plot.
# Plot liegt in Objekt "p"
# speichern in Datei "MeinPlot.png"
ggsave("MeinPlot.png", plot=p, units="mm", width=400, height=200, dpi=300, pointsize=7)
33.3 Histrogramm
Histogramme können mit dem geom_histogram()
hinzugefügt werden.
# Histogramm des Alters aus dem Datensatz "epa"
# lade Datensatz
load(url("https://www.produnis.de/R/epa.RData"))
%>%
epa ggplot(aes(x=age)) +
geom_histogram(aes(y=..density..), col="white", fill="plum4")
## Warning: The dot-dot notation (`..density..`) was deprecated in ggplot2 3.4.0.
## ℹ Please use `after_stat(density)` instead.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Mit der Funktion stat_density()
können wir die Dichtefunktion des Alters hinzufügen:
%>%
epa ggplot(aes(x=age)) +
geom_histogram(aes(y=..density..), col="white", fill="plum4") +
stat_density(geom="line", colour="blue", linetype = "dotted")
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Die Dichteverteilung kann auch als Fläche angezeigt werden. Über den Parameter alpha
kann eingestellt werden, wie durchsichtig die Fläche sein soll.
%>%
epa ggplot(aes(x=age)) +
geom_histogram(aes(y=..density..), col="white", fill="plum4") +
stat_density(geom="area", colour="blue", linetype = "dotted", alpha=0.5)
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Die Dichteverteilung der Normalverteilung kann mit der Funktion stat_funtion()
ebenso darübergelegt werden.
%>%
epa ggplot(aes(x=age)) +
geom_histogram(aes(y=..density..), col="white", fill="plum4") +
stat_density(geom="area", colour="blue", linetype = "dotted", alpha=0.5) +
stat_function(fun=dnorm, args=(c(mean=62,sd=18)), colour="red", linetype = "dashed")
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
33.4 Säulen- und Balkendiagramm
Säulendiagramme werden mit geom_bar()
erzeugt. Die Werte der Variable müssen als Faktor vorliegen.
# Lade Testdatensatz
load(url("https://www.produnis.de/R/nw.RData"))
<-nw %>%
p drop_na() %>%
ggplot(aes(x=bed))
+ geom_bar() p
Ein Balkendiagramm wird erzeugt, indem die Kompontent coord_flip()
hinzugefügt wird.
+ geom_bar() + coord_flip() p
Sie können gruppierte Plots über die Aesthetic fill
erzeugen.
%>%
nw drop_na() %>%
ggplot(aes(x=bed, fill=timework)) +
geom_bar()
Über den Parameter position
können Sie die Balken nebeneinander gruppieren…
%>%
nw drop_na() %>%
ggplot(aes(x=bed, fill=timework)) +
geom_bar(position="dodge")
… oder als Prozentwerte plotten.
%>%
nw drop_na() %>%
ggplot(aes(x=bed, fill=timework)) +
geom_bar(position="fill")
Möchten Sie ein Barplot aus bereits berechneten Häufigkeiten erstellen, müssen Sie dies dem Geom über den Parameter stat=identity
mitteilen. Die Daten müssen als Datenframe übergeben werden.
# erzeuge Testdaten
<- c("Erdbeere", "Schokolade", "Vanille")
kategorie <- c(10,20,30)
haeufigkeiten <- data.frame(kategorie, haeufigkeiten)
df
ggplot(df, aes(x=kategorie, y=haeufigkeiten, fill=kategorie))+
geom_bar(stat="identity", col="black")
33.5 Boxlots
Boxplots werden über das geom_boxplot()
erstellt. Aus dem Nachtwachendatensatz erstellen wir ein Boxplot über die “Anzahl der Dienste am Stück” (nights
).
load(url("https://www.produnis.de/R/nw.RData"))
ggplot(nw, aes(y=nights))+
geom_boxplot()
Das Aussehen kann beliebig angepasst werden.
ggplot(nw, aes(y=nights))+
# Die Ausreisser stylen
geom_boxplot(colour="darkblue", fill="skyblue", outlier.colour="blue", outlier.shape=8, outlier.size=3) +
# zeichne Whisker-Linien
stat_boxplot(geom ='errorbar') +
# beschrifte Y-Achse
ylab("Dienste hintereinander") +
# Textgröße Y-Achsenskala
theme(axis.title.y = element_text(size=18)) +
# individuelle Ticks Y-Achse
scale_y_continuous(breaks = c(0, 2, 4, 6, 8, 10 , 15, 25)) +
# beschrifte X-Achse
xlab(NULL) +
# X-Achsenbeschriftung löschen
theme(axis.ticks.x = element_blank(), axis.text.x = element_blank())
So können auch mehere Gruppen abgebildet werden, zum Beispiel nach Geschlecht gruppiert:
ggplot(nw, aes(x=sex, y=nights, fill=sex)) +
# Die Ausreisser stylen
geom_boxplot(colour="darkblue", outlier.colour="blue", outlier.shape=8, outlier.size=3) +
# zeichne Whisker-Linien
stat_boxplot(geom ='errorbar') +
# beschrifte Y-Achse
ylab("Dienste hintereinander") +
# Textgröße Y-Achsenskala
theme(axis.title.y = element_text(size=18)) +
# individuelle Ticks Y-Achse
scale_y_continuous(breaks = c(0, 2, 4, 6, 8, 10 , 15, 25)) +
# beschrifte X-Achse
xlab(NULL) +
# X-Achsenbeschriftung löschen
theme(axis.ticks.x = element_blank(), axis.text.x = element_blank()) +
# Zeichne den Mittelwert als roten Punkt
stat_summary(fun=mean, colour="darkred", geom="point", shape=18, size=5, show.legend = F)
Hier ein etwas komplexeres Beispiel aus dem Nachtwachen-Datensatz. Zuerst selektieren wir die Variablen zu Pflegestufen
, Demenz
und freiheitsentziehenden Maßnahmen (FEM
) und bringen sie ins long table
Format. Dann führen wir eine neue gruppierende Variable “Gruppe
” ein. Diese dient als Trenner zwischen den Boxplotgruppen.
load("../nw-pub.RData")
# Lade Nachtwachendatensatz
load(url("https://www.produnis.de/R/nw.RData"))
<- nw %>%
nwbp # suche die richtigen Spalten heraus
select(Stufe0, Stufe1, Stufe2, Stufe3, Demenz, Bettgitter, Bettgurt, Schlafmittel) %>%
# erzeuge daraus eine "long table"
pivot_longer(cols=c(Stufe0, Stufe1, Stufe2, Stufe3, Demenz, Bettgitter, Bettgurt, Schlafmittel), names_to="Variable", values_to="Anzahl") %>%
# Füge manuell die "Trenner"-Variable hinzu
bind_cols(., Gruppe=factor(rep(c("Pflegestufe", "Pflegestufe", "Pflegestufe", "Pflegestufe", "Demenz", "FEM", "FEM", "FEM"), 276)))
ggplot(nwbp, aes(Variable, Anzahl))+
geom_boxplot(outlier.size = 3,outlier.shape=1) +
stat_boxplot(geom ='errorbar') +
ylab(NULL) + xlab(NULL)+
theme(axis.text.x = element_text(size=12))+
theme(axis.text.y = element_text(size=11))+
scale_y_continuous(limits=c(0, 70))+
scale_y_continuous(breaks = c(0,10,20,30,40,50,60,70,100))+
facet_grid(. ~ Gruppe, scales = "free", space = "free") # "Gruppe" ist der Spaltenname
## Scale for y is already present.
## Adding another scale for y, which will replace the existing scale.
## Warning: Removed 321 rows containing non-finite values (`stat_boxplot()`).
## Removed 321 rows containing non-finite values (`stat_boxplot()`).
33.6 Likert-Plots
Likkert-Plots können über das Zusatzpaket likert
geplottet werden. Die Daten müssen in einem Datenframe vorliegen und an die Funktion likert()
übergeben werden.
# Lade Nachtwachendatensatz
load(url("https://www.produnis.de/R/nw.RData"))
# Erzeuge Datenframe "Pause"
<- data.frame(nw$pause)
pause
# übergebe Datenframe an "likert()"
<- likert::likert(pause)
pause
# plotte
plot(pause)
Sollen mehrere Variablen gemeinsam ausgewertet werden, erzeugt man einfach ein Datenframe, wobei wie gewohnt jede Spalte eine Variable darstellt.
# Erzeuge neues Datenframe "n"
<- data.frame(nw[, 29:34])
n
# übergebe an "likert()"
<- likert::likert(n)
n
# plot
plot(n)
33.7 Kreisdiagramm
In ggplot()
gibt es kein Geom, mit dem Kreisdiagramme erstellt werden können. Der Trick besteht darin, einfach ein geom_bar()
auf einem circulären Koordinationsystem zu plotten. Dies erreichen wir, indem coord_polar()
hinzugefügt wird.
Wir übergeben ggplot()
ein Datenframe, mit einer Variable für die Gruppennamen, und einer Variable mit den Anteilswerten.
Dass die Anteile bereits berechnet sind teilen wir über den Parameter stat=“identity” mit.
# Erzeuge Datenframe
<- data.frame(Gruppe=c("A", "B", "C"), Anteil=c(60, 25, 15))
df
# pfusche Pie-Chart zurecht
ggplot(df, aes(x="", y=Anteil, fill=Gruppe)) +
geom_bar(stat="identity", width=1) +
coord_polar("y", start=0) +
# entferne Achsen und Ticks
theme_void()
Liegen die Daten in einer Variable vor, z.B. als factor
, ändert sich der Aufruf wie folgt:
# Lade Nachtwachendaten
load(url("https://www.produnis.de/R/nw.RData"))
# plotte Variable "sex" als PieChart
ggplot(nw,aes(x="", fill=factor(sex)))+
geom_bar(width = 1,color="white") +
coord_polar("y") +
labs(fill="Geschlecht")+
# entferne Achsen und Ticks
theme_void()