Infovis 1: Demo

library("readr")
library("lubridate")
library("dplyr")
library("ggplot2")
library("tidyr")

Als erstes laden wir den Datensatz temperature_SHA_ZER.csv ein. Es handelt sich dabei um eine leicht modifizierte Variante der Daten aus PrePro1 und PrePro2.

# Wir können den Datensatz direkt über die URL einladen oder aber ihr nutzt die
# URL um den Datensatz lokal bei euch abzuspeichern und wie gewohnt einzulesen
temperature <- read_delim("datasets/infovis/temperature_SHA_ZER.csv", ",")
time SHA ZER
2000-01-01 00:00:00 0.2 -8.8
2000-01-01 01:00:00 0.3 -8.7
2000-01-01 02:00:00 0.3 -9.0
2000-01-01 03:00:00 0.3 -8.7
2000-01-01 04:00:00 0.4 -8.5
2000-01-01 05:00:00 0.5 -8.4

Ggplot2

Ein ggplot wird mit dem Befehl ggplot() initiiert. Hier wird einerseits der Datensatz festgelegt, auf dem der Plot beruht (data =), sowie die Variablen innerhalb des Datensatzes, die Einfluss auf den Plot ausüben (mapping = aes()).

# Datensatz: "temperature" | Beeinflussende Variablen: "time" und "temp"
ggplot(data = temperature, mapping = aes(time, SHA))

Weiter braucht es mindestens ein “Layer”, der beschreibt, wie die Daten dargestellt werden sollen (z.B. geom_point()). Anders als bei “Piping” (|>) wird ein Layer mit + hinzugefügt.

ggplot(data = temperature, mapping = aes(time, SHA)) +
  # Layer: "geom_point" entspricht Punkten in einem Scatterplot
  geom_point()

Da ggplot die Eingaben in der Reihenfolge data = und dann mapping = erwartet, können wir diese Spezifizierungen auch weglassen.

ggplot(temperature, aes(time, SHA)) +
  geom_point()

Long vs. wide

Wie wir in PrePro 2 bereits erwähnt haben, ist ggplot2 auf long tables ausgelegt. Wir überführen deshalb an dieser Stelle die breite in eine lange Tabelle:

temperature_long <- pivot_longer(temperature, -time, names_to = "station", values_to = "temp")

Nun wollen wir die Stationen unterschiedlich einfärben. Da wir Variablen definieren wollen, welche Einfluss auf die Grafik haben sollen, gehört diese Information in aes().

ggplot(temperature_long, aes(time, temp, colour = station)) +
  geom_point()

Wir können noch einen Layer mit Linien hinzufügen:

ggplot(temperature_long, aes(time, temp, colour = station)) +
  geom_point() +
  geom_line()

Beschriftungen (labels)

Weiter können wir die Achsen beschriften und einen Titel hinzufügen. Zudem lasse ich die Punkte (geom_point()) nun weg, da mir diese nicht gefallen.

ggplot(temperature_long, aes(time, temp, colour = station)) +
  geom_line() +
  labs(
    x = "Zeit",
    y = "Temperatur in °C",
    title = "Temperaturdaten Schweiz",
    subtitle = "2001 bis 2002",
    color = "Station"
  )

Split Apply Combine

Im obigen Plot fällt auf, dass stündliche Werte eine zu hohe Auflösung haben, wenn wir die Daten über 2 Jahre visualisieren. Mit Split Apply Combine (PrePro 3) können wir die Auflösung unserer Daten verändern:

temperature_day <- temperature_long |>
  mutate(time = as.Date(time))

temperature_day
## # A tibble: 35,088 × 3
##    time       station  temp
##    <date>     <chr>   <dbl>
##  1 2000-01-01 SHA       0.2
##  2 2000-01-01 ZER      -8.8
##  3 2000-01-01 SHA       0.3
##  4 2000-01-01 ZER      -8.7
##  5 2000-01-01 SHA       0.3
##  6 2000-01-01 ZER      -9  
##  7 2000-01-01 SHA       0.3
##  8 2000-01-01 ZER      -8.7
##  9 2000-01-01 SHA       0.4
## 10 2000-01-01 ZER      -8.5
## # ℹ 35,078 more rows

temperature_day <- temperature_day |>
  group_by(station, time) |>
  summarise(temp = mean(temp))

temperature_day
## # A tibble: 1,462 × 3
## # Groups:   station [2]
##    station time        temp
##    <chr>   <date>     <dbl>
##  1 SHA     2000-01-01  1.25
##  2 SHA     2000-01-02  1.73
##  3 SHA     2000-01-03  1.59
##  4 SHA     2000-01-04  1.78
##  5 SHA     2000-01-05  4.66
##  6 SHA     2000-01-06  3.49
##  7 SHA     2000-01-07  3.87
##  8 SHA     2000-01-08  3.28
##  9 SHA     2000-01-09  3.24
## 10 SHA     2000-01-10  3.24
## # ℹ 1,452 more rows

X/Y-Achse anpassen

Man kann auch Einfluss auf die x-/y-Achsen nehmen. Dabei muss man zuerst festlegen, was für ein Achsentyp der Plot hat (vorher hat ggplot eine Annahme auf der Basis der Daten getroffen).

Bei unserer y-Achse handelt es sich um numerische Daten, ggplot nennt diese: scale_y_continuous(). Unter ggplot2.tidyverse.org findet man noch andere x/y-Achsentypen (scale_x_irgendetwas bzw. scale_y_irgendetwas).

ggplot(temperature_day, aes(time, temp, colour = station)) +
  geom_line() +
  labs(
    x = "Zeit",
    y = "Temperatur in °C",
    title = "Temperaturdaten Schweiz",
    subtitle = "2001 bis 2002",
    color = "Station"
  ) +
  scale_y_continuous(limits = c(-30, 30)) # y-Achsenabschnitt bestimmen

Das gleiche Spiel kann man für die x-Achse betreiben. Bei unserer x-Achse handelt es sich ja um Datumsangaben. ggplot nennt diese: scale_x_date().

ggplot(temperature_day, aes(time, temp, colour = station)) +
  geom_line() +
  labs(
    x = "Zeit",
    y = "Temperatur in °C",
    title = "Temperaturdaten Schweiz",
    subtitle = "2001 bis 2002",
    color = "Station"
  ) +
  scale_y_continuous(limits = c(-30, 30)) +
  scale_x_date(
    date_breaks = "3 months",
    date_labels = "%b"
  )

Facets / Small Multiples

Sehr praktisch sind auch die Funktionen für “Small multiples”. Dies erreicht man mit facet_wrap() (oder facet_grid(), mehr dazu später). Man muss mit einem Tilde-Symbol “~” nur festlegen, welche Variable für das Aufteilen des Plots in kleinere Subplots verantwortlich sein soll.

ggplot(temperature_day, aes(time, temp, colour = station)) +
  geom_line() +
  labs(
    x = "Zeit",
    y = "Temperatur in °C",
    title = "Temperaturdaten Schweiz",
    subtitle = "2001 bis 2002",
    color = "Station"
  ) +
  scale_y_continuous(limits = c(-30, 30)) +
  scale_x_date(
    date_breaks = "3 months",
    date_labels = "%b"
  ) +
  facet_wrap(~station)

Auch facet_wrap kann man auf seine Bedürfnisse anpassen: Beispielweise kann man mit ncol = die Anzahl Facets pro Zeile bestimmen.

Zudem brauchen wir die Legende nicht mehr, da der Stationsname über jedem Facet steht. Ich setze deshalb theme(legend.position="none")

p <- ggplot(temperature_day, aes(time, temp, colour = station)) +
  geom_line() +
  labs(
    x = "Zeit",
    y = "Temperatur in °C",
    title = "Temperaturdaten Schweiz",
    subtitle = "2001 bis 2002"
  ) +
  scale_y_continuous(limits = c(-30, 30)) +
  scale_x_date(
    date_breaks = "3 months",
    date_labels = "%b"
  ) +
  facet_wrap(~station, ncol = 1) +
  theme(legend.position = "none")


p

Themes

Bisher haben wir die Standardeinstellung für das Kreieren der Plots genutzt. In diesem Abschnitt zeigen wir, wie du Plots individuell mit sogenannten Themes anpassen kannst.

Nun wollen wir mit einer von ggplot2 zur Verfügung gestellten Theme unseren Plot anpassen. Wir benutzen hier theme_classic(), weitere Themes findet ihr hier.

p + theme_classic()

Fast alle Aspekte eines Plots können auch individuell angepasst werden. Jürgen Dengler und sein Team empfehlen folgende Anpassungen:

mytheme <- 
  theme_classic()  +
  theme(axis.line = element_line(linewidth = 0.6, color = "black"), 
        axis.text = element_text(size = 11, color = "black"), 
        axis.title = element_text(size = 13, color = "black"), 
        axis.ticks = element_line(linewidth = 0.6, color = "black"), 
        axis.ticks.length = unit(0.2, "cm"),
        axis.title.y = element_text(vjust = +2),
        axis.title.x = element_text(vjust = -2),
        plot.title = element_text(hjust = 0.5, size = 13),
        plot.subtitle = element_text(hjust = 0.5, size = 10),
        plot.margin = margin(t = 4, r = 6, b = 6, l = 8, unit = "pt") 
        
  )
p + mytheme

Plot exportieren

Folgendermassen könnt ihr den letzten Plot als PNG-Datei abspeichern:

ggsave(filename = "plot.png")