Wahlergebnisse 2025

library(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.4     ✔ readr     2.1.5
✔ forcats   1.0.0     ✔ stringr   1.5.1
✔ ggplot2   3.5.1     ✔ tibble    3.2.1
✔ lubridate 1.9.3     ✔ tidyr     1.3.1
✔ purrr     1.0.2     
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(geojsonio)
Registered S3 method overwritten by 'geojsonsf':
  method        from   
  print.geojson geojson

Attaching package: 'geojsonio'

The following object is masked from 'package:base':

    pretty
library(sf)
Linking to GEOS 3.10.2, GDAL 3.4.1, PROJ 8.2.1; sf_use_s2() is TRUE
library(paletteer)
library(ggthemes)
# https://github.com/linusha/wahlkreise-25-geometry/
if(!file.exists("germany-25-wahlkreise.geojson"))
    download.file("https://raw.githubusercontent.com/linusha/wahlkreise-25-geometry/refs/heads/main/germany-25-wahlkreise.geojson", "germany-25-wahlkreise.geojson")
wahlkreise_map <- geojson_read("germany-25-wahlkreise.geojson", what = "sp")
wahlkreise_sf <- st_as_sf(wahlkreise_map)
if(!file.exists("kerg2_00285.csv"))
    download.file("https://bundeswahlleiterin.de/bundestagswahlen/2025/ergebnisse/opendata/btw25/daten/kerg2_00285.csv", "kerg2_00285.csv")
kerg2 <- read_csv2("kerg2_00285.csv", skip = 9)
ℹ Using "','" as decimal and "'.'" as grouping mark. Use `read_delim()` for more control.
Rows: 15617 Columns: 19
── Column specification ────────────────────────────────────────────────────────
Delimiter: ";"
chr (9): Wahlart, Gebietsart, Gebietsnummer, Gebietsname, UegGebietsart, Ueg...
dbl (8): Gruppenreihenfolge, Stimme, Anzahl, Prozent, VorpAnzahl, VorpProzen...
num (1): Wahltag
lgl (1): Bemerkung

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
laender <- kerg2 |>
    filter(Gebietsart == "Land") |>
    select(Gebietsnummer, Gebietsname) |>
    unique() |>
    mutate(OstWest = case_when(Gebietsname %in% c("Brandenburg", "Mecklenburg-Vorpommern", "Sachsen", "Sachsen-Anhalt", "Thüringen") ~ "Ost",
    Gebietsname == "Berlin" ~ "Berlin",
    .default = "West"))
afd_zweit <- kerg2 |>
    filter(Gruppenname == "AfD" & Gebietsart == "Wahlkreis" & Stimme == 2) |>
    mutate(WKR_NR = as.integer(Gebietsnummer)) |>
    select(WKR_NR, Anzahl, Prozent, UegGebietsnummer)
wahlkreise_sf |>
    inner_join(afd_zweit, by = "WKR_NR") |>
    ggplot() +
    geom_sf(aes(fill = Prozent)) +
    labs(title = "Zweitstimmenergebnis der AfD") +
    scale_fill_paletteer_c("ggthemes::Brown")

symbol_pos <- st_centroid(wahlkreise_sf) |>
    inner_join(afd_zweit, by = "WKR_NR")
Warning: st_centroid assumes attributes are constant over geometries
wahlkreise_sf  |>
    ggplot() +
    geom_sf() +
    geom_sf(data = symbol_pos, aes(size = Anzahl, colour = Prozent)) +
    scale_size(range = c(1, 5)) +
    labs(title = "Zweitstimmenergebnis der AfD") +
    scale_colour_paletteer_c("ggthemes::Brown")

afd_zweit |>
    inner_join(laender, by = c(UegGebietsnummer = "Gebietsnummer")) |>
    ggplot(aes(Prozent, fill = Gebietsname)) +
    geom_histogram(breaks = 0:50) +
    scale_fill_paletteer_d("ggthemes::Tableau_20")

afd_zweit |>
    inner_join(laender, by = c(UegGebietsnummer = "Gebietsnummer")) |>
    ggplot(aes(Prozent, fill = OstWest)) +
    geom_histogram(breaks = 0:50) +
    scale_fill_paletteer_d("ggthemes::Tableau_10") +
    labs(title = "Zweitstimmenergebnis der AfD")