Bump-Chart in R: Rangwechsel über die Zeit zeigen

R
ggplot2
Visualisierung
Wien
Autor:in

DI Dr. Johannes Hofrichter

Veröffentlichungsdatum

20. Juli 2026

Ein Bump-Chart verfolgt Ränge über die Zeit: Jede Linie ist ein Element, und ihre Höhe zeigt nicht den Wert, sondern den Platz in der Rangliste – ideal, um Auf- und Abstiege sichtbar zu machen.

Manchmal interessiert nicht die absolute Größe, sondern die Reihenfolge: Wer liegt vorn, wer überholt wen? Dafür ist der Bump-Chart gemacht. Er wirft die genauen Werte bewusst weg und zeigt nur den Platz in der Rangliste – die geschwungenen Linien machen jedes Überholmanöver sofort sichtbar. Der Preis dafür: Ob zwischen Rang eins und zwei ein Hauch oder eine Welt liegt, sieht man nicht mehr. Ich zeige das an den Top-8-Vornamen für Neugeborene in Wien von 2014 bis 2023, getrennt nach Buben und Mädchen.

Die Daten

Die Daten stammen von der Stadt Wien (Vornamen Neugeborene, je Jahr eine eigene HTML-Seite). Es gibt keine fertige Datei zum Download, deshalb hole ich die HTML-Tabellen mit rvest direkt von den Jahresseiten und zerlege jede Seite in einen Block für Mädchen und einen für Buben.

Code: Daten laden
library(rvest)
library(dplyr)

years <- 2014:2023

parse_block <- function(tbl, cols, geschlecht, jahr) {
  block <- tbl[-1, cols]
  names(block) <- c("rang", "name", "anzahl", "anteil")
  block |>
    mutate(
      geschlecht = geschlecht,
      jahr       = jahr,
      rang       = suppressWarnings(as.integer(rang)),
      name       = trimws(name),
      anzahl     = suppressWarnings(as.integer(gsub("\\.", "", anzahl)))
    ) |>
    filter(!is.na(rang), rang <= 15)
}

scrape_year <- function(y) {
  url <- paste0(
    "https://www.wien.gv.at/statistik/bevoelkerung/vornamen/vornamen",
    y, ".html"
  )
  tbls <- html_table(read_html(url), fill = TRUE)
  tbl  <- tbls[[1]]
  # Erste Tabelle: Spalten 1-4 = Mädchen, 5-8 = Buben (verifiziert 2026)
  if (ncol(tbl) >= 8) {
    bind_rows(
      parse_block(tbl, 1:4, "Mädchen", y),
      parse_block(tbl, 5:8, "Buben",   y)
    )
  }
}

vornamen_raw <- bind_rows(lapply(years, function(y) {
  Sys.sleep(0.4)
  scrape_year(y)
}))

Aufbereiten

Für ein lesbares Bild verfolge ich nur jene Namen, die im letzten Jahr (2023) in den Top 8 standen, dafür über alle Jahre hinweg. So bleiben die Linien zusammenhängend und das Diagramm übersichtlich. Übrig bleibt das Objekt vornamen mit Geschlecht, Jahr, Rang und Name.

Code: Daten aufbereiten
# Namen, die im letzten Jahr in den Top 8 standen – über alle Jahre verfolgen
focus_names <- vornamen_raw |>
  filter(jahr == max(jahr), rang <= 8) |>
  select(geschlecht, name) |>
  distinct()

vornamen <- vornamen_raw |>
  inner_join(focus_names, by = c("geschlecht", "name")) |>
  filter(rang <= 8) |>
  arrange(geschlecht, jahr, rang) |>
  select(geschlecht, jahr, rang, name)

Die Grafik

Den geschwungenen Verlauf erzeugt geom_bump() aus dem Paket ggbump; geom_point() setzt die Knoten je Jahr. Mit endpoints extrahiere ich die letzte Position jeder Linie und beschrifte sie rechts mit dem Namen. scale_y_reverse() dreht die Achse um, damit Rang 1 oben liegt, und facet_wrap() stellt Buben und Mädchen nebeneinander. Das dunkle Theme mit Navy-Hintergrund und goldener Schrift gibt der Grafik den Look der Website.

Code: Grafik
endpoints <- vornamen |>
  group_by(geschlecht) |>
  filter(jahr == max(jahr)) |>
  ungroup()

navy      <- "#1B365D"
gold_hell <- "#E9C46A"

ggplot(vornamen, aes(x = jahr, y = rang, colour = name)) +
  geom_bump(linewidth = 2, smooth = 8, alpha = 0.9) +
  geom_point(size = 3.6) +
  geom_text(
    data = endpoints, aes(label = name),
    hjust = 0, nudge_x = 0.18, size = 4.4, fontface = "bold",
    colour = gold_hell
  ) +
  facet_wrap(~ geschlecht, ncol = 2, scales = "free_y") +
  scale_y_reverse(breaks = 1:8) +
  scale_x_continuous(
    breaks = seq(2014, 2022, 2),
    limits = c(2014, 2023 + 2.2), expand = c(0.02, 0)
  ) +
  scale_colour_manual(
    values = colorRampPalette(
      RColorBrewer::brewer.pal(8, "Set2")
    )(n_distinct(vornamen$name))
  ) +
  guides(colour = "none") +
  labs(
    title    = "Rangwechsel der Top-Vornamen in Wien",
    subtitle = "Top 8 der beliebtesten Vornamen, Buben und Mädchen, 2014–2023",
    x        = NULL,
    y        = "Rang (1 = häufigster Name)",
    caption  = "Daten: Stadt Wien, Vornamen Neugeborene (CC-BY 4.0)."
  ) +
  theme_minimal(base_size = 12) +
  theme(
    plot.background    = element_rect(fill = navy, colour = NA),
    panel.background   = element_rect(fill = navy, colour = NA),
    plot.title         = element_text(face = "bold", size = 20, colour = gold_hell),
    plot.subtitle      = element_text(colour = "grey80", margin = margin(b = 12)),
    plot.caption       = element_text(colour = "grey65", hjust = 0),
    strip.text         = element_text(face = "bold", size = 13, colour = gold_hell),
    axis.title         = element_text(colour = gold_hell),
    axis.text          = element_text(colour = "grey85"),
    axis.text.x        = element_text(size = 11, colour = "grey85"),
    panel.grid.minor   = element_blank(),
    panel.grid.major.x = element_blank(),
    panel.grid.major.y = element_line(colour = "grey30")
  )

Bump-Chart der Top-8-Vornamen für Neugeborene in Wien von 2014 bis 2023, getrennt nach Buben und Mädchen.

Was die Linien erzählen: Jede Linie ist ein Name, die Höhe sein Rang im jeweiligen Jahr, Rang 1 ganz oben. Kreuzen sich zwei Linien, hat ein Name den anderen überholt; eine flach oben verlaufende Linie ist ein Dauer-Favorit. Als Variante können Sie die Anzahl der verfolgten Namen erhöhen oder statt des Rangs den tatsächlichen Anteil auf die y-Achse legen – dann wird aus dem Bump-Chart ein klassisches Liniendiagramm.


Eigene Daten so darstellen?

Auch das Sammeln der Rohdaten per Web-Scraping gehört für mich zu einer vollständigen Datenanalyse – von der Quelle bis zur fertigen Grafik. Wenn Sie ggplot2 und ggbump selbst einsetzen möchten, zeige ich die Technik im Visualisierungskurs. Weitere moderne Diagrammtypen finden Sie im Ridgeline-Plot, im Raincloud-Plot und im Dumbbell-Chart.

Zurück nach oben