Lab: Datenvisualisierung

Urban Research HS2026

Mario Angst

2026-09-30

Lab: Datenvisualisierung

Artwork by Allison Horst, CC-BY license

Workflow und unser Fokus heute

Wickham, Çetinkaya-Rundel, and Grolemund (2023), https://r4ds.hadley.nz/whole-game.html#fig-ds-whole-game

Was wir am Ende haben werden

Daten: GWR (Eidg. Gebäude- und Wohnungsregister)

Daten herunterladen

Besucht https://www.housing-stat.ch/de/data/supply/public.html

Unter “Daten herunterladen” gebt “Zürich” ein und wählt “Kanton Zürich ZH” aus.

Lädt “Alle Daten (ZIP)” herunter.

Congrats, alle Gebäude des Kantons Zürich (über die Zeit!) sind nun auf eurem Computer als Datensatz.

Datensatz platzieren

Erstellt an dem Ort, wo ihr vorher euer Projekt erstellt habt, einen Ordner data.

Erstellt darin einen weiteren Ordner gwr.

Entpackt die Datei, die ihr soeben vom GWR heruntergeladen habt, in diesem Ordner.

Erstellt ein Script lab-datenvisualisierung.R

Wir rüsten uns mit Packages aus!

Artwork by Allison Horst, CC-BY license

Packages installieren

install.packages("readr")
install.packages("dplyr")
install.packages("janitor")
install.packages("ggplot2")
install.packages("ggthemes")

Packages laden

library(readr)
library(dplyr)
library(janitor)
library(ggplot2)
library(ggthemes)

Datensatz laden

Wir laden nun einen der Datensätze aus dem GWR in R.

gwr_gebaeude_zh <- 
    read_tsv("data/gwr/gebaeude_batiment_edificio.csv") |>
    clean_names()
  1. Wir benutzen die Funktion read_tsv() (von readr) und geben den Pfad zu unserer File ein
  2. Wir benutzen die Funktion clean_names() (von janitor) und “putzen” die geladene File etwas

readr? janitor?

Artwork by Allison Horst, CC-BY license

Datensatz anschauen

gwr_gebaeude_zh
# A tibble: 400,210 × 47
    egid gdekt ggdenr ggdename       egrid lgbkr lparz lparzsx ltyp  gebnr gbez 
   <dbl> <chr>  <dbl> <chr>          <chr> <dbl> <chr> <lgl>   <lgl> <chr> <chr>
 1     1 ZH         2 Affoltern am … CH41…     0 4498  NA      NA    22    <NA> 
 2     2 ZH         2 Affoltern am … <NA>      0 3812  NA      NA    708   <NA> 
 3     3 ZH         2 Affoltern am … CH64…     0 3805  NA      NA    727   <NA> 
 4     4 ZH         2 Affoltern am … CH79…     0 3811  NA      NA    715   <NA> 
 5     5 ZH         2 Affoltern am … CH63…     0 3804  NA      NA    732   <NA> 
 6     6 ZH         2 Affoltern am … CH78…     0 3810  NA      NA    720   <NA> 
 7     7 ZH         2 Affoltern am … CH62…     0 3803  NA      NA    740   <NA> 
 8     8 ZH         2 Affoltern am … CH77…     0 3809  NA      NA    722   <NA> 
 9     9 ZH         2 Affoltern am … CH61…     0 3802  NA      NA    742   <NA> 
10    10 ZH         2 Affoltern am … CH66…     0 3808  NA      NA    723   <NA> 
# ℹ 400,200 more rows
# ℹ 36 more variables: gkode <dbl>, gkodn <dbl>, gksce <dbl>, gstat <dbl>,
#   gkat <dbl>, gklas <dbl>, gbauj <dbl>, gbaum <dbl>, gbaup <dbl>,
#   gabbj <dbl>, garea <dbl>, gvol <dbl>, gvolnorm <dbl>, gvolsce <dbl>,
#   gastw <dbl>, ganzwhg <dbl>, gazzi <dbl>, gschutzr <dbl>, gebf <dbl>,
#   gwaerzh1 <dbl>, genh1 <dbl>, gwaersceh1 <dbl>, gwaerdath1 <date>,
#   gwaerzh2 <dbl>, genh2 <dbl>, gwaersceh2 <dbl>, gwaerdath2 <date>, …

Terminologie: Datensatz I

  • Variable (variable): Irgend etwas, was man über ein Objekt (bspw. ein Gebäude) messen kann (Bsp: Gebäudehöhe, Heizungstyp, Gebäudename)
  • Wert (value): Ein möglicher Zustand einer Variable, wenn man sie misst (Höhe in m oder “hat Ölheizung”)
  • Observation (observation): Messung(en) (oft für mehrere Variablen zu einem Zeitpunkt) bezogen auf ein Objekt, kann je einen Wert für mehrere Variablen umfassen (Höhe: 30m, Ölheizung: “hat keine Ölheizung”, gemessen für Gebäude “Gasthaus Wilder Mann” am 30. Januar 2026) -> Datenpunkt

Terminologie: Datensatz II

  • Tabellendaten (tabular data): Menge von Werten, welche sich jeweils auf eine Observation und eine Variable in dieser Observation beziehen
  • “Tidy” data: Daten sind dann “tidy”, wenn sie in Reihen (rows) und Spalten (columns) so angeordnet sind dass:

Tidy data: Jede Reihe stellt eine Observation und jede Spalte stellt eine Variable dar

Tidy Data

Illustrations from the Openscapes blog Tidy Data for reproducibility, efficiency, and collaboration by Julia Lowndes and Allison Horst

Datensatz anschauen: Tidy?

gwr_gebaeude_zh |>
    select(egid, garea, gvol, gbauj)
# A tibble: 400,210 × 4
    egid garea  gvol gbauj
   <dbl> <dbl> <dbl> <dbl>
 1     1   198    NA  1984
 2     2    NA    NA  1977
 3     3    16   921  1978
 4     4   125    NA  1978
 5     5    94    NA  1978
 6     6   158    NA  1978
 7     7    10    NA  1978
 8     8   155    NA  1978
 9     9    83    NA  1977
10    10   160    NA  1978
# ℹ 400,200 more rows
  1. Ctrl + Shift + M macht die Vorwärts-Pipe (|>)

Daten anschauen: Interaktiver Viewer in IDE

Funktioniert in RStudio:

View(gwr_gebaeude_zh)

Was können wir diesen Datensatz fragen?

Wir haben Daten hier zu 400210 bewilligungspflichtigen existierenden und nicht mehr existierenden / noch nicht existierenden Gebäuden in Zürich.

  • In welche Gemeinde wurden in welchem Jahr die meisten Gebäude abgerissen?
  • In welcher Gemeinde standen 2025 die höchsten durchschnittlichen Gebäude?
  • Was ist die häufigste Gebäudebezeichnung? (…)

Was im Datensatz alles drin ist

Öffnet das Metadaten-PDF, welches bei euch unter data/gwr/gebaeude-batiment-edificio_specifications.pdf drin ist. Dieses PDF listet alle Variablen im Datensatz.

Fragen an den Datensatz? Diskutiert 4 Minuten mit eurem Nachbarn.

Unser Ziel in diesem Visualisierungs-Lab: Zusammenhang

Zusammenhang zwischen Gebäudefläche und Gebäudevolumen in drei Gemeinden zwischen 2020 und 2026, mit allgemeinem Trend und separiert nach Gemeinde

Pause

Artwork by Allison Horst, CC-BY license

Datenvisualisierung end-to-end Beispiel

Unser Ziel in diesem Visualisierungs-Lab: Visualisierung

Visualisierung bauen: Daten filtern

Daten filtern

Für unsere Analyse fokussieren wir uns auf die drei Gemeinden Dübendorf, Winterthur und Uster und schauen nur die Jahren 2020 bis 2026 an. Wir filtern darum unsere Daten und erstellen einen kleineren Datensatz. Ihr müsst dies noch nicht verstehen, aber führt es aus:

gwr_viz_daten <-
      gwr_gebaeude_zh |> 
      filter(gbauj >= 2020 & gbauj <= 2026) |> 
      filter(ggdename %in% c("Dübendorf","Uster","Winterthur")) |> 
      filter(!is.na(garea) & !is.na(gvol))
gwr_viz_daten
# A tibble: 599 × 47
        egid gdekt ggdenr ggdename   egrid lgbkr lparz lparzsx ltyp  gebnr gbez 
       <dbl> <chr>  <dbl> <chr>      <chr> <dbl> <chr> <lgl>   <lgl> <chr> <chr>
 1 191884277 ZH       198 Uster      CH45…     0 B6431 NA      NA    7743  <NA> 
 2 191886531 ZH       198 Uster      CH53…     0 F1506 NA      NA    7681  <NA> 
 3 191886532 ZH       198 Uster      CH53…     0 F1506 NA      NA    7679  <NA> 
 4 191887131 ZH       198 Uster      CH53…     0 F1506 NA      NA    7679  <NA> 
 5 191887155 ZH       198 Uster      CH53…     0 F1507 NA      NA    7680  <NA> 
 6 191887449 ZH       198 Uster      CH93…     0 C3536 NA      NA    7670  <NA> 
 7 191901651 ZH       198 Uster      CH41…     0 B7210 NA      NA    7758  <NA> 
 8 191902112 ZH       198 Uster      CH79…     0 F870  NA      NA    7688  <NA> 
 9 191902113 ZH       198 Uster      CH51…     0 F870  NA      NA    7744  <NA> 
10 191903496 ZH       230 Winterthur CH60…     1 ST33… NA      NA    230S… <NA> 
# ℹ 589 more rows
# ℹ 36 more variables: gkode <dbl>, gkodn <dbl>, gksce <dbl>, gstat <dbl>,
#   gkat <dbl>, gklas <dbl>, gbauj <dbl>, gbaum <dbl>, gbaup <dbl>,
#   gabbj <dbl>, garea <dbl>, gvol <dbl>, gvolnorm <dbl>, gvolsce <dbl>,
#   gastw <dbl>, ganzwhg <dbl>, gazzi <dbl>, gschutzr <dbl>, gebf <dbl>,
#   gwaerzh1 <dbl>, genh1 <dbl>, gwaersceh1 <dbl>, gwaerdath1 <date>,
#   gwaerzh2 <dbl>, genh2 <dbl>, gwaersceh2 <dbl>, gwaerdath2 <date>, …

Visualisierung bauen: ggplot erstellen

ggplot erstellen

ggplot(
    data = gwr_viz_daten
    )

Visualisierung bauen: aesthetic mappings

aesthetic mappings: x und y

ggplot(
    data = gwr_viz_daten,
    mapping = aes(x = garea, y = gvol)
    )

Visualisierung bauen: aesthetic mappings

Visualisierung bauen: geom einfügen

geom (geometrisches Objekt) einfügen: wir fügen (mit +) einen Layer geom_point() hinzu und kriegen einen Scatterplot

ggplot(
    data = gwr_viz_daten,
    mapping = aes(x = garea, y = gvol, color = ggdename, shape = ggdename)
    ) +
    geom_point()

Visualisierung bauen: geom einfügen

Visualisierung bauen: Gemeinden als Farbe

Aesthetic mapping 2: Gemeinden mit Farben hervorheben

Gibt es Unterschiede nach Gemeinden?

ggplot(
    data = gwr_viz_daten,
    mapping = aes(x = garea, y = gvol, color = ggdename)
    ) +
    geom_point()

Visualisierung bauen: Gemeinden als Farbe

Visualisierung bauen: Zusammenhangs-Geom

Allgemeinen Zusammenhang hervorheben mit einem neuen Layer: geom_smooth (wieder mit + hinzugefügt)

ggplot(
    data = gwr_viz_daten,
    mapping = aes(x = garea, y = gvol, color = ggdename)
    ) +
    geom_point() +
    geom_smooth(method = "lm")

Visualisierung bauen: Zusammenhangs-Geom

Visualisierung bauen: Zusammenhangs-Geom II

Allgemeinen Zusammenhang hervorheben mit geom_smooth, aber jetzt für alle Gemeinden. Wir benutzen das Mapping zu Gemeinden nun nur noch für Punkte

ggplot(
    data = gwr_viz_daten,
    mapping = aes(x = garea, y = gvol)
    ) +
    geom_point(mapping = aes(color = ggdename)) +
    geom_smooth(method = "lm")

Visualisierung bauen: Zusammenhangs-Geom II

Visualisierung bauen: Form zusätzlich zu Farbe

Um die Gemeinden noch besser zu differenzieren verwenden wir nun noch ein mapping der Punkte zu Form (shape)

ggplot(
    data = gwr_viz_daten,
    mapping = aes(x = garea, y = gvol)
    ) +
    geom_point(mapping = aes(color = ggdename, shape = ggdename)) +
    geom_smooth(method = "lm")

Visualisierung bauen: Form zusätzlich zu Farbe

Visualisierung bauen: Accessibility

Rot-Blau-Grün ist allgemein nicht so eine gute Idee. Wir benutzen nun noch ein color-blind friendly theme von ggthemes, welches wir wieder mit + hinzufügen

ggplot(
    data = gwr_viz_daten,
    mapping = aes(x = garea, y = gvol)
    ) +
    geom_point(mapping = aes(color = ggdename, shape = ggdename)) +
    geom_smooth(method = "lm") +
    scale_color_colorblind()

Visualisierung bauen: Accessibility

Visualisierung bauen: Beschriftungen

Wir sollten unsere Achsen besser beschriften und ein Titel wäre noch toll. Wir können dies über einen Layer mit labs() tun

ggplot(
    data = gwr_viz_daten,
    mapping = aes(x = garea, y = gvol)
    ) +
    geom_point(mapping = aes(color = ggdename, shape = ggdename)) +
    geom_smooth(method = "lm") +
    scale_color_colorblind()  +
    labs(
      title = "Gebäudebaujahr und Gebäudevolumen",
      subtitle = "Basierend auf GWR für Dübendorf, Uster und Winterthur von 2020 bis 2026",
      x = "Gebäudefläche in m²", y = "Gebäudevolumen in m³",
      color = "Gemeinde", shape = "Gemeinde"
    )

Visualisierung bauen: Beschriftungen

Rückblick: Layers

Pause

Artwork by Allison Horst, CC-BY license

Verteilungen visualisieren

Kategorische Variablen

Eine Variable ist kategorisch, wenn sie nur einen Wert aus einer kleinen Menge von vorbestimmten Kategorien annehmen kann.

Beispiel: Gebäudekategorie (gstat) im GWR:

Gebäude projektiert
Gebäude bewilligt
Gebäude im Bau
Gebäude bestehend
Gebäude nicht nutzbar
Gebäude abgebrochen
Gebäude nicht realisiert

Kategorische Variablen: Typen

Artwork by Allison Horst, CC-BY license

Kategorische Variablen: Verteilungen visualisieren

ggplot(
    data = gwr_viz_daten,
    mapping = aes(x = gstat)
    ) +
    geom_bar()

Kategorische Variablen: Verteilungen visualisieren

Numerische Variablen

Numerische Variablen können numerische Werte annehmen (duh), was beispielsweise heisst, dass man damit rechnen (bspw. Durchschnitte ausrechnen) kann.

Numerische Variablen: Typen

Artwork by Allison Horst, CC-BY license

Numerische Variablen: Histogram

ggplot(
    data = gwr_viz_daten,
    mapping = aes(x = garea)
    ) +
    geom_histogram(binwidth = 1000)

Numerische Variablen: Histogram

Histogram: binwidth

binwidth ist wichtig: Wie breit sind die bins (Eimer) in der die Verteilung dargestellt wird

ggplot(
    data = gwr_viz_daten,
    mapping = aes(x = garea)
    ) +
    geom_histogram(binwidth = 100)

Histogram: binwidth

Numerische Variablen: Density

ggplot(
    data = gwr_viz_daten,
    mapping = aes(x = garea)
    ) +
    geom_density()

Numerische Variablen: Density

Zusammenhänge visualisieren

Numerische und kategoriale Variable

Side-by-side Boxplots:

Wickham, Çetinkaya-Rundel, and Grolemund (2023), Figure 1.1

Numerische und kategoriale Variable: Boxplots

Gebäudefläche pro Gemeinde

ggplot(
    data = gwr_viz_daten,
    mapping = aes(x = ggdename, y = garea)
    ) +
    geom_boxplot()

Numerische und kategoriale Variable: Boxplots

Numerische und kategoriale Variable: Density Plots

Gebäudeflächen pro Gemeinde

ggplot(
    data = gwr_viz_daten,
    mapping = aes(x = garea, fill = ggdename, color = ggdename)
    ) +
    geom_density(alpha = 0.5)
  1. alpha ist die Transparenz (zwischen 0 und 1), welche nun für das Density-Geom bei 0.5 liegt

Numerische und kategoriale Variable: Density Plots

Zwei kategoriale Variablen: Bar Chart

ggplot(
    data = gwr_viz_daten,
    mapping = aes(x = ggdename, fill = factor(gkat))
    ) +
    geom_bar()

Zwei kategoriale Variablen: Bar Chart

Zwei kategoriale Variablen: Stacked Bars

ggplot(
    data = gwr_viz_daten,
    mapping = aes(x = ggdename, fill = factor(gkat))
    ) +
    geom_bar(position = "fill")
  1. position = "fill" ändert die Art, wie der Balken mit den Farben befüllt wird

Zwei kategoriale Variablen: Stacked Bars

Zwei numerische Variablen: Scatterplot

ggplot(
    data = gwr_viz_daten,
    mapping = aes(x = garea, y = gvol)
    ) +
    geom_point()

Zwei numerische Variablen: Scatterplot

Zwei numerische Variablen: Trendlinie

ggplot(
    data = gwr_viz_daten,
    mapping = aes(x = garea, y = gvol)
    ) +
    geom_smooth(stat = "smooth")

Zwei numerische Variablen: Trendlinie

Drei Variablen: In einer Visualisierung

Drei Variablen: Facets/ Subfigures

ggplot(
    data = gwr_viz_daten,
    mapping = aes(x = garea, y = gvol)
    ) +
    geom_point() +
    geom_smooth(method = "lm") +
    facet_wrap(~ggdename)

Drei Variablen: Facets/ Subfigures

Visualisierungen speichern

ggsave()

ggsave() speichert den letzten Plot, den ihr generiert habt, auf eurem Computer.

ggplot(
    data = gwr_viz_daten,
    mapping = aes(x = garea, y = gvol)
    ) +
    geom_point()

ggsave(
    "output/viz/area_volume_scatterplot.png",
    width = 12,
    height = 10,
    units = "cm")

KI Party Zeit

Bot time

Mit dem Vokabular, welches ihr jetzt kennt und mit was ihr wisst und herausfinden könnt über das GWR und die Informationen darin, nehmt euch 45 Minuten Zeit um:

  • eine Verteilung einer Variable zu visualisieren
  • einen Zusammenhang zwischen zwei Variablen zu visualisieren

Erstellt jeweils:

  • eine ansprechende Visualisierung
  • eine möglichst hässliche Visualisierung

Speichert die Visualisierungen

References

Wickham, Hadley, Mine Çetinkaya-Rundel, and Garrett Grolemund. 2023. R for Data Science (2e). https://r4ds.hadley.nz/.