Vorbemerkungen

Dieses Dokument beschreibt die Vorprozessierung und explorative Analyse des Datensatzes, der Grundlage des auf srf.ch veröffentlichten Artikel So stark sind die Schweizer Städte nach links gerückt ist.

SRF Data legt Wert darauf, dass die Datenvorprozessierung und -Analyse nachvollzogen und überprüft werden kann. SRF Data glaubt an das Prinzip offener Daten, aber auch offener und nachvollziehbarer Methoden. Zum anderen soll es Dritten ermöglicht werden, auf dieser Vorarbeit aufzubauen und damit weitere Auswertungen oder Applikationen zu generieren.

Für die vorliegende Analyse erhielt SRF Data vom Schweizer Städteverband Daten zur Sitzverteilung in den Exekutiven und Legislativen der grossen Schweizer Städte. In diesem Script werden diese Daten zusammengeführt und entlang folgender Fragestellung ausgewertet: “Wie verschob sich das politische Kräfteverhältnis in den grossen Schweizer Städten in den vergangenen 25 Jahren?”.

Die Endprodukte des vorliegenden Scripts, neben der vorliegenden explorativen Analyse, sind (Datenbeschreibung siehe unten):

  • data_ex.Rda: Ein Datensatz mit der Sitzerverteilung in der Exekutive der grossen Schweizer Städte für die Jahr 1993 bis 2017. Für die zehn grössten Städte sind auch Daten für das Jahr 2018 enthalten.
  • data_leg.Rda: Ein Datensatz mit der Sitzerverteilung in der Legislative der grossen Schweizer Städte für die Jahr 1993 bis 2017. Für die zehn grössten Städte sind auch Daten für das Jahr 2018 enthalten.
  • diverse Visualisierungen

R-Script & Daten

R-Script & Daten

Die Vorprozessierung und Analyse wurde im Statistikprogramm R vorgenommen. Das zugrunde liegende Script sowie die prozessierten Daten können unter diesem Link heruntergeladen werden. Durch Ausführen von main.Rmd kann der hier beschriebene Prozess nachvollzogen und der für den Artikel verwendete Datensatz generiert werden. Dabei werden Daten aus dem Ordner input eingelesen und Ergebnisse in den Ordner output geschrieben.

SRF Data verwendet das rddj-template von Timo Grossenbacher als Grundlage für seine R-Scripts. Entstehen bei der Ausführung dieses Scripts Probleme, kann es helfen, die Anleitung von rddj-template zu studieren.

Debug-Informationen: This report was generated on 2018-12-07 10:23:41. R version: 3.4.4 on x86_64-pc-linux-gnu. For this report, CRAN packages as of 2018-01-01 were used.

GitHub

Der Code für die vorliegende Datenprozessierung ist auf https://github.com/srfdata/2018-07-linke-staedte zur freien Verwendung verfügbar.

Weitere Projekte

Code & Daten von SRF Data sind unter http://srfdata.github.io verfügbar.

Haftungsausschluss

Die veröffentlichten Informationen sind sorgfältig zusammengestellt, erheben aber keinen Anspruch auf Aktualität, Vollständigkeit oder Richtigkeit. Es wird keine Haftung übernommen für Schäden, die durch die Verwendung dieses Scripts oder der daraus gezogenen Informationen entstehen. Dies gilt ebenfalls für Inhalte Dritter, die über dieses Angebot zugänglich sind.

Originalquelle

Originalquelle sind Daten, die der Schweizer Städteverband SRF Data zur Verfügung stellte. Die Daten umfassen die Sitzverteilungen in den Exekutiven und Legislativen grosser Schweizer Städte für die Jahre 1993 bis 2017.

Vorbereitungen

## [1] "package package:rmarkdown detached"

Packages definieren

# von https://mran.revolutionanalytics.com/web/packages/checkpoint/vignettes/using-checkpoint-with-knitr.html
# alle Packages, die nicht gebraucht werden,
# können hier entfernt werden (auskommentieren reicht nicht!)
# Wichtig: wenn neues Package installiert werden soll,
# scanForPackages = T setzen im checkpoint() call im nächsten Chunk
cat(
  "
library(rstudioapi)
library(tidyverse) # ggplot2, dplyr, tidyr, readr, purrr, tibble
library(magrittr) # pipes
library(stringr) # string manipulation
library(readxl) # excel
library(scales) # scales for ggplot2
library(jsonlite) # json
library(forcats) # easier factor handling,
library(lintr) # code linting, auf keinen Fall entfernen ;-)
library(sp) # spatial data handling
library(rgeos) # spatial data handling
library(rgdal) # spatial data handling
library(styler) # code formatting
library(googlesheets) # googlesheets (replace with tidyverse/googlesheets4 asap)
library(rmarkdown) # muss für automatisches knitting 
# in deploy.sh eingebunden werden",
  file = "manifest.R"
)

Packages installieren

# if checkpoint is not yet installed, install it (for people using this
# system for the first time)
if (!require(checkpoint)) {
  if (!require(devtools)) {
    install.packages("devtools", repos = "http://cran.us.r-project.org")
    require(devtools)
  }
  devtools::install_github("RevolutionAnalytics/checkpoint",
                           ref = "v0.3.2", # could be adapted later,
                           # as of now (beginning of July 2017
                           # this is the current release on CRAN)
                           repos = "http://cran.us.r-project.org")
  require(checkpoint)
}
## Loading required package: checkpoint
## 
## checkpoint: Part of the Reproducible R Toolkit from Microsoft
## https://mran.microsoft.com/documents/rro/reproducibility/
# nolint start
if (!dir.exists("~/.checkpoint")) {
  dir.create("~/.checkpoint")
}
# nolint end
# install packages for the specified CRAN snapshot date
checkpoint(snapshotDate = package_date,
           project = path_to_wd,
           verbose = T,
           scanForPackages = T,
           use.knitr = F,
           R.version = R_version)
## Scanning for packages used in this project
## rmarkdown files found and will not be parsed. Set use.knitr = TRUE
## - Discovered 16 packages
## All detected packages already installed
## checkpoint process complete
## ---
rm(package_date)

Packages laden

source("manifest.R")
## ── Attaching packages ────────────────────────────────── tidyverse 1.2.1 ──
## ✔ ggplot2 2.2.1     ✔ purrr   0.2.4
## ✔ tibble  1.4.1     ✔ dplyr   0.7.4
## ✔ tidyr   0.7.2     ✔ stringr 1.2.0
## ✔ readr   1.1.1     ✔ forcats 0.2.0
## ── Conflicts ───────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## 
## Attaching package: 'magrittr'
## The following object is masked from 'package:purrr':
## 
##     set_names
## The following object is masked from 'package:tidyr':
## 
##     extract
## 
## Attaching package: 'scales'
## The following object is masked from 'package:purrr':
## 
##     discard
## The following object is masked from 'package:readr':
## 
##     col_factor
## 
## Attaching package: 'jsonlite'
## The following object is masked from 'package:purrr':
## 
##     flatten
## rgeos version: 0.3-26, (SVN revision 560)
##  GEOS runtime version: 3.6.2-CAPI-1.10.2 4d2925d6 
##  Linking to sp version: 1.2-5 
##  Polygon checking: TRUE
## rgdal: version: 1.2-16, (SVN revision 701)
##  Geospatial Data Abstraction Library extensions to R successfully loaded
##  Loaded GDAL runtime: GDAL 2.2.3, released 2017/11/20
##  Path to GDAL shared files: /usr/share/gdal/2.2
##  GDAL binary built with GEOS: TRUE 
##  Loaded PROJ.4 runtime: Rel. 4.9.3, 15 August 2016, [PJ_VERSION: 493]
##  Path to PROJ.4 shared files: (autodetected)
##  Linking to sp version: 1.2-5
unlink("manifest.R")
sessionInfo()
## R version 3.4.4 (2018-03-15)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 18.04.1 LTS
## 
## Matrix products: default
## BLAS: /opt/R/R-3.4.4/lib64/R/lib/libRblas.so
## LAPACK: /opt/R/R-3.4.4/lib64/R/lib/libRlapack.so
## 
## locale:
##  [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
##  [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
##  [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
##  [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
##  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
## [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] rmarkdown_1.8      googlesheets_0.2.2 styler_1.0.0      
##  [4] rgdal_1.2-16       rgeos_0.3-26       sp_1.2-5          
##  [7] lintr_1.0.2        jsonlite_1.5       scales_0.5.0      
## [10] readxl_1.0.0       magrittr_1.5       forcats_0.2.0     
## [13] stringr_1.2.0      dplyr_0.7.4        purrr_0.2.4       
## [16] readr_1.1.1        tidyr_0.7.2        tibble_1.4.1      
## [19] ggplot2_2.2.1      tidyverse_1.2.1    rstudioapi_0.7    
## [22] checkpoint_0.4.0  
## 
## loaded via a namespace (and not attached):
##  [1] reshape2_1.4.3   haven_1.1.0      lattice_0.20-35  colorspace_1.3-2
##  [5] htmltools_0.3.6  yaml_2.1.16      rlang_0.1.6      pillar_1.0.1    
##  [9] foreign_0.8-69   glue_1.2.0       modelr_0.1.1     bindrcpp_0.2    
## [13] bindr_0.1        plyr_1.8.4       munsell_0.4.3    gtable_0.2.0    
## [17] cellranger_1.1.0 rvest_0.3.2      psych_1.7.8      evaluate_0.10.1 
## [21] knitr_1.18       rex_1.1.2        parallel_3.4.4   broom_0.4.3     
## [25] Rcpp_0.12.14     backports_1.1.2  mnormt_1.5-5     hms_0.4.0       
## [29] digest_0.6.13    stringi_1.1.6    grid_3.4.4       rprojroot_1.3-1 
## [33] cli_1.0.0        tools_3.4.4      lazyeval_0.2.1   crayon_1.3.4    
## [37] pkgconfig_2.0.1  xml2_1.1.1       lubridate_1.7.1  assertthat_0.2.0
## [41] httr_1.3.1       R6_2.2.2         nlme_3.1-131.1   compiler_3.4.4
rm(list = ls(all.names = TRUE))

Zusätzliche Scripts laden

# falls Logik auf andere Scripts ausgelagert werden soll (z.B. der Übersichtlichkeit halber), hier einkommentieren
knitr::read_chunk("scripts/my_script.R")
source("scripts/my_script.R")

Exekutive

Daten einlesen

Es wird ein Datensatz namens “data_ex_raw” erstellt, der die (ungesäuberten) Rohdaten für die Stadtregierungen (Exekutive) beinhaltet. Der Datensatz wird anschliessend im Ordner “Output” als Rda gespeichert.

amt <- "Exekutive"
data_ex_raw <- data.frame()

### Datenstruktur 1: 1993-1997, 1999
temp <- c(1993:1997, 1999)
for (i in temp) {
  loop <- read_excel(
    paste(
      "input/ssv/Politdaten_",
      i,
      ".xls",
      sep = ""
    ),
    sheet = 2,
    range = anchored("B11", 
                     dim = c(NA, NA))
  )
  loop %<>%
    select(1, 4, 7, 9, 11, 13, 15, 17, 19, 21:23, 25) %>%
    filter(!is.na(Alle) &
      !X__1 == "davon Frauen" &
      !X__1 == "dont femmes") %>%
    slice(3:n()) %>%
    mutate(year = i, amt = amt)
  data_ex_raw %<>%
    bind_rows(loop)
}


### Datenstruktur 2: 1998
temp <- c(1998)
for (i in temp) {
  loop <- read_excel(
    paste(
      "input/ssv/Politdaten_",
      i,
      ".xls",
      sep = ""
    ),
    sheet = 2,
    range = anchored("B11", dim = c(NA, NA))
  )
  loop %<>%
    select(1, 4, 7, 9, 11, 13,15,17,19,21:23) %>%
        filter(!is.na(Alle) &
      !X__1 == "davon Frauen" &
      !X__1 == "dont femmes") %>%
    slice(3:n()) %>%
    mutate(year = i, amt = amt)
  data_ex_raw %<>%
    bind_rows(loop)
}


### Datenstruktur 3: 2000
temp <- c(2000)
for (i in temp) {
  loop <- read_excel(
    paste(
      "input/ssv/Politdaten_",
      i,
      ".xls",
      sep = ""
    ),
    sheet = 2,
    range = anchored("A5", dim = c(NA, NA))
  )
  loop %<>%
    select(1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23) %>%
    filter(!is.na(Alle) &
      !X__1 == "davon Frauen" &
      !X__1 == "dont femmes") %>%
    slice(2:n()) %>%
    mutate(year = i, amt = amt)
  data_ex_raw %<>%
    bind_rows(loop)
}

### Datenstruktur 4: 2001-2004
temp <- c(2001:2004)
for (i in temp) {
  loop <- read_excel(
    paste(
      "input/ssv/Politdaten_",
      i,
      ".xls",
      sep = ""
    ),
    sheet = 2,
    range = anchored("B11", dim = c(NA, NA))
  )
  loop %<>%
    select(1, 4, 7, 9, 11, 13, 15, 17, 19:21, 23) %>%
    filter(!is.na(Alle) &
      !X__1 == "davon Frauen" &
      !X__1 == "dont femmes") %>%
    slice(3:n()) %>%
    mutate(year = i, amt = amt)
  data_ex_raw %<>%
    bind_rows(loop)
}

### Datenstruktur 5: 2005-2008
temp <- c(2005:2008)
for (i in temp) {
  loop <- read_excel(
    paste(
      "input/ssv/Politdaten_",
      i,
      ".xls",
      sep = ""
    ),
    sheet = 3,
    range = anchored("A10", dim = c(NA, NA))
  )
  loop %<>%
    select(1, 2, 6, 8, 10, 12, 14, 16, 18, 20) %>%
    filter(!is.na(.[[2]])) %>%
    rename(
      Alle = "Alle Parteien / Ensemble des partis",
      FDP = "FDP / PRD",
      CVP = "CVP / PDC",
      SPS = "SPS / PS",
      SVP = "SVP / UDC",
      LPS = "LPS / PLS",
      EVP = "EVP / PEP",
      GPS = "GPS / PES",
      other = "Übrige Parteien / Autres partis"
    ) %>%
    slice(2:n()) %>%
    mutate(year = i, amt = amt)
  data_ex_raw %<>%
    bind_rows(loop)
}

### Datenstruktur 6: 2009
temp <- c(2009)
for (i in temp) {
  loop <- read_excel(
    paste(
      "input/ssv/Politdaten_",
      i,
      ".xls",
      sep = ""
    ),
    sheet = 3,
    range = anchored("A9", dim = c(NA, NA))
  )
  loop %<>%
    select(1, 2, 6, 8, 10, 12, 14, 16, 18, 20, 22) %>%
    filter(!is.na(.[[2]])) %>%
    rename(
      Alle = "Alle Parteien / Ensemble des partis",
      FDP = "FDP / PRL",
      CVP = "CVP / PDC",
      SPS = "SPS / PS",
      SVP = "SVP / UDC",
      EVP = "EVP / PEP",
      BDP = "BDP / PBD",
      GPS = "GPS / PES",
      GLP = "GLP / PVL",
      other = "Übrige Parteien / Autres partis"
    ) %>%
    slice(2:n()) %>%
    mutate(year = i, amt = amt)
  data_ex_raw %<>%
    bind_rows(loop)
}

### Datenstruktur 7: 2010-2012, 2014
temp <- c(2010:2012, 2014)
for (i in temp) {
  loop <- read_excel(
    paste(
      "input/ssv/Politdaten_",
      i,
      ".xlsx",
      sep = ""
    ),
    sheet = 3,
    range = anchored("A10", dim = c(NA, NA))
  )
  loop %<>%
    select(1, 2, 6, 8, 10, 12, 14, 16, 18, 20, 22) %>%
    filter(!is.na(.[[2]])) %>%
    rename(
      Alle = "Alle Parteien / Ensemble des partis",
      FDP = "FDP / PRD",
      CVP = "CVP / PDC",
      SPS = "SPS / PS",
      SVP = "SVP / UDC",
      EVP = "EVP / PEP",
      BDP = "BDP / PBD",
      GPS = "GPS / PES",
      GLP = "GLP / PVL",
      other = "Übrige Parteien / Autres partis"
    ) %>%
    slice(2:n()) %>%
    mutate(year = i, amt = amt)
  data_ex_raw %<>%
    bind_rows(loop)
}

### Datenstruktur 8: 2013
temp <- c(2013)
for (i in temp) {
  loop <- read_excel(
    paste(
      "input/ssv/Politdaten_",
      i,
      ".xlsx",
      sep = ""
    ),
    sheet = 2,
    range = anchored("A1", dim = c(NA, NA))
  )
  loop %<>%
    select(1, 2, 6, 8, 10, 12, 14, 16, 18, 20, 22) %>%
    filter(!is.na(.[[2]])) %>%
    rename(
      Alle = "Alle Parteien / Ensemble des partis",
      FDP = "FDP / PRD",
      CVP = "CVP / PDC",
      SPS = "SPS / PS",
      SVP = "SVP / UDC",
      EVP = "EVP / PEP",
      BDP = "BDP / PBD",
      GPS = "GPS / PES",
      GLP = "GLP / PVL",
      other = "Übrige Parteien / Autres partis"
    ) %>%
    slice(2:n()) %>%
    mutate(year = i, amt = amt)
  data_ex_raw %<>%
    bind_rows(loop)
}

### Datenstruktur 9: 2015
temp <- c(2015)
for (i in temp) {
  loop <- read_excel(
    paste(
      "input/ssv/Politdaten_",
      i,
      ".xlsx",
      sep = ""
    ),
    sheet = 3,
    range = anchored("A10", dim = c(NA, NA))
  )
  loop %<>%
    select(1, 2, 6, 8, 10, 12, 14, 16, 18, 20) %>%
    filter(!is.na(.[[2]])) %>%
    rename(
      Alle = "Alle Parteien / Ensemble des partis",
      FDP = "FDP / PRD",
      CVP = "CVP / PDC",
      SPS = "SP / PS",
      SVP = "SVP / UDC",
      EVP = "EVP / PEV",
      BDP = "BDP / PBD",
      GPS = "GPS / PES",
      GLP = "GLP / PVL"
    ) %>%
    slice(2:n()) %>%
    mutate(year = i, amt = amt)
  data_ex_raw %<>%
    bind_rows(loop)
}

### Datenstruktur 10: 2016-2017
temp <- c(2016:2018)
for (i in temp) {
  loop <- read_excel(
    paste(
      "input/ssv/Politdaten_",
      i,
      ".xlsx",
      sep = ""
    ),
    sheet = 2,
    range = anchored("A3", dim = c(NA, NA))
  )
  loop %<>%
    select(1, 2, 6, 8, 10, 12, 14, 16, 18, 20) %>%
    filter(!is.na(.[[2]])) %>%
    rename(
      Alle = "Alle Parteien / Ensemble des partis",
      FDP = "FDP / PLR",
      CVP = "CVP / PDC",
      SPS = "SP / PS",
      SVP = "SVP / UDC",
      EVP = "EVP / PEV",
      BDP = "BDP / PBD",
      GPS = "GPS / PES",
      GLP = "GLP / PVL"
    ) %>%
    slice(3:n()) %>%
    mutate(year = i, amt = amt)
  data_ex_raw %<>%
    bind_rows(loop)
}
if (!dir.exists("output")) {
  dir.create("output")
}
save(data_ex_raw, file = "output/data_ex_raw.Rda")
rm(loop)

Daten säubern

Es wird ein Datensatz namens “data_ex” erstellt, der die gesäuberten Daten für die Stadtregierungen (Exekutive) beinhaltet. Zudem wird für jede Stadt die Population als Variable hinzugefügt. Der Datensatz wird anschliessend im Ordner “Output” als Rda gespeichert.

load("output/data_ex_raw.Rda")

# Bereich auswählen und Variable benennen
data_ex <- data_ex_raw %>%
  select(14, 1, 15, 2:13, 17, 16:20) %>%
  rename(city = X__1)

# Base version:
data_ex[data_ex == "-"] <- 0
data_ex[data_ex == "–"] <- 0
data_ex[is.na(data_ex)] <- 0
data_ex[data_ex == "…"] <- 0
data_ex[data_ex == ""] <- 0

# Fussnoten entfernen
data_ex %<>%
  mutate(
    FDP = str_replace_all(FDP, " #[^[:alpha:]]+", " "),
    CVP = str_replace_all(CVP, " #[^[:alpha:]]+", " "),
    SPS = str_replace_all(SPS, " #[^[:alpha:]]+", " "),
    SVP = str_replace_all(SVP, " #[^[:alpha:]]+", " "),
    LDU = str_replace_all(LDU, " #[^[:alpha:]]+", " "),
    LPS = str_replace_all(LPS, " #[^[:alpha:]]+", " "),
    EVP = str_replace_all(EVP, " #[^[:alpha:]]+", " "),
    SD = str_replace_all(SD, " #[^[:alpha:]]+", " "),
    GPS = str_replace_all(GPS, " #[^[:alpha:]]+", " "),
    FPS = str_replace_all(FPS, " #[^[:alpha:]]+", " "),
    BDP = str_replace_all(BDP, " #[^[:alpha:]]+", " "),
    GLP = str_replace_all(GLP, " #[^[:alpha:]]+", " "),
    other = str_replace_all(other, " #[^[:alpha:]]+", " "),
    Alle = str_replace_all(Alle, " #[^[:alpha:]]+", " "),
    city = str_replace_all(city, " ", ""),
    city = str_replace_all(city, "#[^[:alpha:]]+", ""),
    city = str_replace_all(city, "([^[:alpha:]])", "")
  )

# Schreibweise vereinheitlichen
data_ex %<>%
  mutate(city = str_replace_all(city, "[^[:alpha:]]", " "))

# Ersetze Namen in einer Funktion
beautify_municipality_names <- function(df) {
  df %>% mutate(
    # Aesch (BL)
    city = str_replace_all(city,
                           "AeschBL",
                           "Aesch (BL)"),
    # Affoltern am Albis
    city = str_replace_all(city,
                           "AffolternaA|AffolternamAlbis",
                           "Affoltern am Albis"),
    # Altdorf (UR)
    city = str_replace_all(city,
                           "AltdorfUR",
                           "Altdorf (UR)"),
    # Altstätten
    city = str_replace_all(city,
                           "AltstΣtten",
                           "Altstätten"),
    # Basel
    city = str_replace_all(city,
                           "BaselStadtkanton",
                           "Basel"),
    # Biel/Bienne
    city = str_replace_all(city,
                           "^Biel$|BielBienne",
                           "Biel/Bienne"),
    # Brig-Glis
    city = str_replace_all(city,
                           "BrigGlis",
                           "Brig-Glis"),
    # Buchs (SG)
    city = str_replace_all(city,
                           "BuchsSG",
                           "Buchs (SG)"),
    # Bülach
    city = str_replace_all(city,
                           "Bⁿlach",
                           "Bülach"),
    # Bussigny
    city = str_replace_all(city,
                           "BussignyprèsLausanne",
                           "Bussigny"),
    # Carouge
    city = str_replace_all(city,
                           "^Carouge$|CarougeGE",
                           "Carouge (GE)"),
    # Chêne-Bougeries
    city = str_replace_all(city,
                           "ChêneBougeries",
                           "Chêne-Bougeries"),
    # Duebendorf
    city = str_replace_all(city,
                           "Dbendorf|Dⁿbendorf",
                           "Dübendorf"),
    # Delemont
    city = str_replace_all(city,
                           "DelΘmont",
                           "Delémont"),
    # Ecublens (VD)
    city = str_replace_all(city,
                           "EcublensVD",
                           "Ecublens (VD)"),
    # Genf
    city = str_replace_all(city,
                           "Genve|GenΦve",
                           "Genève"),
    # Gossau (SG)
    city = str_replace_all(city,
                           "GossauSG",
                           "Gossau (SG)"),
    # Glarus
    city = str_replace_all(city,
                           "GlarusNord",
                           "Glarus"),
    # Illnau-Effretikon
    city = str_replace_all(city,
                           "IllnauEffretikon",
                           "Illnau-Effretikon"),
    # Kniz
    city = str_replace_all(city,
                           "Kniz",
                           "Köniz"),
    # Küsnacht (ZH)
    city = str_replace_all(city,
                           "^Küsnacht$|Kⁿsnacht|KüsnachtZH",
                           "Küsnacht (ZH)"),
    # Küssnacht (SZ)
    city = str_replace_all(city,
                           "KüssnachtSZ|KüssnachtAR",
                           "Küssnacht (SZ)"),
    # La Chaux-de-Fonds
    city = str_replace_all(city,
                           "ChauxdeFondsLa|LaChauxdeFonds",
                           "La Chaux-de-Fonds"),
    # La Tour-de-Peilz
    city = str_replace_all(city,
                           "LaTourdePeilz",
                           "La Tour-de-Peilz"),
    # Le Grand-Saconnex
    city = str_replace_all(city,
                           "LeGrandSaconnex",
                           "Le Grand-Saconnex"),
    # La Neuveville
    city = str_replace_all(city,
                           "NeuvevilleLa|LaNeuveville",
                           "La Neuveville"),
    # Oberwil (BL)
    city = str_replace_all(city,
                           "OberwilBL",
                           "Oberwil (BL)"),
    # La Tour-de-Peilz
    city = str_replace_all(city,
                           "TourdePeilzLa",
                           "La Tour-de-Peilz"),
    # LeGrandSaconnex
    city = str_replace_all(city,
                           "GrandSaconnexLe",
                           "Le Grand-Saconnex"),
    # Le Locle
    city = str_replace_all(city,
                           "LocleLe|LeLocle",
                           "Le Locle"),
    # Littau gehört seit 2009 zu Luzern und wird ignoriert
    # Münchenstein
    city = str_replace_all(city,
                           "Mⁿnchenstein",
                           "Münchenstein"),
    # Münsingen
    city = str_replace_all(city,
                           "Mⁿnsingen",
                           "Münsingen"),
    # Muri bei Bern
    city = str_replace_all(city,
                           "MuriBE|MuribeiBern",
                           "Muri bei Bern"),
    # Neuchâtel
    city = str_replace_all(city,
                           "Neuchtel|NeuchΓtel",
                           "Neuchâtel"),
    # Neuhausen am Rheinfall
    city = str_replace_all(city,
                           "NeuhausenaRheinfall|NeuhausenamRheinfall",
                           "Neuhausen am Rheinfall"),
    # Plan-les-Ouates
    city = str_replace_all(city,
                           "PlanlesOuates",
                           "Plan-les-Ouates"),
    # Rapperswil-Jona entstand 2007 aus Rapperswil und Jona, welches rund 
    # doppelt so gross war. Was machen wir also vor 2006? Wir lassen die
    # Frage für den Moment unbeantwortet, da wir es nicht genauer ansehen
    city = str_replace_all(city,
                           "RapperswilJona",
                           "Rapperswil-Jona"),
    # Reinach (BL)
    city = str_replace_all(city,
                           "ReinachBL",
                           "Reinach (BL)"),
    # Renens (VD)
    city = str_replace_all(city,
                           "^Renens$|RenensVD",
                           "Renens (VD)"),
    # Rüti (ZH)
    city = str_replace_all(city,
                           "RütiZH|RⁿtiZH",
                           "Rüti (ZH)"),
    # St. Gallen
    city = str_replace_all(city,
                           "StGallen",
                           "St. Gallen"),
    # St. Moritz
    city = str_replace_all(city,
                           "StMoritz",
                           "St. Moritz"),
    # Stäfa
    city = str_replace_all(city,
                           "StΣfa",
                           "Stäfa"),
    # Thônex
    city = str_replace_all(city,
                           "Thnex",
                           "Thônex"),
    # Val-de-Ruz
    city = str_replace_all(city,
                           "ValdeRuz",
                           "Val-de-Ruz"),
    # Val-de-Travers
    city = str_replace_all(city,
                           "ValdeTravers",
                           "Val-de-Travers"),
    # Villars-sur-Glâne
    city = str_replace_all(city,
                           "VillarssurGlâne",
                           "Villars-sur-Glâne"),
    # Wädenswil
    city = str_replace_all(city,
                           "WΣdenswil",
                           "Wädenswil"),
    # Wetzikon (ZH)
    city = str_replace_all(city,
                           "WetzikonZH",
                           "Wetzikon (ZH)"),
    # Wil (SG)
    city = str_replace_all(city,
                           "WilSG",
                           "Wil (SG)"),
    # Wohlen (AG)
    city = str_replace_all(city,
                           "WohlenAG",
                           "Wohlen (AG)"),
    # Yverdon-les-Bains
    city = str_replace_all(city,
                           "YverdonlesBains",
                           "Yverdon-les-Bains"),
    # Zürich
    city = str_replace_all(city,
                           "[[:cntrl:]]Zürich",
                           "Zürich"),
    city = str_replace_all(city,
                           "Zrich|Zⁿrich",
                           "Zürich")
  )
}

# Funktion anwenden
data_ex %<>%
  beautify_municipality_names()

# Übrige berechnen
data_ex %<>%
  mutate(others = as.numeric(.[[15]]) + 
           as.numeric(.[[16]]) + 
           as.numeric(.[[18]]), 
         na.rm = TRUE) %>%
  select(1:14, 17, 19:21)

# Summe überprüfen
data_ex %<>%
  mutate(all = as.numeric(FDP) +
    as.numeric(CVP) +
    as.numeric(SPS) +
    as.numeric(SVP) +
    as.numeric(LDU) +
    as.numeric(LPS) +
    as.numeric(EVP) +
    as.numeric(SD) +
    as.numeric(PDA) +
    as.numeric(GPS) +
    as.numeric(FPS) +
    as.numeric(BDP) +
    as.numeric(GLP) +
    as.numeric(others)) %>%
  mutate(diff = as.numeric(Alle) - all,
         others = others + diff) %>%
  select(-diff, -all) %>%
  filter(!Alle == 0)

data_ex %<>% 
  filter(!city == "AlleTous",
         !city == "SchweizSuisse")

save(data_ex, file = "output/data_ex.Rda")

load("output/data_ex.Rda")

bfs_municipalities <- read_excel(
  "input/su-d-01.02.03.06.xlsx",
  sheet = "2016",
  skip = 2
) %>%
  select(id_and_name = Region, population = Total) %>%
  # behalte nur Gemeinden, nicht Bezirke / Kantone
  filter(str_detect(id_and_name, "^\\.\\.\\.")) %>%
  # separiere Gemeinde ID und Name
  rowwise() %>%
  mutate(
    bfs_id = str_extract(id_and_name, "^\\.*\\d{4}"),
    # entferne Punkte und konvertiere in Zahl
    bfs_id = as.numeric(str_replace(bfs_id, "^\\.*", "")),
    name = str_replace(id_and_name, "^\\.*\\d{4} ", "")
  ) %>%
  select(-id_and_name)

# Daten um Anzahl Einwohner ergänzen
data_ex %<>%
  left_join(bfs_municipalities, by = c("city" = "name"))

Die folgenden Gemeinden fallen raus, weil sie fusioniert haben:

# Welche Städte konnten nicht zugeordnet werden?
knitr::kable(
  data_ex %>%
    filter(is.na(bfs_id)) %>%
    distinct(city)
)
city
Jona
Littau
RapperswilSG
# Entferne diese
data_ex %<>%
  filter(!is.na(bfs_id)) %>%
  arrange(desc(population, year))

Vollständigkeit visualisieren

In den nachfolgenden Plots wird der Übersicht halber die Vollständigkeit des Datensatzes visualisiert.

order <- data_ex %>%
  distinct(city) %>%
  unlist()


ggplot(
  data_ex %>%
    mutate(city = factor(city, levels = rev(order))),
  aes(
    x = year,
    y = city
  )
) +
  geom_point(color = "#1c9621") +
  scale_x_continuous(breaks = c(1998, 2005, 2015)) +
  theme(axis.text.y = element_text(size = 6))

Aargau Solothurn

# erstelle Tabelle mit BFS IDs und Kantonszugehörigkeit
cantons_lookup <- read_excel(
  "input/be-b-00.04-rgs-16.xls",
  sheet = "01.01.2016",
  skip = 16,
  col_names = FALSE
) %>%
  select(bfs_id = X__1, canton_id = X__3)

# Weil wir im oberen Data Frame nur eine ID haben, müssen wir noch die Namen
# aus dem zweiten Tabellenblatt einlesen
canton_names <- read_excel(
  "input/be-b-00.04-rgs-16.xls",
  sheet = "Synopsis_de",
  range = "C4:D29",
  col_names = FALSE
) %>%
  select(canton_id = X__1, canton = X__2)

# Hole Kantonsnamen rein via ID
cantons_lookup %<>%
  left_join(canton_names, by = "canton_id") %>%
  select(-canton_id)

# aufräumen
rm(canton_names)

# erstelle Data Frame mit Gemeinden in AG/SO
data_ag_so <- data_ex %>%
  left_join(cantons_lookup, by = "bfs_id") %>%
  filter(canton == "Aargau" | canton == "Solothurn") %>%
  arrange(desc(population), year)

order_ag_so <- data_ag_so %>%
  distinct(city) %>%
  unlist()

ggplot(
  data_ag_so %>%
    mutate(city = factor(city, levels = rev(order_ag_so))),
  aes(
    x = year,
    y = city
  )
) +
  geom_point(color = "#1c9621", size = 4) +
  scale_x_continuous(breaks = c(1998, 2005, 2015)) +
  labs(
    x = NULL,
    y = NULL,
    title = "Gemeinden in den Kantonen Aargau / Solothurn"
  )

# speichere für später Liste mit relevanten! Gemeinden (mit ausreichend Daten)
order_ag_so <- data_ag_so %>%
  filter(year == 2003) %>%
  distinct(city) %>%
  unlist()
ggplot(
  data_ex %>%
    left_join(cantons_lookup, by = "bfs_id") %>%
    mutate(city = factor(city, levels = rev(order))) %>%
    filter(canton == "Zürich" | canton == "Schaffhausen"),
  aes(
    x = year,
    y = city
  )
) +
  geom_point(color = "#1c9621", size = 4) +
  scale_x_continuous(breaks = c(1998, 2005, 2015)) +
  labs(
    x = NULL,
    y = NULL,
    title = "Gemeinden in den Kantonen Zürich / Schaffhausen"
  )

Plots vorbereiten

Die Daten werden für die Plots vorbereitet. U.a. werden die einzelnen Parteien einem Lager (Links, Rechts, Mitte) zugeteilt. Der Datensatz wird anschliessend im Ordner “Output” als “data_ex_plot.Rda” gespeichert.

lager_levels <- c("Rechte", "Sonstige", "Mitte", "Linke")
lager_colors <- c("#27A1A6", "#D9D9D9", "#B8B8B8", "#F1434A")

top_50 <- bfs_municipalities %>%
  ungroup() %>%
  top_n(50, wt = population) %>%
  arrange(desc(population))

data_ex_plot <- data_ex

# Einzelne Parteien einem politischen Lager zuordnen
data_ex_plot %<>%
  mutate(Linke = as.numeric(SPS)
  + as.numeric(GPS)
  + as.numeric(PDA)) %>%
  mutate(Mitte = as.numeric(CVP)
  + as.numeric(EVP)
  + as.numeric(BDP)
  + as.numeric(LDU)
  + as.numeric(GLP)) %>%
  mutate(Rechte = as.numeric(SVP)
  + as.numeric(FDP)
  + as.numeric(LPS)
  + as.numeric(FPS)
  + as.numeric(SD)) %>%
  mutate(Sonstige = as.numeric(Alle) - Linke - Rechte - Mitte)

# Datensatz für Plot 3 speichern
save(data_ex_plot, file = "output/data_ex_plot.Rda")

Plot 1: Sitzverteilung in den 50 grössten Schweizer Städten

Ein erster Plot soll zeigen, wie sich die Exekutive in den 50 grössten Schweizer Städten zwischen 1993 und 2017 zusammensetzte.

load("output/data_ex_plot.Rda")

# Datensatz transformieren, top 50 selektieren
data_ex_plot1 <- data_ex_plot

data_ex_plot1 %<>%
  select(year,
         city,
         population,
         Alle,
         Linke,
         Mitte,
         Rechte,
         Sonstige) %>%
  gather(
    lager,
    sitze,
    Linke:Sonstige
  )

# Sitzanteile berechnen
data_ex_plot1 %<>%
  mutate(
    anteil = as.numeric(sitze) / as.numeric(Alle) * 100,
    lager = factor(lager, levels = lager_levels)
  )

# Plot generieren
plot <- ggplot(
  data_ex_plot1 %>%
    filter(city %in% top_50$name),
  aes(
    x = year,
    y = anteil,
    fill = lager
  )
) +
  geom_area(position = "stack") +
  labs(x = "Jahr", 
       y = "Anteil", 
       title = "Exekutive: Sitzverteilung in den 50 grössten Städte\n(Kleinstparteien nicht kategorisiert)") +
  facet_wrap(~reorder(city, -population)) +
  scale_fill_manual(values = lager_colors) +
  theme_minimal()
plot

# Plot speichern
ggsave("output/plot_exekutive01.pdf", 
       width = 10, 
       height = 8)

Plot 2: Sitzverteilung in den 10 grössten Schweizer Städten (inkl. Kleinstparteien)

Weil viele kleinere Parteien (z.B. Lega) in der Kategorie “Sonstige” zusammengefasst werden, ist die Analyse noch zu unpräzise. Aus diesem Grund werden jene Kleinstparteien für die 10 grössten Städte manuell recherchiert und in einem Excel-File erfasst. Dieses File wird anschliessend eingelesen und mit den bestehenden Daten gemerged. Anschliessend wird die Entwicklung in den 10 grössten Städten als Plot ausgewiesen.

load("output/data_ex_plot.Rda")

# Vorbereiterer Datensatz für Sonstige ausspielen
#(nur für die 10 grössten Städte)
data_sonstige_ex <- data_ex_plot %>%
  select(year, city, others, population) %>%
  filter(city %in% top_50[1:10, ]$name)

write.csv(
  data_sonstige_ex,
  file = "output/sonstige_ex.csv",
  fileEncoding = "UTF-8"
)
rm(data_sonstige_ex)

# Datensatz mit Aufschlüsselung "sonstiger" Parteien einlesen
# (nur für die 10 grössten Städte)
data_ex_plot2 <- read_excel("input/sonstige_ex.xlsx") %>%
  # wandle Jahr in korrekten Datentyp um
  mutate(year = as.numeric(year)) %>%
  # ersetze alle NAs durch nullen (in allen Spalten)
  mutate_all(funs(replace(., is.na(.), 0))) %>%
  select(year, city, AL:Pop) %>%
  right_join(
    data_ex_plot,
    by = c("city", "year")
  ) %>%
  select(year, city, population, bfs_id, Alle:others, AL:Pop, Linke:Sonstige)

# Einzelne Parteien einem politischen Lager zuordnen
data_ex_plot2 %<>%
  mutate(Linke = as.numeric(SPS) +
    as.numeric(GPS) +
    as.numeric(PDA.y) +
    as.numeric(PDA.x) +
    as.numeric(AL) +
    as.numeric(Solidarite) +
    as.numeric(GB) +
    as.numeric(CSP) +
    as.numeric(JungesBern) +
    as.numeric(LinkeSonstiges) +
    as.numeric(Pop)) %>%
  mutate(Mitte = as.numeric(CVP) +
    as.numeric(EVP) +
    as.numeric(BDP) +
    as.numeric(DSP) +
    as.numeric(LDU.y) +
    as.numeric(LDU.x) +
    as.numeric(GLP)) %>%
  mutate(Rechte = as.numeric(SVP) +
    as.numeric(FDP) +
    as.numeric(LPS) +
    as.numeric(FPS.y) +
    as.numeric(FPS.x) +
    as.numeric(LEGA) +
    as.numeric(LP) +
    as.numeric(MCR) +
    as.numeric(BielerVolk) +
    as.numeric(Biel) +
    as.numeric(SD)) %>%
  mutate(Sonstige = as.numeric(Alle) - 
           Linke - Rechte - Mitte) %>%
  select(year, 
         city, population, 
         Alle, Linke, Mitte, 
         Rechte, Sonstige) %>%
  filter(!is.na(Sonstige)) %>%
  gather(
    lager,
    sitze,
    Linke:Sonstige
  ) %>%
  mutate(
    anteil = as.numeric(sitze) / as.numeric(Alle) * 100,
    lager = factor(lager, levels = lager_levels)
  )

# Plot generieren
plot <- ggplot(data_ex_plot2, aes(x = year, 
                                  y = anteil,
                                  fill = lager)) +
  geom_area(position = "stack") +
  labs(x = "Jahr",
       y = "Anteil",
       title = "Exekutive: Sitzverteilung in den 10 grössten Städte\n(Kleinstparteien kategorisiert)") +
  facet_wrap(~reorder(city, -population)) +
  scale_fill_manual(values = lager_colors) +
  theme_minimal()
plot

# Plot speichern
ggsave("output/plot_exekutive02.pdf",
       width = 10,
       height = 8)

Plot 3: Grösse der Stadt und Anteil der linken Parteien an der Stadtregierung

Vieles deutet daraufhin, dass linke Parteien vor allem in Regierungen grosser Städte stark sind.

# Jahr und politisches Lages auswählen
data_ex_plot3 <- anti_join(data_ex_plot1,
                           data_ex_plot2,
                           by = c("year",
                                  "city",
                                  "Alle",
                                  "population",
                                  "lager"))
data_ex_plot3 %<>%
  bind_rows(data_ex_plot2)

data_ex_plot4 <- subset(data_ex_plot3,
                        year == 2017 & lager == "Linke")

# Plot generieren
plot <- ggplot(data_ex_plot4,
               aes(x = population,
                   y = anteil)) +
  geom_point() +
  scale_x_continuous(trans = "log2") +
  labs(y = "Anteil der SP und Grünen in Prozent",
       x = "Population (log)",
       title = "Je grösser die Stadt, desto stärker links die Regierung") +
  theme_minimal()
plot

#Plot speichern
ggsave("output/plot_exekutive03.pdf",
       width = 10,
       height = 8)

Plot 4: Sitzverteilung in den 10 grössten Schweizer Städten (ungewichtet, mit Kleinstparteien)

# Städte nach Grösse sortieren
order <- data_ex_plot %>%
  distinct(city, .keep_all = TRUE) %>%
  arrange(desc(population)) %>%
  select(city) %>%
  unlist()

# Datensatz
data_ex_plot7 <- data_ex_plot3

data_ex_plot7 %<>%
  filter(city %in% order[1:10]) %>%
  spread(lager, anteil) %>%
  group_by(year) %>% 
  summarise(
      Linke = mean(Linke, na.rm = TRUE),
      Mitte = mean(Mitte, na.rm = TRUE),
      Rechte = mean(Rechte, na.rm = TRUE),
      Sonstige = mean(Sonstige, na.rm = TRUE)) %>% 
  gather(
    lager,
    anteil,
    2:5)

# Plot generieren
plot <- ggplot(data_ex_plot7,
               aes(x = year,
                   y = anteil,
                   color = lager)) +
  geom_line() +
  labs(y = "Anteil in Prozent",
       x = "Jahr",
       title = "Exekutive: Die 10 grössten Städte\n(ungewichtet, Kleinstparteien kategorisiert)") +
  theme_minimal()
plot

#Plot speichern
ggsave("output/plot_exekutive04.pdf", 
       width = 10,
       height = 8)

Legislative

Daten einlesen

Es wird ein Datensatz namens “data_leg_raw” erstellt, der die (ungesäuberten) Rohdaten für die Stadtparlamente (Legislative) beinhaltet. Der Datensatz wird anschliessend im Ordner “Output” als Rda gespeichert.

amt <- "Legislative"
data_leg_raw <- data.frame()

### Datenstruktur 1: 1993-1998
temp <- c(1993:1998)
for (i in temp) {
  loop <- read_excel(
    paste(
      "input/ssv/Politdaten_",
      i,
      ".xls",
      sep = ""
    ),
    sheet = 1,
    range = anchored("B11", dim = c(NA, NA))
  )
  loop %<>%
    select(1:3, 5, 7, 9, 11:13, 15:17, 19) %>%
    filter(!is.na(.[[2]]) &
      !.[[1]] == "davon Frauen" &
      !.[[1]] == "dont femmes") %>%
    slice(3:n()) %>%
    mutate(year = i, amt = amt)
  data_leg_raw %<>%
    bind_rows(loop)
}


### Datenstruktur 2: 1999
temp <- c(1999)
for (i in temp) {
  loop <- read_excel(
    paste(
      "input/ssv/Politdaten_",
      i,
      ".xls",
      sep = ""
    ),
    sheet = 1,
    range = anchored("B11", dim = c(NA, NA))
  )
  loop %<>%
    select(1:3, 5, 7, 9, 11:13, 15:17, 19) %>%
    filter(!is.na(.[[2]]) &
      !.[[1]] == "davon Frauen" &
      !.[[1]] == "dont femmes") %>%
    slice(3:n()) %>%
    mutate(year = i, amt = amt)
  data_leg_raw %<>%
    bind_rows(loop)
}

### Datenstruktur 3: 2000
temp <- c(2000)
for (i in temp) {
  loop <- read_excel(
    paste(
      "input/ssv/Politdaten_",
      i,
      ".xls",
      sep = ""
    ),
    sheet = 1,
    range = anchored("A5", dim = c(NA, NA))
  )
  loop %<>%
    select(1:2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22) %>%
    filter(!is.na(.[[2]]) &
      !.[[1]] == "davon Frauen" &
      !.[[1]] == "dont femmes") %>%
    slice(2:n()) %>%
    mutate(year = i, amt = amt)
  data_leg_raw %<>%
    bind_rows(loop)
}

### Datenstruktur 4: 2001-2004
temp <- c(2001:2004)
for (i in temp) {
  loop <- read_excel(
    paste(
      "input/ssv/Politdaten_",
      i,
      ".xls",
      sep = ""
    ),
    sheet = 1,
    range = anchored("B11", dim = c(NA, NA))
  )
  loop %<>%
    select(1:3, 5, 7, 9, 11:12, 14:16, 18) %>%
    filter(!is.na(.[[2]]) &
      !.[[1]] == "davon Frauen" &
      !.[[1]] == "dont femmes") %>%
    slice(3:n()) %>%
    mutate(year = i, amt = amt)
  data_leg_raw %<>%
    bind_rows(loop)
}

### Datenstruktur 5: 2005-2008
temp <- c(2005:2008)
for (i in temp) {
  loop <- read_excel(
    paste(
      "input/ssv/Politdaten_",
      i,
      ".xls",
      sep = ""
    ),
    sheet = 2,
    range = anchored("A10", dim = c(NA, NA))
  )
  loop %<>%
    select(1:2, 4, 6, 8, 10, 12, 14, 16, 18) %>%
    filter(!is.na(.[[2]]))  %>%
    rename(
      Alle = "Alle Parteien / Ensemble des partis",
      FDP = "FDP / PRD",
      CVP = "CVP / PDC",
      SPS = "SPS / PS",
      SVP = "SVP / UDC",
      LPS = "LPS / PLS",
      EVP = "EVP / PEP",
      GPS = "GPS / PES",
      other = "Übrige Parteien / Autres partis"
    ) %>%
    slice(2:n()) %>%
    mutate(year = i, amt = amt)
  data_leg_raw %<>%
    bind_rows(loop)
}


### Datenstruktur 6: 2009
temp <- c(2009)
for (i in temp) {
  loop <- read_excel(
    paste(
      "input/ssv/Politdaten_",
      i,
      ".xls",
      sep = ""
    ),
    sheet = 2,
    range = anchored("A9", dim = c(NA, NA))
  )
  loop %<>%
    select(1:2, 4, 6, 8, 10, 12, 14, 16, 18, 20) %>%
    filter(!is.na(.[[2]])) %>%
    rename(
      Alle = "Alle Parteien / Ensemble des partis",
      FDP = "FDP / PRL",
      CVP = "CVP / PDC",
      SPS = "SPS / PS",
      SVP = "SVP / UDC",
      EVP = "EVP / PEP",
      BDP = "BDP / PBD",
      GPS = "GPS / PES",
      GLP = "GLP / PVL",
      other = "Übrige Parteien / Autres partis"
    ) %>%
    slice(2:n()) %>%
    mutate(year = i, amt = amt)
  data_leg_raw %<>%
    bind_rows(loop)
}

### Datenstruktur 7: 2010-2011
temp <- c(2010:2011)
for (i in temp) {
  loop <- read_excel(
    paste(
      "input/ssv/Politdaten_",
      i,
      ".xlsx",
      sep = ""
    ),
    sheet = 2,
    range = anchored("A10", dim = c(NA, NA))
  )
  loop %<>%
    select(1:2, 4, 6, 8, 10, 12, 14, 16, 18, 20) %>%
    filter(!is.na(.[[2]])) %>%
    rename(
      Alle = "Alle Parteien / Ensemble des partis",
      FDP = "FDP / PRD",
      CVP = "CVP / PDC",
      SPS = "SPS / PS",
      SVP = "SVP / UDC",
      EVP = "EVP / PEP",
      BDP = "BDP / PBD",
      GPS = "GPS / PES",
      GLP = "GLP / PVL",
      other = "Übrige Parteien / Autres partis"
    ) %>%
    slice(2:n()) %>%
    mutate(year = i, amt = amt)
  data_leg_raw %<>%
    bind_rows(loop)
}

### Datenstruktur 8: 2012
temp <- c(2012)
for (i in temp) {
  loop <- read_excel(
    paste(
      "input/ssv/Politdaten_",
      i,
      ".xlsx",
      sep = ""
    ),
    sheet = 2,
    range = anchored("A10", dim = c(NA, NA))
  )
  loop %<>%
    select(1:2, 4, 6, 8, 10, 12, 14, 16, 18, 20) %>%
    filter(!is.na(.[[2]])) %>%
    rename(
      Alle = "Alle Parteien / Ensemble des partis",
      FDP = "FDP / PLR",
      CVP = "CVP / PDC",
      SPS = "SPS / PS",
      SVP = "SVP / UDC",
      EVP = "EVP / PEP",
      BDP = "BDP / PBD",
      GPS = "GPS / PES",
      GLP = "GLP / PVL",
      other = "Übrige Parteien / Autres partis"
    ) %>%
    slice(2:n()) %>%
    mutate(year = i, amt = amt)
  data_leg_raw %<>%
    bind_rows(loop)
}

### Datenstruktur 9: 2013
temp <- c(2013)
for (i in temp) {
  loop <- read_excel(
    paste(
      "input/ssv/Politdaten_",
      i,
      ".xlsx",
      sep = ""
    ),
    sheet = 1,
    range = anchored("A1", dim = c(NA, NA))
  )
  loop %<>%
    select(1:2, 4, 6, 8, 10, 12, 14, 16, 18, 20) %>%
    filter(!is.na(.[[2]])) %>%
    rename(
      Alle = "Alle Parteien / Ensemble des partis",
      FDP = "FDP / PLR",
      CVP = "CVP / PDC",
      SPS = "SPS / PS",
      SVP = "SVP / UDC",
      EVP = "EVP / PEP",
      BDP = "BDP / PBD",
      GPS = "GPS / PES",
      GLP = "GLP / PVL",
      other = "Übrige Parteien / Autres partis"
    ) %>%
    slice(2:n()) %>%
    mutate(year = i, amt = amt)
  data_leg_raw %<>%
    bind_rows(loop)
}

### Datenstruktur 10: 2014
temp <- c(2014)
for (i in temp) {
  loop <- read_excel(
    paste(
      "input/ssv/Politdaten_",
      i,
      ".xlsx",
      sep = ""
    ),
    sheet = 2,
    range = anchored("A10", dim = c(NA, NA))
  )
  loop %<>%
    select(1:2, 5, 7, 9, 11, 13, 15, 17, 19, 21) %>%
    filter(!is.na(.[[2]])) %>%
    rename(
      Alle = "Alle Parteien / Ensemble des partis",
      FDP = "FDP / PLR",
      CVP = "CVP / PDC",
      SPS = "SPS / PS",
      SVP = "SVP / UDC",
      EVP = "EVP / PEP",
      BDP = "BDP / PBD",
      GPS = "GPS / PES",
      GLP = "GLP / PVL",
      other = "Übrige Parteien / Autres partis"
    ) %>%
    slice(2:n()) %>%
    mutate(year = i, amt = amt)
  data_leg_raw %<>%
    bind_rows(loop)
}


### Datenstruktur 11: 2015
temp <- c(2015)
for (i in temp) {
  loop <- read_excel(
    paste(
      "input/ssv/Politdaten_",
      i,
      ".xlsx",
      sep = ""
    ),
    sheet = 2,
    range = anchored("A10", dim = c(NA, NA))
  )
  loop %<>%
    select(1:2, 5, 7, 9, 11, 13, 15, 17, 19) %>%
    filter(!is.na(.[[2]])) %>%
    rename(
      Alle = "Alle Parteien / Ensemble des partis",
      FDP = "FDP / PLR",
      CVP = "CVP / PDC",
      SPS = "SP / PS",
      SVP = "SVP / UDC",
      EVP = "EVP / PEV",
      BDP = "BDP / PBD",
      GPS = "GPS / PES",
      GLP = "GLP / PVL"
    ) %>%
    slice(2:n()) %>%
    mutate(year = i, amt = amt)
  data_leg_raw %<>%
    bind_rows(loop)
}


### Datenstruktur 12: 2016-2017
temp <- c(2016:2018)
for (i in temp) {
  loop <- read_excel(
    paste(
      "input/ssv/Politdaten_",
      i,
      ".xlsx",
      sep = ""
    ),
    sheet = 1,
    range = anchored("A3", dim = c(NA, NA))
  )
  loop %<>%
    select(1:2, 5, 7, 9, 11, 13, 15, 17, 19) %>%
    filter(!is.na(.[[2]])) %>%
    rename(
      Alle = "Alle Parteien / Ensemble des partis",
      FDP = "FDP / PLR",
      CVP = "CVP / PDC",
      SPS = "SP / PS",
      SVP = "SVP / UDC",
      EVP = "EVP / PEV",
      BDP = "BDP / PBD",
      GPS = "GPS / PES",
      GLP = "GLP / PVL"
    ) %>%
    slice(3:n()) %>%
    mutate(year = i, amt = amt)
  data_leg_raw %<>%
    bind_rows(loop)
}

#Das File Roh
save(data_leg_raw, file = "output/data_leg_raw.Rda")

rm(loop)

Daten säubern

Es wird ein Datensatz namens “data_leg” erstellt, der die gesäuberten Daten für die Stadtparlamente (Legislative) beinhaltet. Der Datensatz wird anschliessend im Ordner “Output” als Rda gespeichert.

load("output/data_leg_raw.Rda")

# Bereich auswählen und Variable benennen
data_leg <- data_leg_raw %>%
  select(14, 1, 15, 2:13, 17, 16:21) %>%
  rename(city = X__1) %>%
  mutate(city = paste(.[[2]],
                      .[[16]],
                      .[[18]],sep=""),
    city = str_replace_all(city, "NA", "")) %>%
  select(1, 18, 3:15, 17, 19:21)

# Base version:
data_leg[data_leg == "-"] <- 0
data_leg[data_leg == "–"] <- 0
data_leg[is.na(data_leg)] <- 0
data_leg[data_leg == "…"] <- 0
data_leg[data_leg == ""] <- 0
data_leg[data_leg == "."] <- 0
data_leg[data_leg == "..."] <- 0

# Fussnoten entfernen
data_leg %<>%
  mutate(
    FDP = str_replace_all(FDP, " #[^[:alpha:]]+", " "),
    CVP = str_replace_all(CVP, " #[^[:alpha:]]+", " "),
    SPS = str_replace_all(SPS, " #[^[:alpha:]]+", " "),
    SVP = str_replace_all(SVP, " #[^[:alpha:]]+", " "),
    LDU = str_replace_all(LDU, " #[^[:alpha:]]+", " "),
    LPS = str_replace_all(LPS, " #[^[:alpha:]]+", " "),
    EVP = str_replace_all(EVP, " #[^[:alpha:]]+", " "),
    SD = str_replace_all(SD, " #[^[:alpha:]]+", " "),
    GPS = str_replace_all(GPS, " #[^[:alpha:]]+", " "),
    FPS = str_replace_all(FPS, " #[^[:alpha:]]+", " "),
    BDP = str_replace_all(BDP, " #[^[:alpha:]]+", " "),
    GLP = str_replace_all(GLP, " #[^[:alpha:]]+", " "),
    other = str_replace_all(other, " #[^[:alpha:]]+", " "),
    Alle = str_replace_all(Alle, " #[^[:alpha:]]+", " "),
    city = str_replace_all(city, " ", ""),
    city = str_replace_all(city, "#[^[:alpha:]]+", ""),
    city = str_replace_all(city, "([^[:alpha:]])", "")
  )

# Leere Zeilen löschen
data_leg %<>% filter(!Alle == 0)

#others berechnen
data_leg %<>%
  mutate(others = as.numeric(.[[15]]) + as.numeric(.[[17]])) %>%
  select(-15,-17)

# Schreibweise vereinheitlichen
data_leg %<>%
  mutate(city = str_replace_all(city, "[^[:alpha:]]", " "))

# Ersetze seltsame Gemeindenamen durch schönere
data_leg %<>%
  beautify_municipality_names()

# Summe überprüfen
data_leg %<>%
  mutate(all = as.numeric(FDP) +
    as.numeric(CVP) +
    as.numeric(SPS) +
    as.numeric(SVP) +
    as.numeric(LDU) +
    as.numeric(LPS) +
    as.numeric(EVP) +
    as.numeric(SD) +
    as.numeric(PDA) +
    as.numeric(GPS) +
    as.numeric(FPS) +
    as.numeric(BDP) +
    as.numeric(GLP) +
    as.numeric(others)) %>%
  mutate(diff = as.numeric(Alle) - all) %>%
  mutate(others = others + diff) %>%
  select(-diff, -all) 

data_leg %<>% 
  filter(!city == "AlleTous",
         !city == "SchweizSuisse")

save(data_leg, file = "output/data_leg.Rda")

Plots vorbereiten

Die Daten werden für die Plots vorbereitet. U.a. werden die einzelnen Parteien einem Lager (Links, Rechts, Mitte) zugeteilt. Der Datensatz wird anschliessend im Ordner “Output” als “data_leg_plot.Rda” gespeichert.

load("output/data_leg.Rda")

# Um Einwohnerzahl ergänzen
data_leg_plot <- data_leg %>%
  left_join(bfs_municipalities, by = c("city" = "name"))

# Einzelne Parteien einem politischen Lager zuordnen
data_leg_plot %<>%
  mutate(Linke = as.numeric(SPS)
  + as.numeric(GPS)
  + as.numeric(PDA)) %>%
  mutate(Mitte = as.numeric(CVP)
  + as.numeric(EVP)
  + as.numeric(BDP)
  + as.numeric(LDU)
  + as.numeric(GLP)) %>%
  mutate(Rechte = as.numeric(SVP)
  + as.numeric(FDP)
  + as.numeric(LPS)
  + as.numeric(FPS)
  + as.numeric(SD)) %>%
  mutate(Sonstige = as.numeric(Alle) - Linke - Rechte - Mitte)

# Datensatz für Plot 3 speichern
save(data_leg_plot, file = "output/data_leg_plot.Rda")

Plot 1: Sitzverteilung in den 50 grössten Schweizer Städten

load("output/data_leg_plot.Rda")

# Datensatz transformieren
data_leg_plot1 <- data_leg_plot

data_leg_plot1 %<>%
  select(year, city, population, Alle, Linke:Sonstige) %>%
  gather(
    lager,
    sitze,
    Linke:Sonstige
  )

# Sitzanteile berechnen
data_leg_plot1 %<>%
  mutate(
    anteil = as.numeric(sitze) / as.numeric(Alle) * 100,
    lager = factor(lager, levels = lager_levels)
  )

# Plot generieren
plot <- ggplot(data_leg_plot1 %>%
    filter(city %in% top_50$name),
               aes(x = year,
                   y = anteil,
                   fill = lager)) +
  geom_area(position = "stack") +
  labs(x = "Jahr",
       y = "Anteil",
       title = "Legislative: Sitzverteilung in den 50 grössten Städte\n(Kleinstparteien nicht kategorisiert)") +
  facet_wrap(~reorder(city, -population)) +
  scale_fill_manual(values = lager_colors) +
  theme_minimal()
plot

# Plot speichern
ggsave("output/plot_legislative01.pdf",
       width = 10,
       height = 8)

Plot 2: Sitzverteilung in den 10 grössten Schweizer Städten (ungewichtet, mit Kleinstparteien)

load("output/data_leg_plot.Rda")

# Vorbereiterer Datensatz für Sonstige ausspielen (nur für die 10 grössten Städte). Für die 10 grössten Städte werden die Kategorie "Sonstige" manuell in einem Excel-File aufgeschlüsselt.
data_sonstige_leg <- data_leg_plot %>%
  select(year, city, others, population) %>%
  filter(city %in% order[1:10]) %>%
  write.csv(file = "output/sonstige_leg.csv",
            fileEncoding = "UTF-8")

rm(data_sonstige_leg)

# Das manuell erarbeitete File (nur für die 10 grössten Städte) wird nun eingelesen und mit dem bestehenden Datensatz data_leg_plot2 gemerged.
data_leg_plot2 <-
  read_excel("input/sonstige_leg.xlsx") %>%
  select(-diff) %>%
  # wandle Jahr in korrekten Datentyp um
  mutate(year = as.numeric(year)) %>%
  # ersetze alle NAs durch nullen (in allen Spalten)
   right_join(
    data_leg_plot,
    by = c("city", "year")
  ) %>%
  select(year, city, amt, population, Alle,
         Rechte.x:Sonstige.x, Linke.y:Sonstige.y) %>%
  mutate_all(funs(replace(., is.na(.), 0)))

# Die neuen Anteile der politischen Lager berechnen
data_leg_plot2 %<>%
  mutate(Linke = Linke.y + Linke.x,
         Mitte = Mitte.y + Mitte.x,
         Rechte = Rechte.y + Rechte.x,
         Sonstige = Sonstige.y - Linke.x - Mitte.x - Rechte.x) %>%
  select(year:population, Alle, Linke:Sonstige) %>%
  gather(
    lager,
    sitze,
    Linke:Sonstige
  ) %>%
  mutate(
    anteil = as.numeric(sitze) / as.numeric(Alle) * 100,
    lager = factor(lager, levels = lager_levels)
  )

#Die 50 grössten Städte auswählen und Datensatz für späteren Plot speichern
data_leg_plot2 %<>%
  filter(city %in% order[1:50])
data_leg_plot3 <- data_leg_plot2
data_leg_plot4 <- data_leg_plot2
data_leg_plot5 <- data_leg_plot2

#Plot generieren
data_leg_plot2 %<>%
  filter(city %in% order[1:10]) %>%
  spread(lager, anteil) %>%
  group_by(year) %>% 
  summarise(
      Linke = mean(Linke, na.rm = TRUE),
      Mitte = mean(Mitte, na.rm = TRUE),
      Rechte = mean(Rechte, na.rm = TRUE),
      Sonstige = mean(Sonstige, na.rm = TRUE)) %>% 
  gather(
    lager,
    anteil,
    Linke:Sonstige)

# Plot generieren
plot <- ggplot(data_leg_plot2,
               aes(x = year,
                   y = anteil,
                   color = lager)) +
  geom_line() +
  labs(y = "Anteil in Prozent",
       x = "Jahr",
       title = "Legislative: Die 10 grössten Städte\n(ungewichtet, Kleinstparteien kategorisiert)") +
  theme_minimal()
plot

#Plot speichern
ggsave("output/plot_legislative02.pdf",
       width = 10,
       height = 8)

Visualisierungen

Für die Visualisierung könnte es spannend sein, die Städte in einige wenige Kategorien zu untereteilen. Ein Ansatz wäre eine Art «Median». Wäre ein Stadtrat aus 2 Linken, 2 Mittigen und 3 Rechten zusammengesetzt, wäre der Median die Person in der Mitte: z.B. Links | Links | Mitte | Mitte | Rechts | Rechts | Rechts. Die Schwierigkeit ist hier naturgemäss die Gruppe «Sonstige». Wo reiht sie sich ein in dieser Idee?

data_ex_plot %<>%
  rowwise() %>%
  # wiederhole die Wörter Linke, Mitte, Rechte für jeden Sitz ein Mal
  mutate(median = c(
    rep("Linke", times = Linke),
    rep("Mitte", times = Mitte),
    rep("Sonstige", times = Mitte),
    rep("Rechte", times = Rechte)
  # und behalte dann nur jenen in der Mitte
  )[ceiling((Linke + Mitte + Sonstige + Rechte) / 2)])
# sort by size
order <- data_ex_plot %>%
  distinct(city, .keep_all = TRUE) %>%
  arrange(desc(population)) %>%
  select(city) %>%
  unlist()

all_years <- seq(
  min(data_ex_plot$year),
  max(data_ex_plot$year),
  1
)

data_ex_plot %<>%
  mutate(
    city = factor(city, levels = order)
  )

ggplot(
  data = data_ex_plot %>%
    # show biggest at top
    mutate(
      city = factor(city, levels = rev(levels(city)))
    ) %>%
    filter(
      # reduce to biggest 10
      city %in% order[1:10]
    ),
  aes(
    x = year,
    y = city,
    colour = median
  )
) +
  geom_point(shape = 19, size = 4) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 90)) +
  scale_x_continuous(breaks = all_years) +
  scale_colour_manual(values = c(
    "Linke" = "#f1434a",
    "Mitte" = "#b8b8b8",
    "Sonstige" = "#27A1A6",
    "Rechte" = "#d9d9d9"
  ))

Das Modell ist definitiv nicht das präzistest-mögliche! Es ergeben sich ganz konkret beispielsweise folgende Verzerrungen zugunsten der Linken/Mitte:

  • Renens, 1996: 3 Linke, 3 Rechte => Median = Linke
  • LaChauxdeFonds, 1997: 2 Linke, 1 Sonstige, 2 Rechte => Median = Sonstige
  • Dübendorf, 1998: 1 Linke, 2 Mitte, 3 Sonstige, 3 Rechte => Median = Sonstige
  • StGallen, 2017: 2 Linke, 1 Mitte, 1 Sonstige, 1 Rechts => Median = Mitte
  • Biel, 2006: 4 Linke, 2 Sonstige, 2 Rechte => Median = Linke
  • Luzern, 2007: 2 Linke, 1 Mitte, 1 Sonstige, 1 Rechte => Median = Mitte

Ein kurzes Wort zu Luzern: 2012 trat der parteilose Stadtpräsident und Bildungsdirektor Urs W. Studer (62) nach 16 Jahren im Amt zurück. Die NLZ schreibt: «In den 16 Jahren als Stadtpräsident hat der parteilose Studer Luzern geprägt. Aufgefordert, seine grössten Erfolge zu benennen, gibt sich der frühere liberale Grossrat, der mit der Stadtpräsidentenwahl 1996 aus seiner Partei ausgetreten war, bescheiden und spricht zuerst von seinem Stapi-Vorgänger Franz Kurzmeyer. «Ich gelte ja als sein politischer Ziehsohn», sagt Studer und erklärt: «Wir haben die gleiche Philosophie. Liberal bedeutet ein starkes Gemeinwesen, einen sozialen Staat.»

Ein kurzes Wort zu St.Gallen: 2013/14 ist die Linke tatsächlich aus der Regierung geflogen. Danach konnte sie 2015 und 2017 Sitze zurückerobern. 2017 ging ausserdem ein Sitz von der CVP an die GLP. Die Person der GLP (Sonja Lüthi) wird von Smartvote Links der Mitte eingeordnet. Als Mitglied der GLP ist sie in Umweltfragen grün, in Finanzfragen eher der FDP nah. Seit 2013 ist ausserdem ein Parteiloser Mitgleid der Exekutive. Er war politisch nicht aktiv vor seiner Wahl, was seine Verortung sehr schwer macht.

Ein kurzes Wort zu Biel: Die Stadt hatte wärend den Jahren 2005 bis 2013 tatsächlich 8 Mitglieder. Was zunächst wie ein Fehler aussieht, ist Konzept. So schrieb der Bund über die Reform: «Nach dem Willen des Gemeinderats zählt die Bieler Stadtregierung ab nächster Legislatur (ab 2014) wie in den meisten Schweizer Städten nur noch fünf statt acht Mitglieder. Heute leiten nur die vier hauptamtlichen Gemeinderäte eine Direktion. Die vier nebenamtlichen führen keine Dossiers, sind aber gleichermassen stimmberechtigt.» «Bei Pattsituationen konnte der Stadtpräsident den Stichentscheid fällen.» «Der mit acht Mitgliedern für eine Stadt sehr grosse Gemeinderat war bisher Garant dafür, dass die französischsprachige Minderheit eine angemessene Vertretung erhielt.» Die zwei Sonstigen die 2006 in Biel eingetragen sind, waren Mitglieder der stark rechten FPS (ehemals Autopartei). Es war also 4 Links gegen 4 Rechts (2 davon FDP).

Eine detailliertere Ansicht pro Stadt könnte eventuell zusätzliche Informationen liefern:

# filter
one_city_only <- data_ex_plot %>%
  filter(city == "Biel/Bienne") %>%
  arrange(year)

max_seats <- max(as.numeric(one_city_only$Alle))

# make list of vectors of repeated words
one_city_only %<>%
  split(1:nrow(one_city_only)) %>%
  map(function(row) {
    # because we can not create a data frame with unequal vector lengths
    # we need to fill them up with NAs
    fill_with_NA <- rep(
      NA,
      max_seats - row$Linke - row$Mitte - row$Rechte - row$Sonstige
    )
    c(
      rep("Linke", times = row$Linke),
      rep("Mitte", times = row$Mitte),
      rep("Sonstige", times = row$Sonstige),
      rep("Rechte", times = row$Rechte),
      fill_with_NA
    )
  }) %>%
  # convert to data frame
  as.data.frame()

# re assign years as column names
names(one_city_only) <- t(data_ex_plot %>%
  distinct(year) %>%
  arrange(year))

# make tidy 
one_city_only %<>%
  gather(year, seat) %>%
  mutate(
    # convert to factor with specific order (levels)
    seat = factor(seat, levels = c(lager_levels, "Vakant")),
    # convert to correct data type
    year = as.numeric(year)
  ) %>%
  group_by(year) %>%
  mutate(
    n = row_number()
  ) %>%
  ungroup()
## Warning: attributes are not identical across measure variables;
## they will be dropped
ggplot(
  data = one_city_only,
  aes(
    x = year,
    y = n,
    colour = seat
  )
) +
  geom_point(shape = 19, size = 4) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 90)) +
  scale_x_continuous(breaks = all_years) +
  scale_colour_manual(values = c(lager_colors, "#EFEFEF")) +
  labs(
    y = "",
    x = ""
  )
## Warning: Removed 32 rows containing missing values (geom_point).

Linting

Der Code in diesem RMarkdown wird mit lintr automatisch auf den Wickham’schen tidyverse style guide überprüft.

lintr::lint(
  "main.Rmd", linters =
    lintr::with_defaults(
      commented_code_linter = NULL,
      trailing_whitespace_linter = NULL
    )
)
## main.Rmd:262:31: style: Commas should always have a space after.
##     select(1, 4, 7, 9, 11, 13,15,17,19,21:23) %>%
##                               ^
## main.Rmd:262:34: style: Commas should always have a space after.
##     select(1, 4, 7, 9, 11, 13,15,17,19,21:23) %>%
##                                  ^
## main.Rmd:262:37: style: Commas should always have a space after.
##     select(1, 4, 7, 9, 11, 13,15,17,19,21:23) %>%
##                                     ^
## main.Rmd:262:40: style: Commas should always have a space after.
##     select(1, 4, 7, 9, 11, 13,15,17,19,21:23) %>%
##                                        ^
## main.Rmd:1079:1: style: lines should not be more than 80 characters.
##        title = "Exekutive: Sitzverteilung in den 50 grössten Städte\n(Kleinstparteien nicht kategorisiert)") +
## ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## main.Rmd:1135:16: style: Variable and function names should be all lowercase.
##     as.numeric(JungesBern) +
##                ^~~~~~~~~~
## main.Rmd:1136:16: style: Variable and function names should be all lowercase.
##     as.numeric(LinkeSonstiges) +
##                ^~~~~~~~~~~~~~
## main.Rmd:1153:16: style: Variable and function names should be all lowercase.
##     as.numeric(BielerVolk) +
##                ^~~~~~~~~~
## main.Rmd:1180:1: style: lines should not be more than 80 characters.
##        title = "Exekutive: Sitzverteilung in den 10 grössten Städte\n(Kleinstparteien kategorisiert)") +
## ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## main.Rmd:1270:1: style: lines should not be more than 80 characters.
##        title = "Exekutive: Die 10 grössten Städte\n(ungewichtet, Kleinstparteien kategorisiert)") +
## ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## main.Rmd:1682:31: style: Commas should always have a space after.
##                       .[[18]],sep=""),
##                               ^
## main.Rmd:1682:34: style: Put spaces around all infix operators.
##                       .[[18]],sep=""),
##                                 ~^~
## main.Rmd:1723:14: style: Commas should always have a space after.
##   select(-15,-17)
##              ^
## main.Rmd:1826:1: style: lines should not be more than 80 characters.
##        title = "Legislative: Sitzverteilung in den 50 grössten Städte\n(Kleinstparteien nicht kategorisiert)") +
## ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## main.Rmd:1914:1: style: lines should not be more than 80 characters.
##        title = "Legislative: Die 10 grössten Städte\n(ungewichtet, Kleinstparteien kategorisiert)") +
## ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## main.Rmd:1941:13: style: Place a space before left parenthesis, except in a function call.
##   )[ceiling((Linke + Mitte + Sonstige + Rechte) / 2)])
##             ^
# lintr::lint("scripts/my_script.R", linters =
#               lintr::with_defaults(
#                 commented_code_linter = NULL,
#                 trailing_whitespace_linter = NULL
#                 )
#             )