Election Netherlands 15 March 2017

This morning, two facts from yesterdays Dutch election were particularly striking to me.

The Economist has a nice chart visualizing the results.

I wondered what these effects are in a comparative perspective and conducted an analysis with data from ParlGov.

Here are the main facts.

  1. The electoral loss of the Social Democrats (PVdA) was particularly bad.
  2. A largest party with little more than 20% vote share is less exceptional nowadays.
library(tidyverse)
library(lubridate)

library(knitr)
options(knitr.kable.NA = '')

I use the data from ParlGov and limit my analysis to older democracies, excluding countries from Central/Eastern Europe.

db_file <- 'parlgov.db'
url <- 'http://www.parlgov.org/static/data/parlgov-experimental.db'
if( ! db_file %in% list.files()) download.file(url, db_file, mode='wb')
parlgov_db <- src_sqlite(db_file)

get_decade <- function(election_date) year(election_date) %/% 10 * 10

get_parlgov_table <- function(table_name) tbl(parlgov_db, table_name) %>% as_tibble
party_raw <- get_parlgov_table('view_party')
elec_raw <- get_parlgov_table('view_election')

elec <- elec_raw %>%
  filter(election_type == 'parliament',
         election_date >= '1945-01-01') %>%
  mutate(country = country_name,
         decade = get_decade(election_date)) %>%
  left_join(party_raw %>% select(party_id, family=family_name_short)) %>%
  group_by(country) %>%
  filter(min(election_date) <= '1980-01-01') %>%
  ungroup

elec_info <- get_parlgov_table('election')
turnout <- elec_info %>% 
  filter(id %in% elec$election_id) %>% 
  mutate(decade = get_decade(date)) %>% 
  group_by(decade) %>% 
  summarize(turnout = mean(votes_valid / electorate, na.rm=T))

results <- get_parlgov_table('election_result')
alliance <- results %>%
  filter(id %in% alliance_id) %>%
  mutate(tmp = paste(election_id, party_id)) %>%
  .[['tmp']]

cabinet <- get_parlgov_table('view_cabinet')
cab_party <- cabinet %>%
  filter(cabinet_party == 1) %>%
  distinct(election_id, party_id) %>%
  mutate(cabinet = 1)

First, I look at the electoral performance of the Dutch Social Democrats (PVdA) with the following information.

PvdA vote share

The PVd has always been less successful than the German and Swedish Social Democrats. Nevertheless, the 2017 result is particularly bad (see also vote loss comparison below).

socdem <- elec %>%
  filter(party_id %in% c(558, 742, 904)) %>%  # NOR-104 SWE-904
  mutate(year = year(election_date),
         party = paste(stringi::stri_trans_totitle(country_name_short), party_name_short, sep=' - ')) %>%
  bind_rows(tibble(party='Nld - PvdA', party_name_short='PvdA',
                   decade=2010, year=2017, vote_share=5.7))

pvda <- socdem %>%
  filter(party_name_short == 'PvdA') %>%
  group_by(decade) %>%
  summarise(vote_share = round(mean(vote_share, na.rm=T), 0)) %>%
  spread(decade, vote_share)
pvda %>% kable
1940 1950 1960 1970 1980 1990 2000 2010
27 31 26 29 31 26 21 17
ggplot(socdem, aes(year, vote_share, color=party)) + geom_line() + ylim(0, 60)

Party family share

Here, I present a comparison of the mean vote share of the main party families by decade.

All the main large party families have lost vote share over the last decades. Social Democrats have lost to Greens and Socialists/Communists.

Nevertheless, I was surprised how relatively stable the mean vote by party family has been.

pa_fam <- elec %>%
  filter( ! family %in% c('code', 'none', 'spec')) %>%
  group_by(decade, election_id, family) %>%
  summarise(vote_share = sum(vote_share, na.rm=T)) %>%
  group_by(decade, family)

# use reshape to add 0.0% for complete family data
pa_fam <-  pa_fam %>%
  spread(family, vote_share, fill = 0) %>%
  gather(family, vote_share, -election_id, -decade) %>%
  group_by(decade, family) %>%
  summarise(vote_share = mean(vote_share, na.rm=T))

fam_level <- c('com', 'eco', 'soc', 'agr', 'lib', 'chr', 'con', 'right')
fam_color <- c('#FB9A99', '#33A02C', '#E31A1C', '#B2DF8A', '#FDBF6F', '#FF7F00', '#1F78B4', '#A6CEE3')
pa_fam <- pa_fam %>% mutate(family = factor(family, fam_level))

pa_fam_pl <- pa_fam %>% 
  left_join(turnout) %>% 
  mutate(vote_share_with_turnout = vote_share * turnout) %>% 
  select(-turnout) %>% 
  gather(turnout, vote_share, -decade, -family)

ggplot(pa_fam_pl, aes(decade, vote_share, fill=family)) +
  geom_area(position = 'stack') +
  scale_fill_manual(values = fam_color) +
  facet_grid(. ~ turnout)