Skip to content

Instantly share code, notes, and snippets.

@chrishanretty
Last active April 24, 2017 20:45
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save chrishanretty/be9cb5a2df9b3e8142d3df22678a0763 to your computer and use it in GitHub Desktop.
Save chrishanretty/be9cb5a2df9b3e8142d3df22678a0763 to your computer and use it in GitHub Desktop.
Analysis of swings in Conservative and Labour-held seats, BES data
library(foreign) ## for data import
library(dplyr) ## for chaining ops together
library(ggplot2) ## for plotting
library(reshape2) ## for reshaping
library(hrbrthemes) ## for pretty pictures
library(survey) ## for... uh, survey data
party.colours <- c("#0087DC","#D50000","#FDBB30","#FFFF00","#008142","#99CC33","#70147A","#DDDDDD")
bes <- read.spss("~/Dropbox/2017-forecasting/data/individual/BES2015_W10_Panel_v0.3.sav")
res <- read.csv("~/Dropbox/2017-forecasting/data/constituency/ge2015_results.csv")
bes <- merge(bes, res[,c("pano", "Winner15")],
all.x = TRUE,
all.y = FALSE,
by = "pano")
### Tidy up the VI vars so we have the right labels
###
bes$generalElectionVoteW6 <- car:::recode(as.character(bes$generalElectionVoteW6),
"'Labour'='Labour';
'Conservative'='Conservatives';
'Liberal Democrat'= 'Liberal Democrats';
'Scottish National Party (SNP)'= 'SNP';
'Plaid Cymru'='Plaid Cymru';
'Green Party'='Greens';
'United Kingdom Independence Party (UKIP)'='UKIP';
else = NA")
bes$vi_ge <- factor(bes$generalElectionVoteW6,
levels = c("Conservatives", "Labour",
"Liberal Democrats", "SNP",
"Plaid Cymru", "Greens",
"UKIP", "Other"),
ordered = TRUE)
bes$generalElectionVoteW10 <- car:::recode(as.character(bes$generalElectionVoteW10),
"'Labour'='Labour';
'Conservative'='Conservatives';
'Liberal Democrat'= 'Liberal Democrats';
'Scottish National Party (SNP)'= 'SNP';
'Plaid Cymru'='Plaid Cymru';
'Green Party'='Greens';
'United Kingdom Independence Party (UKIP)'='UKIP';
else = NA")
bes$vi <- factor(bes$generalElectionVoteW10,
levels = c("Conservatives", "Labour",
"Liberal Democrats", "SNP",
"Plaid Cymru", "Greens",
"UKIP", "Other"),
ordered = TRUE)
### Only use certain variables
bes <- bes[,c("pano", "vi", "Winner15", "vi_ge","wt_full_W9")]
### Restrict to those for whom we know constituency
bes <- subset(bes, !is.na(pano))
### Restrict to those with a weight for the post-election wave
bes <- subset(bes, !is.na(wt_full_W9))
mySvy <- svydesign(ids = ~1, weights = bes$wt_full_W9, data = bes)
### Table of VI currently
svytable(~vi, mySvy) / sum(svytable(~vi, mySvy))
### Table of Conservative-held seats
vitab <- svytable(~Winner15+vi, mySvy)
nRespondents <- rowSums(vitab)
vitab.pct <- vitab / nRespondents
vitab.m <- melt(vitab.pct)
### Merge this with the known results from last time
res.m <- melt(res[,c("Winner15", "TotalVote15", "Con15", "Lab15", "LD15", "SNP15",
"PC15", "UKIP15", "Green15", "Other15")],
id.vars = c("Winner15", "TotalVote15"))
res.m$votes <- res.m$value / 100 * res.m$TotalVote15
res.m <- res.m %>%
group_by(Winner15) %>%
mutate(totalVotes = sum(unique(TotalVote15))) %>%
group_by(Winner15, variable) %>%
summarize(known_share = sum(votes, na.rm = TRUE) / unique(totalVotes))
### Change the labelling
res.m$vi <- car::recode(res.m$variable,
"'Con15'='Conservatives'; 'Lab15'='Labour';
'LD15'='Liberal Democrats';'SNP15'='SNP';'PC15'='Plaid Cymru';
'Green15'='Greens';'UKIP15'='UKIP'; else ='Other'")
vitab.m <- merge(vitab.m, res.m,
by = c("Winner15", "vi"),
all = TRUE)
vitab.m$swing <- vitab.m$value - vitab.m$known_share
vitab.m$win_label <- as.character(vitab.m$Winner15)
vitab.m$win_label <- sub("Scottish National Party", "SNP", vitab.m$win_label)
vitab.m$win_label <- paste0(vitab.m$win_label,
"-held seats")
my.ylims <- c(-0.1, .125)
p1.df <- subset(vitab.m,
vi == "Conservatives" &
Winner15 %in% c("Conservative", "Labour", "Liberal Democrat",
"Scottish National Party"))
p1 <- ggplot(p1.df,
aes(x = win_label, y = swing)) +
geom_bar(stat = "identity", width = 0.6, fill = party.colours[1]) +
geom_hline(yintercept = 0) +
scale_x_discrete("") +
scale_y_continuous("Change", labels = scales::percent, limits = my.ylims) +
coord_flip() +
theme_minimal() +
theme_ipsum_rc() +
labs(title = "The Conservatives are up in seats they don't already hold",
subtitle = "Source: BES wave 10")
p2.df <- subset(vitab.m,
vi == "Labour" &
Winner15 %in% c("Conservative", "Labour", "Liberal Democrat",
"Scottish National Party"))
p2 <- ggplot(p2.df,
aes(x = win_label, y = swing)) +
geom_bar(stat = "identity", width = 0.6, fill = party.colours[2]) +
geom_hline(yintercept = 0) +
scale_x_discrete("") +
scale_y_continuous("Change", labels = scales::percent, limits = my.ylims) +
coord_flip() +
theme_minimal() +
theme_ipsum_rc() +
labs(title = "Labour is going backwards in former heartlands",
subtitle = "Source: BES wave 10")
p3.df <- subset(vitab.m,
vi == "Liberal Democrats" &
Winner15 %in% c("Conservative", "Labour", "Liberal Democrat",
"Scottish National Party"))
p3 <- ggplot(p3.df,
aes(x = win_label, y = swing)) +
geom_bar(stat = "identity", width = 0.6, fill = party.colours[3]) +
geom_hline(yintercept = 0) +
scale_x_discrete("") +
scale_y_continuous("Change", labels = scales::percent, limits = my.ylims) +
coord_flip() +
theme_minimal() +
theme_ipsum_rc() +
labs(title = "The Lib Dem vote is spreading out...",
subtitle = "Source: BES wave 10")
p4.df <- subset(vitab.m,
vi == "UKIP" &
Winner15 %in% c("Conservative", "Labour", "Liberal Democrat",
"Scottish National Party"))
p4 <- ggplot(p4.df,
aes(x = win_label, y = swing)) +
geom_bar(stat = "identity", width = 0.6, fill = party.colours[7]) +
geom_hline(yintercept = 0) +
scale_x_discrete("") +
scale_y_continuous("Change", labels = scales::percent, limits = my.ylims) +
coord_flip() +
theme_minimal() +
theme_ipsum_rc() +
labs(title = "UKIP is falling back everywhere but Scotland",
subtitle = "Source: BES wave 10")
png(file = "p1.png", width = 600, height = 600)
print(p1)
dev.off()
png(file = "p2.png", width = 600, height = 600)
print(p2)
dev.off()
png(file = "p3.png", width = 600, height = 600)
print(p3)
dev.off()
png(file = "p4.png", width = 600, height = 600)
print(p4)
dev.off()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment