Notes

This document illustrates the preprocessing of the dataset visualized in this article on srf.ch.

SRF Data attaches great importance to transparent and reproducible data preprocessing and -analysis. SRF Data believes in the principles of open data but also open and reproducible methods. Third parties should be empowered to build on the work of SRF Data and to generate new analyses and applications.

R-Script & processed data

The preprocessing and analysis of the data was conducted in the R project for statistical computing. The RMarkdown script used to generate this document and all the resulting data can be downloaded under this link. Through executing main.Rmd, the herein described process can be reproduced and this document can be generated. In the course of this, data from the folder ìnput will be processed and results will be written to output.

GitHub

The code for the herein described process can also be freely downloaded from https://github.com/srfdata/2015-09-elections-political-shifts. Criticism in the form of GitHub issues and pull requests is very welcome!

License

Creative Commons License
2015-09-elections-political-shifts by SRF Data is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

Exclusion of liability

The published information has been collated carefully, but no guarantee is offered of its completeness, correctness or up-to-date nature. No liability is accepted for damage or loss incurred from the use of this script or the information drawn from it. This exclusion of liability also applies to third-party content that is accessible via this offer.

Other projects

All code & data from SRF Data is available under http://srfdata.github.io.

Data description

Original data source

Michael Hermann, Mario Nowak (Forschungsstelle sotomo) with data from the Swiss Federal Statistical Office (FSO).

Shifts in political space

The shifts on the left-right- and the progressive-conservative-axes are available from 1981 to 2014 (1-year-steps) in the spatial aggregation levels of:

  • municipalities (gem)
  • cantons (kt)
  • municipality types (detailed description) (agglotyp)
  • language regions (sprachreg)

They are computed from national ballots results using a statistical dimensionality reduction method. A detailed methodology description (in German) can be found in the box at the end of the article on srf.ch. Important: The dimensionless values always signify the relative deviation from the median in a given year -> not absolute, semantical positions.

Shifts in party strengths

The shifts in party strengths for the national council are available from 1971 to 2014 (4-year-steps) in the spatial aggregation levels of:

  • municipalities (gem)
  • cantons (kt)
  • municipality types (detailed description) (agglotyp)
  • language regions (sprachreg)

Spatial aggregation & municipality harmonization

For all computations and spatial aggregations, the municipalities of 2015 were used (“Gemeindestand”). In order to account for municipality mergers and splits, the data were fully harmonized to the level of 2015.

Description of output

The following sections describe the results of the data preprocessing as stored in the output folder.

output/polit_raum_*.csv

Contains position on the left-right- and the progressive-conservative-axes from 1981 to 2014 (1-year-steps) in the above mentioned spatial aggregation levels.

Attribute Type Description
jahr Integer Year
*_id Integer / String ID of the referenced spatial unit
dim Integer Political space dimension (axis). Dimension 21 signifies left (negative) and right (positive), 22 signifies progressive (positive) and conservative (negative).
wert Double Value (dimensionless). See explanation above.
anz_gultig Double Number of people who voted validly in a given year and spatial unit (yearly average, rounded).
anz_stber Double Total number of people allowed to vote in a given year and spatial unit (yearly average, rounded).

output/nrw_*.csv

Contains party strengths in percent for the national council from 1971 to 2014 (4-year-steps) in the above mentioned spatial aggregation levels.

Attribute Type Description
jahr Integer Year of national council election
*_id Integer / String ID of the referenced spatial unit
partei Integer Party ID, references ID in output/parties.csv
wert Double Party strength in percent

Lookup tables

output/lut_*.csv

Contains full names and further information (e.g. translations) for the spatial aggregation levels of municipalities (gem) and municipality types (agglotyp).

Goes without description.

output/parties.csv

Contains party classifications made by SRF Data with the help of political scientists, used throughout all projects related to elections.

Attribute Type Description
ID Integer Unique identifier
Abbr_* String Abbreviation in German (D), French (F), English (E), Romansh (R), Italian (I), respectively
Legend_* String Abbreviation, but with slightly more information, used for frontend purposes
Name_* String Full name
Sortorder Integer Used for frontend purposes solely
OLD_ID String “Official” ID as given in https://github.com/srfdata/2015-06-elections-partystrengths/blob/master/analysis/input/parteienstaerke_mod_2.xlsx (sheet “Parteien”), used for combining party strengths for party groupings

Preparations

Install packages

Read in data & prepare it

# We mostly need the following datasets

# lut_agglotyp.csv
lut_agglotyp <- read.csv2(file = "input/lut_agglotyp.csv", sep = ";", stringsAsFactors = F)

# polit_raum_agglotyp.csv
polit_raum_agglotyp <- read.csv2(file = "input/polit_raum_agglotyp.csv", sep = ";", stringsAsFactors = F)

# anz_gultig_agglotyp.csv
anz_gultig_agglotyp <- read.csv2(file = "input/anz_gultig_agglotyp.csv", sep = ";", stringsAsFactors = F)

# anz_stber_agglotyp.csv
anz_stber_agglotyp <- read.csv2(file = "input/anz_stber_agglotyp.csv", sep = ";", stringsAsFactors = F)

# add valid votes
polit_raum_agglotyp %<>%
  inner_join(anz_gultig_agglotyp, by = c("jahr", "agglotyp")) %>% 
  rename(anz_gultig = anz) %>%
  inner_join(anz_stber_agglotyp, by = c("jahr", "agglotyp")) %>% 
  rename(anz_stber = anz) %>% 
  mutate(share_vote = anz_gultig / anz_stber)

polit_raum_agglotyp %<>% 
  mutate(wert = as.numeric(wert), agglotyp = factor(agglotyp, levels = lut_agglotyp$typ_id, labels = lut_agglotyp$typ)) 
polit_raum_agglotyp_left_right <- polit_raum_agglotyp %>% 
  filter(dim == 22)
polit_raum_agglotyp_cons_prog <- polit_raum_agglotyp %>% 
  filter(dim == 21) 

# lut_gem.csv
lut_gem <- read.csv2(file = "input/lut_gem.csv", sep = ";", stringsAsFactors = F)

# polit_raum_gem.csv
polit_raum_gem <- read.csv2(file = "input/polit_raum_gem.csv", sep = ";", stringsAsFactors = F)

polit_raum_gem %<>% 
  mutate(wert = as.numeric(wert)) 

# join in agglotyp
polit_raum_gem %<>% 
  inner_join(lut_gem, by = "gnr") %>% 
  mutate(agglotyp_id = factor(agglotyp_id, levels = lut_agglotyp$typ_id, labels = lut_agglotyp$typ)) %>% 
  select(-agglotyp) %>% 
  rename(agglotyp = agglotyp_id)

# join in agglotyp values
polit_raum_gem %<>%
  inner_join(polit_raum_agglotyp, by = c("jahr", "dim", "agglotyp")) %>% 
  select(-anz_gultig) %>% 
  rename(wert_gde = wert.x, wert_agglotyp = wert.y)

# polit_raum_sprachreg.csv
polit_raum_sprachreg <- read.csv2(file = "input/polit_raum_sprachreg.csv", sep = ";", stringsAsFactors = F)

# lut_sprachreg.csv
lut_sprachreg <- read.csv2(file = "input/lut_sprachreg.csv", sep = ";", stringsAsFactors = F)

# anz_gultig_sprachreg.csv
anz_gultig_sprachreg <- read.csv2(file = "input/anz_gultig_sprachreg.csv", sep = ";", stringsAsFactors = F)

# anz_stber_sprachreg.csv
anz_stber_sprachreg <- read.csv2(file = "input/anz_stber_sprachreg.csv", sep = ";", stringsAsFactors = F)

# add valid votes
polit_raum_sprachreg %<>%
  rename(jahr = Jahr) %>% 
  inner_join(anz_gultig_sprachreg, by = c("jahr", "sprachreg")) %>% 
  rename(anz_gultig = anz) %>% 
  inner_join(anz_stber_sprachreg, by = c("jahr", "sprachreg")) %>% 
  rename(anz_stber = anz) %>% 
  mutate(share_vote = anz_gultig / anz_stber)

polit_raum_sprachreg %<>% 
  mutate(wert = as.numeric(wert), sprachreg = factor(sprachreg, levels = lut_sprachreg$sprachreg, labels = lut_sprachreg$label_sprachreg)) 

# parties
nrw_agglotyp <- read.csv2(file = "input/nrw_71_agglotyp.csv", sep = ";", stringsAsFactors = F)
nrw_agglotyp %<>% 
  mutate(wert = as.numeric(wert), agglotyp = factor(agglotyp, levels = lut_agglotyp$typ_id, labels = lut_agglotyp$typ)) 


nrw_gem <- read.csv2(file = "input/nrw_71_gem.csv", sep = "\t", stringsAsFactors = F)

Plausibility checks

# correct number of rows?
nrow(polit_raum_agglotyp) == 34 * 8 * 2
## [1] TRUE
nrow(polit_raum_gem) == 34 * 2324 * 2
## [1] TRUE
length(unique(nrw_agglotyp$partei))
## [1] 12
length(unique(nrw_agglotyp$jahr))
## [1] 11
nrow(nrw_agglotyp) == 11 * 8 * 12 
## [1] TRUE

Analysis

Group sizes

In the following analyses, it is important to note that different municipality types are home to a differing amount of people and are thus not equally “important” for the political landscape of Switzerland. The following chart gives an overview.

anz_stber <- anz_stber_agglotyp %>% 
  filter(jahr == 2014)
anz_stber %<>% 
  mutate(agglotyp = factor(agglotyp, levels = lut_agglotyp$typ_id, labels = lut_agglotyp$typ)) 
ggplot(anz_stber, aes(x = agglotyp, y = anz)) +
  geom_bar(stat = "identity") +
  ylab("Number of people allowed to vote") +
  xlab("Municipality type") +
  theme(axis.text.x = element_text(angle = 90))

Progressive-conservative dimension

# developments in the agglomeration types - dim cons/progr
ggplot(polit_raum_agglotyp_cons_prog, aes(x = jahr, y = wert, color = agglotyp, size = anz_gultig, alpha = anz_gultig)) +
    geom_line() +
    geom_hline(yintercept = 0) + 
    ylim(-10, 10) +
    ylab("Value (Positive: progressive; negative: conservative)") +
    xlab("Year") +
    ggtitle(label = "Political shifts on the progressive-conservative-axis") +
    guides(color = guide_legend(ncol = 2), alpha = F) +
    theme(legend.title = element_text()) +
    scale_color_discrete(name = "Type of municipality") +
    scale_size_continuous(name = "Number of valid votes, also conveyed with opacity")

Most important findings:

  • Big cities performed a significant and constant shift to being more progressive in the last 35 years, a shift which has slowed down in the last 10 years.
  • Municipalities with high status and with low status moved into the opposite direction, the latter starting further “down”. The same is also the case for municipalities with middle status. Note: All these municipalities belong to agglomeration which is not part of the core of agglomerations (i.e. not the same as “cities” / typical “agglo” as we would call it)
  • Most voters live in small agglomeration municipalities - these stayed mostly the same over the last 35 years.
  • Rural municipalities performed a significant and relatively stark shift to being more progressive in the last 10 years.

Left-right dimension

# developments in the agglomeration types - dim left/right
ggplot(polit_raum_agglotyp_left_right, aes(x = jahr, y = wert, color = agglotyp, size = anz_gultig, alpha = anz_gultig)) +
    geom_line() +
    geom_hline(yintercept = 0) + 
    ylim(-10, 10) + 
    ylab("Value (Negative: left; positive: right)") +
    xlab("Year") +
    ggtitle(label = "Political shifts on the left-right-axis") +
    guides(color = guide_legend(ncol = 2), alpha = F) +
    theme(legend.title = element_text()) +
    scale_color_discrete(name = "Type of municipality") +
    scale_size_continuous(name = "Number of valid votes, also conveyed with opacity") +
    coord_flip()