Data analysis of New Zealand General Election advanced voting patterns 2002-2017

votingpatterns.R 5.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. library(dplyr)
  2. library(tidyr)
  3. library(ggplot2)
  4. library(scales)
  5. library(RColorBrewer)
  6. theme_set(theme_classic())
  7. partycolours <- c(
  8. "National Party" = "#00529F",
  9. "Labour Party" = "#D82A20",
  10. "Green Party" = "#098137",
  11. "New Zealand First Party" = "#000000",
  12. "The Opportunities Party" = "#32DAC3",
  13. "ACT New Zealand" = "#FDE401",
  14. "Conservative Party" = "#00AEEF",
  15. "United Future" = "#501557",
  16. "Māori Party" = "#B2001A"
  17. )
  18. dat <- read.csv("AdvancedVotesNewZealand.csv", stringsAsFactors = FALSE) %>%
  19. mutate(Party = gsub(" $", "", Party),
  20. Party = gsub("Mâori", "Māori", Party),
  21. Party = gsub("^Conservative$", "Conservative Party", Party),
  22. Party = gsub("^United Future New Zealand$", "United Future", Party),
  23. Party = gsub(" Coalition$", "", Party),
  24. Party = gsub("MANA", "Mana", Party),
  25. Party = gsub(" \\(.*\\)$", "", Party)) %>%
  26. pivot_wider(id_cols = c(Year, Party),
  27. names_from = Type, values_from = c(Votes, Seats)) %>%
  28. mutate(Votes_Other = Votes_Total - Votes_Advance,
  29. Advance_Proportion = Votes_Advance / Votes_Total,
  30. Seat_Difference = Seats_Total - Seats_Advance)
  31. e.years <- sort(unique(dat$Year))
  32. elec <- dat %>% group_by(Year) %>%
  33. summarise(Total_Votes = sum(Votes_Total),
  34. Total_Advance = sum(Votes_Advance),
  35. Total_Other = sum(Votes_Other),
  36. Total_Seats = sum(Seats_Total),
  37. Advance_Seats = sum(Seats_Advance),
  38. Seat_Differences = sum(abs(Seat_Difference)),
  39. .groups = "drop") %>%
  40. mutate(Prop_Advance = Total_Advance / Total_Other)
  41. partylev <- dat %>% left_join(elec, by = "Year") %>%
  42. mutate(PV_Prop_Total = Votes_Total / Total_Votes,
  43. PV_Prop_Advance = Votes_Advance / Total_Advance)
  44. partyav <- partylev %>% group_by(Party) %>%
  45. summarise(Total_Mean_Prop = mean(PV_Prop_Total),
  46. Advance_Mean_Prop = mean(PV_Prop_Advance),
  47. .groups = "drop") %>% arrange(desc(Total_Mean_Prop))
  48. partylev$Party = factor(partylev$Party, levels = partyav$Party)
  49. typecomp <- partylev %>%
  50. select(Year:Party, Votes_Advance,
  51. Votes_Other, Seats_Advance,
  52. Seats_Total, PV_Prop_Advance,
  53. PV_Prop_Total) %>%
  54. pivot_longer(cols = Votes_Advance:PV_Prop_Total,
  55. names_to = c("Quantity", "Type"),
  56. names_pattern = "(.*)_([^_]*)$",
  57. values_to = "value") %>%
  58. pivot_wider(names_from = "Quantity", values_from = "value")
  59. vtypes <- elec %>% select(Year, Total_Advance, Total_Other) %>%
  60. pivot_longer(Total_Advance:Total_Other, names_to = "Type", names_prefix = "Total_",
  61. values_to = "Votes") %>%
  62. mutate(Type = factor(Type, levels = c("Other", "Advance")))
  63. advplot <- ggplot(vtypes, aes(x = Year, y = Votes, fill = Type)) + geom_area() +
  64. scale_y_continuous(labels = scales::comma, expand = c(0,0)) +
  65. scale_x_continuous("General Election Year",
  66. breaks = e.years,
  67. expand = c(0,0)) +
  68. scale_fill_brewer("Vote Type", palette = "Paired") +
  69. labs(title = "Total Advance Votes", subtitle = "2002 to 2017")
  70. advplot
  71. propplot <- ggplot(filter(partylev, Party %in% names(partycolours)),
  72. aes(x = Year, y = Advance_Proportion, colour = Party)) + geom_line() + geom_point() +
  73. scale_colour_manual(values = partycolours) +
  74. scale_y_continuous("Percent of votes from Advance votes",
  75. labels = scales::percent, limits=c(0, NA), expand=c(0,0)) +
  76. scale_x_continuous("General Election Year",
  77. breaks = e.years) +
  78. labs(title = "Share of Each Party's Votes From Advanced Votes by Year")
  79. propplot
  80. scplot <- ggplot(filter(partylev, Party %in% names(partycolours)),
  81. aes(x = Year, y = Seat_Difference, colour = Party)) +
  82. geom_line() + geom_point() +
  83. scale_colour_manual(values = partycolours) +
  84. scale_x_continuous("General Election Year",
  85. breaks = e.years) +
  86. scale_y_continuous("Seat change from advance results and final results", n.breaks = 8,
  87. labels = function(x) { paste0(ifelse(x > 0, "+", ""), x) }) +
  88. labs(title = "Seat Change Between Advance Vote Results and Final Results")
  89. scplot
  90. pvplot <- ggplot(filter(partylev, Party %in% names(partycolours)),
  91. aes(x = Year, y = PV_Prop_Total, colour = Party)) +
  92. geom_line() + geom_point() +
  93. scale_colour_manual(values = partycolours) +
  94. scale_x_continuous("General Election Year",
  95. breaks = e.years) +
  96. scale_y_continuous("Party vote proportion", n.breaks = 10,
  97. expand=c(0,0), limits = c(0, 0.5), labels = scales::percent) +
  98. labs(title = "Party vote trajectories")
  99. pvplot
  100. daily <- read.csv("2020-advance-vote-data.csv", stringsAsFactors = FALSE) %>%
  101. filter(Date != "Totals") %>% mutate(Date = as.Date(Date)) %>%
  102. pivot_longer(cols = X2020.General.Election:X2014.General.Election, names_to = "Year", names_pattern = "^X([0-9]{4}).*$", values_to = "Votes") %>%
  103. mutate(Votes = ifelse(is.na(Votes), 0, Votes))
  104. dailyplot <- ggplot(daily, aes(x = Date, y = Votes, fill = Year)) +
  105. geom_col(position="dodge") +
  106. scale_x_date("2020 election-equivalent date",
  107. date_breaks = "1 day", date_labels = "%a %b %e",
  108. expand = c(0,0)) +
  109. scale_fill_brewer("Election year", palette = "Set2") +
  110. scale_y_continuous("Advance votes", labels = scales::comma, expand = c(0,0)) +
  111. labs(title = "Daily Advance Votes", subtitle = "Last updated 8 October 2020") +
  112. theme(axis.text.x = element_text(angle = 45, vjust = 1, hjust = 1))
  113. dailyplot