library(tidyverse)
library(ggplot2)
library(reshape2)
library(readxl)

Data was shared by professors Michael Thrasher and Colin Rallings and it was cleaned in Open Refine. It contains local elections results since 1973 for every local authority in the UK.

datalocal = read.csv("historiclocalcouncilsCLEAN2.csv")
colnames(datalocal)
##  [1] "Name_First_Capital" "NAME_CAPITAL"       "code"              
##  [4] "type"               "year"               "council"           
##  [7] "con"                "lab"                "ld"                
## [10] "oth"                "nat"                "ctl"               
## [13] "ctlcode"            "conprop"            "labprop"           
## [16] "ldprop"             "natprop"            "othprop"           
## [19] "maxprop"            "ptyeff"             "cnclmaj"           
## [22] "conshs"             "labshs"             "ldshs"             
## [25] "natshs"             "othshs"             "twoparty"
datalocal %>% head()

Producing the map

library(maps)
library(mapdata)
library(maptools)
library(rgdal)
library(ggmap)
library(ggplot2)
library(rgeos)
library(broom)
library(plyr)
library(gganimate)

For the purpose of this story, I only visualised results in England and Wales and not the whole UK.

The main problem visualising historic election data in the UK has to do with boundaries changes. To deal with this, I decided to subset the data from 1995 onwards, so as to have only few local authorities with no data for past years. To avoid white gaps in the map, I set the parameter that I am visualising to NOC (as advised by professors) when boundary changes make it impossible to track change in control.

#load shapefile previously downloaded from the ONS geoportal.
shapefile = readOGR(dsn= "Local_Authority_Districts_December_2017_Full_Clipped_Boundaries_in_Great_Britain.shp")
## OGR data source with driver: ESRI Shapefile 
## Source: "C:\Users\eho35\Desktop\elections\elections\Local_Authority_Districts_December_2017_Full_Clipped_Boundaries_in_Great_Britain.shp", layer: "Local_Authority_Districts_December_2017_Full_Clipped_Boundaries_in_Great_Britain"
## with 380 features
## It has 10 fields
## Integer64 fields read as strings:  objectid bng_e bng_n
#Reshape for ggplot2 using the Broom package
mapdata <- tidy(shapefile, region="lad17nm")
#filtering out Scotland
csv = read.csv("Local_Authority_Districts_December_2017_Super_Generalised_Clipped_Boundaries_in_United_Kingdom_WGS84.csv")

noscot = csv %>% filter(grepl("S",lad17cd)) %>% select(lad17nm) %>% pull()
mapdata = mapdata %>% filter(!id %in% noscot)
mapdata = mapdata %>% mutate(id = gsub(c(", City of|, of|County |, County of|, Council| City|City of "), "", id)) %>% mutate(id=gsub(" and "," & ", id))

colnames(mapdata)[7]="Name_First_Capital"
mapdata$Name_First_Capital = toupper(mapdata$Name_First_Capital)
datalocal$Name_First_Capital = toupper(datalocal$Name_First_Capital)
join(mapdata, datalocal %>% select(Name_First_Capital,year,ctl) %>% filter(year==2018), by="Name_First_Capital") %>% filter(is.na(ctl)) %>% distinct(Name_First_Capital)
map=ggplot() + geom_polygon(data = join(mapdata, datalocal %>% select(Name_First_Capital,year,ctl) %>% filter(year >1994), by="Name_First_Capital") %>% mutate(ctl = ifelse(is.na(ctl),"NOC",as.character(ctl))), aes(x = long, y = lat, group = group,fill=ctl),color="#ffffff", size = 0.001)+ coord_fixed(1)+scale_fill_manual(values=c("#1465B6", "#C0C0C0","#C40813","#F7B229","#4A4A4A","#17A454","#A10BBD"), name=NULL,breaks=c("Con","Lab","LD","PC","Ind","NOC"))+labs(title = "How England and Wales changed",subtitle =  "Year: {current_frame}", x=NULL, y=NULL)+
  theme_void()+
  theme(legend.position = "bottom", legend.direction = "horizontal",legend.text=element_text(size=18),legend.key.size = unit(.8, "cm"), plot.title=element_text(size = 36),plot.subtitle=element_text(size = 38,face = "bold"))
#ggsave("test1.png")

Producing the gif

library(gifski)
library(transformr)
library(magick)
## Linking to ImageMagick 6.9.9.14
## Enabled features: cairo, freetype, fftw, ghostscript, lcms, pango, rsvg, webp
## Disabled features: fontconfig, x11

Using gganimate I produced the gif to promote the story.

mapanim=map + transition_manual((year))+
  enter_fade() +
  exit_fade()
forgif = animate(mapanim, width=1000, height=1000, duration = 20)
forgif

#anim_save("testgif7.gif", forgif)