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.
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
.
Attention: Please set your working directory in the first code chunk!
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!
2015-09-elections-political-shifts by SRF Data is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
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.
All code & data from SRF Data is available under http://srfdata.github.io.
Michael Hermann, Mario Nowak (Forschungsstelle sotomo) with data from the Swiss Federal Statistical Office (FSO).
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:
gem
)kt
)agglotyp
)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.
The shifts in party strengths for the national council are available from 1971 to 2014 (4-year-steps) in the spatial aggregation levels of:
gem
)kt
)agglotyp
)sprachreg
)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.
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 |
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 |
# von https://mran.revolutionanalytics.com/web/packages/checkpoint/vignettes/using-checkpoint-with-knitr.html
cat("library(magrittr)
library(tidyr)
library(dplyr)
library(readxl)
library(animation)
library(extrafont)
library(jsonlite)
library(ggplot2)",
file = "manifest.R")
package_date <- "2015-10-01"
if(!require(checkpoint)) {
if(!require(devtools)){
install.packages("devtools", repos = "http://cran.us.r-project.org")
require(devtools)
}
devtools::install_github("checkpoint", username = "RevolutionAnalytics", ref = "v0.3.2", 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/
dir.create("~/.checkpoint")
## Warning in dir.create("~/.checkpoint"): '/home/tgrossen/.checkpoint'
## already exists
checkpoint(snapshotDate = package_date, project = path_to_wd, verbose = T, scanForPackages = T, use.knitr = F, R.version = "3.1.3")
## Scanning for packages used in this project
## rmarkdown files found and will not be parsed. Set use.knitr = TRUE
## - Discovered 9 packages
## All detected packages already installed
## checkpoint process complete
## ---
rm(package_date)
source("manifest.R")
##
## Attaching package: 'tidyr'
## The following object is masked from 'package:magrittr':
##
## extract
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
## Registering fonts with R
##
## Attaching package: 'jsonlite'
## The following object is masked from 'package:utils':
##
## View
unlink("manifest.R")
sessionInfo()
## R version 3.1.3 (2015-03-09)
## Platform: x86_64-unknown-linux-gnu (64-bit)
## Running under: Ubuntu 16.04.2 LTS
##
## locale:
## [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
## [3] LC_TIME=de_CH.UTF-8 LC_COLLATE=en_US.UTF-8
## [5] LC_MONETARY=de_CH.UTF-8 LC_MESSAGES=en_US.UTF-8
## [7] LC_PAPER=de_CH.UTF-8 LC_NAME=C
## [9] LC_ADDRESS=C LC_TELEPHONE=C
## [11] LC_MEASUREMENT=de_CH.UTF-8 LC_IDENTIFICATION=C
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] ggplot2_1.0.1 jsonlite_0.9.17 extrafont_0.17 animation_2.4
## [5] readxl_0.1.0 dplyr_0.4.3 tidyr_0.3.1 magrittr_1.5
## [9] checkpoint_0.4.0
##
## loaded via a namespace (and not attached):
## [1] assertthat_0.1 backports_1.1.0 colorspace_1.2-6 DBI_0.3.1
## [5] digest_0.6.12 evaluate_0.10.1 extrafontdb_1.0 grid_3.1.3
## [9] gtable_0.1.2 htmltools_0.3.6 knitr_1.16 MASS_7.3-39
## [13] munsell_0.4.2 parallel_3.1.3 plyr_1.8.3 proto_0.3-10
## [17] R6_2.1.1 Rcpp_0.12.12 reshape2_1.4.1 rmarkdown_1.6
## [21] rprojroot_1.2 Rttf2pt1_1.3.3 scales_0.3.0 stringi_1.1.5
## [25] stringr_1.2.0 tools_3.1.3 yaml_2.1.14
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)
## Warning in read.table(file = file, header = header, sep = sep, quote
## = quote, : incomplete final line found by readTableHeader on 'input/
## lut_sprachreg.csv'
# 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
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))
# 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")
# 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()
## Warning: Removed 1 rows containing missing values (geom_path).
# need to spread it first
polit_raum_agglotyp_spread <- polit_raum_agglotyp %>%
spread(dim, wert) %>%
rename(leftright = `22`, progcons = `21`)
library(grid)
# note: we use geom_path here instead of geom_line
ggplot(polit_raum_agglotyp_spread, aes(x = leftright, y = progcons, color = agglotyp)) +
geom_path(arrow = arrow(ends = "last", type = "closed", length = unit(0.13, "inches"))) +
geom_hline(yintercept = 0) +
geom_vline(xintercept = 0) +
xlab("Value (Negative: left; positive: right)") +
ylab("Value (Positive: progressive; negative: conservative)") +
ggtitle(label = "Political shifts on both axes") +
guides(color = guide_legend(ncol = 2)) +
theme(legend.title = element_text(size = 14), axis.text.x = element_blank(), axis.text.y = element_blank(), axis.ticks.x = element_blank(), axis.ticks.y = element_blank(), plot.margin = unit(c(1,1,1,1), "lines"), legend.text = element_text(size = 14), legend.box = "vertical") +
guides(color = guide_legend(ncol = 1)) +
scale_color_discrete(name = "Type of municipality") +
scale_alpha_continuous(name = "Year") +
xlim(-10, 10) +
ylim(-10, 10)
## Warning: Removed 1 rows containing missing values (geom_path).
The following shows the three most similar (i.e. typical) municipalities for each of the municipality types (in terms of euclidean distance to both dimensions).
polit_raum_gem %>%
group_by(gnr, gemeinde, agglotyp) %>%
summarize(euclidean = as.numeric(dist(rbind(wert_gde, wert_agglotyp)))) %>%
ungroup() %>%
group_by(agglotyp) %>%
arrange(euclidean) %>%
slice(1:3) %>%
as.data.frame()
## gnr gemeinde agglotyp euclidean
## 1 261 Zürich Grossstadt 11.129542
## 2 2701 Basel Grossstadt 17.415019
## 3 351 Bern Grossstadt 18.507061
## 4 1061 Luzern Mittelstadt 14.350345
## 5 3203 St. Gallen Mittelstadt 21.588594
## 6 3901 Chur Mittelstadt 23.955018
## 7 2581 Olten Kleinstadt 15.096612
## 8 6002 Brig-Glis Kleinstadt 22.036277
## 9 4671 Kreuzlingen Kleinstadt 22.607275
## 10 1 Aeugst am Albis statushohe Gemeinde 9.867958
## 11 1051 Adligenswil statushohe Gemeinde 13.091849
## 12 732 Bellmund statushohe Gemeinde 14.267109
## 13 2861 Sissach statusmittlere Gemeinde 8.285717
## 14 198 Uster statusmittlere Gemeinde 9.818788
## 15 2886 Hölstein statusmittlere Gemeinde 10.841969
## 16 2824 Frenkendorf statustiefe Gemeinde 9.214266
## 17 2309 Wünnewil-Flamatt statustiefe Gemeinde 11.835844
## 18 247 Schlieren statustiefe Gemeinde 14.985783
## 19 2523 Horriwil Kleinagglomerationsgemeinde 9.263439
## 20 420 Rüdtligen-Alchenflüh Kleinagglomerationsgemeinde 9.603676
## 21 2904 Neunkirch Kleinagglomerationsgemeinde 9.762454
## 22 2302 St. Antoni ländliche Gemeinde 6.047818
## 23 785 Meiringen ländliche Gemeinde 8.255822
## 24 1068 Vitznau ländliche Gemeinde 8.338027
# doublecheck
gnr_1 <- polit_raum_gem %>%
filter(gnr == 1) %>%
select(wert_gde, wert_agglotyp) %>%
as.data.frame()
dist(rbind(gnr_1$wert_gde, gnr_1$wert_agglotyp))
## 1
## 2 9.867958
gnr_2861 <- polit_raum_gem %>%
filter(gnr == 2861) %>%
select(wert_gde, wert_agglotyp) %>%
as.data.frame()
dist(rbind(gnr_2861$wert_gde, gnr_2861$wert_agglotyp))
## 1
## 2 8.285717
# seems to work ok
# plot them
most_similar_gnr <- polit_raum_gem %>%
group_by(gnr, gemeinde, agglotyp) %>%
summarize(euclidean = as.numeric(dist(rbind(wert_gde, wert_agglotyp)))) %>%
ungroup() %>%
group_by(agglotyp) %>%
arrange(euclidean) %>%
slice(1) %>%
ungroup() %>%
select(gnr)
most_similar <- polit_raum_gem %>%
filter(gnr %in% most_similar_gnr$gnr) %>%
select(jahr, gemeinde, dim, wert_gde, agglotyp) %>%
spread(dim, wert_gde) %>%
rename(leftright = `22`, progcons = `21`) %>%
arrange(jahr, agglotyp)
ggplot(most_similar, aes(x = leftright, y = progcons, color = agglotyp)) +
geom_path(arrow = arrow(ends = "last", type = "closed", length = unit(0.13, "inches"))) +
geom_hline(yintercept = 0) +
geom_vline(xintercept = 0) +
xlab("Value (Negative: left; positive: right)") +
ylab("Value (Positive: progressive; negative: conservative)") +
ggtitle(label = "Political shifts on both axes for most typical municipalities") +
guides(color = guide_legend(ncol = 2)) +
theme(legend.title = element_text()) +
scale_color_discrete(name = "Type of municipality (colors identical with the plot above)") +
scale_alpha_continuous(name = "Year") +
xlim(-10, 10) +
ylim(-10, 10)
ggplot(polit_raum_agglotyp, aes(x = jahr, y = share_vote, color = agglotyp, alpha = anz_gultig)) +
geom_line(size = 2) +
ylab("Average share of people who voted") +
xlab("Year") +
ggtitle(label = "Voting participation") +
# scale_color_manual(values = distinct_colors) +
guides(color = guide_legend(ncol = 2)) +
theme(legend.title = element_text()) +
scale_color_discrete(name = "Type of municipality") +
scale_alpha_continuous(name = "Number of valid votes") +
scale_y_continuous(labels = scales::percent)
Note: The stark peak in 1989 is most likely due to the fact that, in this year, only one vote was used.
ggplot(polit_raum_agglotyp, aes(x = jahr, y = share_vote, color = agglotyp, alpha = anz_gultig)) +
geom_line(aes(alpha = anz_gultig), stat = "smooth", se = F, method = "loess", size = 2) +
ylab("Average share of people who voted") +
xlab("Year") +
ggtitle(label = "Voting participation (loess smoother)") +
guides(color = guide_legend(ncol = 2)) +
theme(legend.title = element_text()) +
scale_color_discrete(name = "Type of municipality") +
scale_alpha_continuous(name = "Number of valid votes") +
scale_y_continuous(labels = scales::percent)
# need to spread it first
polit_raum_sprachreg_spread <- polit_raum_sprachreg %>%
spread(dim, wert) %>%
rename(leftright = `22`, progcons = `21`)
# note: we use geom_path here instead of geom_line
ggplot(polit_raum_sprachreg_spread, aes(x = leftright, y = progcons, color = sprachreg)) +
geom_path(arrow = arrow(ends = "last", type = "closed", length = unit(0.13, "inches"))) +
geom_hline(yintercept = 0) +
geom_vline(xintercept = 0) +
xlab("Value (Negative: left; positive: right)") +
ylab("Value (Positive: progressive; negative: conservative)") +
ggtitle(label = "Political shifts on both axes") +
guides(color = guide_legend(ncol = 2)) +
theme(legend.title = element_text()) +
scale_color_discrete(name = "Language region") +
scale_alpha_continuous(name = "Year") +
xlim(-10, 10) +
ylim(-10, 10)
## Warning: Removed 11 rows containing missing values (geom_path).
Left-right shift looks interesting for the French-speaking region, let’s explore further:
polit_raum_sprachreg_left_right <- polit_raum_sprachreg %>%
filter(dim == 22)
ggplot(polit_raum_sprachreg_left_right, aes(x = jahr, y = wert, color = sprachreg, 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 = "Language region") +
scale_size_continuous(name = "Number of valid votes, also conveyed with opacity") +
coord_flip()
## Warning: Removed 11 rows containing missing values (geom_path).
nrw_agglotyp_svp_sp <- nrw_agglotyp %>%
filter(partei == 4 | partei == 3) %>%
mutate(partei = factor(partei, levels = c(3,4), labels = c("SP", "SVP")))
ggplot(nrw_agglotyp_svp_sp, aes(x = jahr, y = wert, color = agglotyp)) +
geom_line() +
ylab("Party strength (in percent)") +
xlab("Year") +
ggtitle(label = "Party strength of SP and SVP") +
guides(color = guide_legend(ncol = 2), alpha = F) +
theme(legend.title = element_text()) +
scale_color_discrete(name = "Type of municipality") +
facet_grid(partei ~ .)
nrw_agglotyp_cvp_fdp <- nrw_agglotyp %>%
filter(partei == 2 | partei == 1) %>%
mutate(partei = factor(partei, levels = c(2,1), labels = c("CVP", "FDP")))
ggplot(nrw_agglotyp_cvp_fdp, aes(x = jahr, y = wert, color = agglotyp)) +
geom_line() +
ylab("Party strength (in percent)") +
xlab("Year") +
ggtitle(label = "Party strength of CVP and FDP") +
guides(color = guide_legend(ncol = 2), alpha = F) +
theme(legend.title = element_text()) +
scale_color_discrete(name = "Type of municipality") +
facet_grid(partei ~ .)
nrw_agglotyp_gps <- nrw_agglotyp %>%
filter(partei == 13) %>%
mutate(partei = factor(partei, levels = c(13), labels = c("GPS")))
ggplot(nrw_agglotyp_gps, aes(x = jahr, y = wert, color = agglotyp)) +
geom_line() +
ylab("Party strength (in percent)") +
xlab("Year") +
ggtitle(label = "Party strength of the Greens") +
guides(color = guide_legend(ncol = 2), alpha = F) +
theme(legend.title = element_text()) +
scale_color_discrete(name = "Type of municipality") +
facet_grid(partei ~ .)
# note: we use geom_path here instead of geom_line
# todos:
# - add styling
# - add source
# -
setwd("output/")
plotIteration <- function(cur_year){
polit_raum_agglotyp_spread_range <- polit_raum_agglotyp_spread %>%
filter(jahr <= cur_year)
dimplot <- ggplot(polit_raum_agglotyp_spread_range, aes(x = leftright, y = progcons, color = agglotyp)) +
geom_path(size = 1, arrow = arrow(ends = "last", type = "closed", length = unit(0.05, "inches"))) +
geom_hline(yintercept = 0, color = "#94928d") +
geom_vline(xintercept = 0, color = "#94928d") +
xlab("Links <> Rechts") +
ylab("Konservativ <> Progressiv") +
ggtitle(label = cur_year) +
guides(color = guide_legend(ncol = 2)) +
scale_color_discrete(name = "Raumtyp") +
scale_alpha_continuous(name = "Jahr") +
xlim(-10, 10) +
ylim(-10, 10) +
theme_bw() +
theme(title = element_text(size = 16, family = "SRG SSR Type", face = "bold"),
text = element_text(color = "#222222", family = "SRG SSR Type"),
legend.title = element_blank(),
axis.text.x = element_blank(),
axis.text.y = element_blank(),
axis.ticks.x = element_blank(),
axis.ticks.y = element_blank(),
legend.text = element_text(size = 13),
legend.margin = unit(0, "cm"),
plot.margin = unit(c(0.5,0,0.5,0.5), "cm"),
axis.title.x = element_text(size = 14),
axis.title.y = element_text(size = 14),
legend.box = "vertical",
panel.grid = element_blank(),
plot.background = element_rect(fill = "#f5f5f2"),
panel.background = element_rect(fill = "#f5f5f2"),
legend.background = element_rect(fill = "#f5f5f2"),
legend.key = element_blank(),
axis.line = element_line(color = "#94928d")) +
annotate("text", x = 8, y = -10, label = "Quelle: Sotomo", family = "SRG SSR Type", color = "#555555", size = 4) +
guides(color = guide_legend(ncol = 1))
print(dimplot)
}
saveGIF({
for (cur_year in c(1981:2014, rep(2014, 10))){
plotIteration(cur_year)
}
}, interval = 0.1, movie.name = "movement.gif", ani.width = 624, ani.height = 480, clean = T)
## geom_path: Each group consist of only one observation. Do you need to adjust the group aesthetic?
## Warning: Removed 1 rows containing missing values (geom_path).
## Warning: Removed 1 rows containing missing values (geom_path).
## Warning: Removed 1 rows containing missing values (geom_path).
## Warning: Removed 1 rows containing missing values (geom_path).
## Warning: Removed 1 rows containing missing values (geom_path).
## Warning: Removed 1 rows containing missing values (geom_path).
## Warning: Removed 1 rows containing missing values (geom_path).
## Warning: Removed 1 rows containing missing values (geom_path).
## Warning: Removed 1 rows containing missing values (geom_path).
## Warning: Removed 1 rows containing missing values (geom_path).
## Warning: Removed 1 rows containing missing values (geom_path).
## Executing:
## 'convert' -loop 0 -delay 10 Rplot1.png Rplot2.png Rplot3.png
## Rplot4.png Rplot5.png Rplot6.png Rplot7.png Rplot8.png
## Rplot9.png Rplot10.png Rplot11.png Rplot12.png Rplot13.png
## Rplot14.png Rplot15.png Rplot16.png Rplot17.png Rplot18.png
## Rplot19.png Rplot20.png Rplot21.png Rplot22.png Rplot23.png
## Rplot24.png Rplot25.png Rplot26.png Rplot27.png Rplot28.png
## Rplot29.png Rplot30.png Rplot31.png Rplot32.png Rplot33.png
## Rplot34.png Rplot35.png Rplot36.png Rplot37.png Rplot38.png
## Rplot39.png Rplot40.png Rplot41.png Rplot42.png Rplot43.png
## Rplot44.png 'movement.gif'
## Output at: movement.gif
## [1] TRUE
setwd("..")
parties <- read.csv2(file = "input/parties.csv", sep = ",", stringsAsFactors = F)
# remove unnecessary attributes
lut_gem_new <- lut_gem %>% select(-agglotyp)
# add translations to lut_gem
lut_gem_new %<>% rename(name_official = gemeinde)
# first, load municipality name translations (src http://www.bfs.admin.ch/bfs/portal/de/index/infothek/nomenklaturen/blank/blank/gem_liste/03.Document.90142.xls, slightly edited to make it easier to read in)
translated_names <- read_excel("input/gdenamen_translation.xlsx", sheet = 1)[1:75,]
translated_names %<>%
rename(name_official = Name_Official, name_d = Name_D, name_f = Name_F, name_i = Name_I)
lut_gem_new %<>%
left_join(translated_names, by = "name_official") %>%
rename(id = gnr) %>%
rename(kt_id = kt) %>%
rename(sprachreg_id = sprachreg)
# further attribute selection
lut_agglotyp %<>%
select(typ_id, typ) %>%
rename(id = typ_id)
nrw_agglotyp <- read.csv2(file = "input/nrw_71_agglotyp.csv", sep = ";", stringsAsFactors = F)
nrw_agglotyp %<>% mutate(wert = as.numeric(wert)) %>%
rename(agglotyp_id = agglotyp)
nrw_gem %<>% mutate(wert = as.numeric(Wert)) %>%
rename(gem_id = bfs, partei = Partei) %>%
select(-Wert)
nrw_sprachreg <- read.csv2(file = "input/nrw_71_sprachreg.csv", sep = ";", stringsAsFactors = F)
nrw_sprachreg %<>% mutate(wert = as.numeric(Wert)) %>%
rename(sprachreg_id = sprachreg, partei = Partei) %>%
select(-Wert)
nrw_kt <- read.csv2(file = "input/nrw_71_kt.csv", sep = ";", stringsAsFactors = F)
nrw_kt %<>% mutate(wert = as.numeric(Wert)) %>%
rename(kt_id = kt, partei = Partei) %>%
select(-Wert)
polit_raum_agglotyp <- read.csv2(file = "input/polit_raum_agglotyp.csv", sep = ";", stringsAsFactors = F)
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)
polit_raum_agglotyp %<>% mutate(wert = as.numeric(wert))
polit_raum_agglotyp %<>% rename(agglotyp_id = agglotyp)
polit_raum_sprachreg <- read.csv2(file = "input/polit_raum_sprachreg.csv", sep = ";", stringsAsFactors = F)
polit_raum_sprachreg %<>% rename(jahr = Jahr)
polit_raum_sprachreg %<>%
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)
polit_raum_sprachreg %<>% mutate(wert = as.numeric(wert))
polit_raum_sprachreg %<>% rename(sprachreg_id = sprachreg)
polit_raum_gem <- read.csv2(file = "input/polit_raum_gem.csv", sep = ";", stringsAsFactors = F)
anz_gultig_gem <- read.csv2(file = "input/anz_gultig_gem.csv", sep = ";", stringsAsFactors = F)
anz_stber_gem <- read.csv2(file = "input/anz_stber_gem.csv", sep = ";", stringsAsFactors = F)
polit_raum_gem %<>%
inner_join(anz_gultig_gem, by = c("jahr", "gnr")) %>%
rename(anz_gultig = anz) %>%
inner_join(anz_stber_gem, by = c("jahr", "gnr")) %>%
rename(anz_stber = anz)
polit_raum_gem %<>% rename(gem_id = gnr)
polit_raum_gem %<>% mutate(wert = as.numeric(wert))
polit_raum_kt <- read.csv2(file = "input/polit_raum_kt.csv", sep = ";", stringsAsFactors = F)
anz_gultig_kt <- read.csv2(file = "input/anz_gultig_kt.csv", sep = ";", stringsAsFactors = F)
anz_stber_kt <- read.csv2(file = "input/anz_stber_kt.csv", sep = ";", stringsAsFactors = F)
polit_raum_kt %<>%
inner_join(anz_gultig_kt, by = c("jahr", "kt")) %>%
rename(anz_gultig = anz) %>%
inner_join(anz_stber_kt, by = c("jahr", "kt")) %>%
rename(anz_stber = anz)
polit_raum_kt %<>% mutate(wert = as.numeric(wert))
polit_raum_kt %<>% rename(kt_id = kt)
# write out the other files
write.table(parties, file = "output/parties.csv", row.names = F, na = "", sep = ",", quote = T)
write.table(lut_gem_new, file = "output/lut_gem.csv", row.names = F, na = "", sep = ",", quote = T)
write.table(lut_agglotyp, file = "output/lut_agglotyp.csv", row.names = F, na = "", sep = ",", quote = T)
write.table(nrw_agglotyp, file = "output/nrw_agglotyp.csv", row.names = F, na = "", sep = ",", quote = T)
write.table(nrw_gem, file = "output/nrw_gem.csv", row.names = F, na = "", sep = ",", quote = T)
write.table(nrw_kt, file = "output/nrw_kt.csv", row.names = F, na = "", sep = ",", quote = T)
write.table(nrw_sprachreg, file = "output/nrw_sprachreg.csv", row.names = F, na = "", sep = ",", quote = T)
# write.table(nrw_71_gem, file = "output/nrw_71_gem.csv", row.names = F, na = "", sep = ",", quote = T) -> will follow, needs to be converted to wide format
write.table(polit_raum_agglotyp, file = "output/polit_raum_agglotyp.csv", row.names = F, na = "", sep = ",", quote = T)
write.table(polit_raum_gem, file = "output/polit_raum_gem.csv", row.names = F, na = "", sep = ",", quote = T)
write.table(polit_raum_sprachreg, file = "output/polit_raum_sprachreg.csv", row.names = F, na = "", sep = ",", quote = T)
write.table(polit_raum_kt, file = "output/polit_raum_kt.csv", row.names = F, na = "", sep = ",", quote = T)
The results of this analysis were published in the episode of Saturday, September 26th 2015, 19:30
Party strength losses and wins: Where?
# SP
# between 2003 and 2011
nrw_agglotyp_svp_sp %>%
filter(partei == "SP" & jahr >= 2003 & jahr <= 2011) %>%
group_by(agglotyp) %>%
summarize(diff = first(wert) - last(wert)) %>%
arrange(desc(diff))
## Source: local data frame [8 x 2]
##
## agglotyp diff
## (fctr) (dbl)
## 1 Grossstadt 6.224438
## 2 statusmittlere Gemeinde 5.124154
## 3 Kleinstadt 4.786880
## 4 Kleinagglomerationsgemeinde 4.618933
## 5 statustiefe Gemeinde 4.170542
## 6 Mittelstadt 4.132426
## 7 statushohe Gemeinde 3.395582
## 8 ländliche Gemeinde 3.154744
Between 2003 and 2011, the SP lost the most in big cities (6.2 percentage points), followed by middle-status municipalities (5.1). The party lost the least in rural municipalities (3.2).
# SVP
# between 1991 and 2007: the rise of SVP
nrw_agglotyp_svp_sp %>%
filter(partei == "SVP" & jahr >= 1991 & jahr <= 2007) %>%
group_by(agglotyp) %>%
summarize(diff = first(wert) - last(wert)) %>%
arrange(desc(diff))
## Source: local data frame [8 x 2]
##
## agglotyp diff
## (fctr) (dbl)
## 1 Grossstadt -12.51254
## 2 statushohe Gemeinde -15.82503
## 3 statusmittlere Gemeinde -15.99945
## 4 ländliche Gemeinde -16.25189
## 5 Mittelstadt -18.72282
## 6 statustiefe Gemeinde -19.28740
## 7 Kleinagglomerationsgemeinde -19.34388
## 8 Kleinstadt -19.54538
nrw_agglotyp_svp_sp %>%
filter(partei == "SVP" & jahr >= 2007 & jahr <= 2011) %>%
group_by(agglotyp) %>%
summarize(diff = first(wert) - last(wert)) %>%
arrange(desc(diff))
## Source: local data frame [8 x 2]
##
## agglotyp diff
## (fctr) (dbl)
## 1 statustiefe Gemeinde 3.742414
## 2 Grossstadt 3.677293
## 3 statusmittlere Gemeinde 2.693762
## 4 Mittelstadt 2.421912
## 5 Kleinagglomerationsgemeinde 2.398610
## 6 Kleinstadt 2.068013
## 7 ländliche Gemeinde 1.688183
## 8 statushohe Gemeinde 1.664444
Between 1991 and 2007, the SVP gained tremendously. They won the most voters in little cities (19.5 percentage points), closely followed by municipalities of small agglomerations (19.3) and low-status municipalities (19.3). The won the least in big cities (12.5). From 2007 to 2011, the party lost again, the most in low-status municipalities (3.7) and big cities (3.7), the least in high-status municipalities and rural municipalities (1.7 both).
# CVP: The slow decline
# between 1971 and 2011
nrw_agglotyp_cvp_fdp %>%
filter(partei == "CVP" & jahr >= 1971 & jahr <= 2011) %>%
group_by(agglotyp) %>%
summarize(diff = first(wert) - last(wert)) %>%
arrange(desc(diff))
## Source: local data frame [8 x 2]
##
## agglotyp diff
## (fctr) (dbl)
## 1 ländliche Gemeinde 13.636592
## 2 Kleinagglomerationsgemeinde 10.426281
## 3 Kleinstadt 8.311346
## 4 Mittelstadt 7.847546
## 5 statustiefe Gemeinde 6.525694
## 6 statusmittlere Gemeinde 6.197461
## 7 statushohe Gemeinde 4.866242
## 8 Grossstadt 4.348259
Between 1971 and 2011, the CVP continuously and steadily lost votes. The party lost the most in rural municipalities (13.6 percentage points), followed by municipalities of small agglomerations (10.4). They lost the least in big cities (4.3).
# FDP: The slow decline
# between 1979 and 2011
nrw_agglotyp_cvp_fdp %>%
filter(partei == "FDP" & jahr >= 1979 & jahr <= 2011) %>%
group_by(agglotyp) %>%
summarize(diff = first(wert) - last(wert)) %>%
arrange(desc(diff))
## Source: local data frame [8 x 2]
##
## agglotyp diff
## (fctr) (dbl)
## 1 statushohe Gemeinde 16.938460
## 2 Mittelstadt 16.183982
## 3 Kleinstadt 15.119465
## 4 Kleinagglomerationsgemeinde 11.310805
## 5 Grossstadt 11.192368
## 6 statustiefe Gemeinde 10.857251
## 7 statusmittlere Gemeinde 10.778217
## 8 ländliche Gemeinde 9.314937
Between 1979 and 2011, the FDP continuously and steadily lost votes. The party lost the most in high-status municipalities (16.9 percentage points), followed by middle cities (16.2). They lost the least in rural municipalities (9.3).