Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save USMortality/1ff2f5ac1506c518eb9b0610ad95ca0e to your computer and use it in GitHub Desktop.
Save USMortality/1ff2f5ac1506c518eb9b0610ad95ca0e to your computer and use it in GitHub Desktop.
Presidential Elections Popular Vote Swing States [USA]
library(readr)
library(dplyr)
library(tidyr)
library(ggplot2)
library(scales)
sf <- 2
width <- 600 * sf
height <- 335 * sf
options(vsc.dev.args = list(width = width, height = height, res = 72 * sf))
df <- read_csv(paste0(
"https://raw.githubusercontent.com/fivethirtyeight/election-results/",
"refs/heads/main/election_results_presidential.csv"
))
swing_states <- c("AZ", "GA", "MI", "NC", "NV", "PA", "WI")
votes_2020 <- df |>
filter(
office_name == "U.S. President",
state_abbrev %in% swing_states,
ballot_party %in% c("DEM", "REP"),
stage == "general"
) |>
select(cycle, state_abbrev, ballot_party, votes) |>
setNames(c("year", "state", "party", "votes"))
# https://election.lab.ufl.edu/2024-general-election-turnout/
votes_2024 <- tibble(
state = swing_states,
ballots = c(3428000, 5297258, 5710000, 5725000, 1487887, 7050000, 3425000),
rep_proj_share = c(.52, .503, .495, .509, .506, .501, .496),
dem_proj_share = c(.469, .488, .485, .479, .475, .489, .489)
) |>
mutate(
REP = ballots * rep_proj_share,
DEM = ballots * dem_proj_share
) |>
pivot_longer(
cols = c(REP, DEM),
names_to = "party",
values_to = "votes"
) |>
mutate(year = 2024) |>
select(year, state, party, votes) |>
setNames(c("year", "state", "party", "votes"))
# Combine and arrange data
combined_votes <- rbind(votes_2020, votes_2024) |>
group_by(year, party) |>
summarize(votes = sum(votes))
# Define party colors
party_colors <- c(
"DEM" = "#1f78b4", # blue
"REP" = "#e31a1c" # red
)
# Generate plot
chart <-
ggplot(combined_votes, aes(x = party, y = votes, fill = party)) +
geom_bar(
stat = "identity",
position = position_stack(reverse = TRUE)
) +
geom_text(
aes(label = comma(round(votes))),
position = position_stack(vjust = 0.5),
size = 2,
color = "white",
fontface = "bold"
) +
scale_fill_manual(values = party_colors) +
facet_wrap(~year, nrow = 1) +
labs(
title =
"2024 Swing State's Historical Popular Vote in US Presidential Elections",
subtitle = paste(
paste(swing_states, collapse = ", "),
"· @USMortality · Updated: 11/19/24 12:52pm"
),
caption = "Source: decisiondeskhq.com, election.lab.ufl.edu",
x = "",
y = "Votes",
fill = "Party"
) +
scale_y_continuous(labels = comma) +
theme_bw() +
theme(
legend.position = "top",
axis.text.x = element_blank(),
axis.ticks.x = element_line(color = "black")
)
ggsave(
filename = "chart1.png", plot = chart, width = width, height = height,
units = "px", dpi = 72 * sf, device = grDevices::png, type = "cairo"
)
# Combine and calculate margins
margins <- bind_rows(votes_2020, votes_2024) |>
pivot_wider(names_from = party, values_from = votes) |>
mutate(margin = DEM - REP)
# Define colors for margins
# Correctly define colors for TRUE/FALSE
margin_colors <- c(`TRUE` = "#1f78b4", `FALSE` = "#e31a1c")
# Generate bar chart with margins
chart <-
ggplot(margins, aes(x = state, y = margin, fill = margin > 0)) +
geom_bar(stat = "identity", width = 0.7) +
scale_fill_manual(
values = margin_colors,
labels = c("Negative (REP)", "Positive (DEM)")
) +
facet_wrap(~year, nrow = 1) +
labs(
title = "Swing State Margins in U.S. Presidential Elections",
subtitle = paste(
paste(swing_states, collapse = ", "),
"· @USMortality · Updated: 11/19/24 12:52pm"
),
caption = "Source: decisiondeskhq.com, election.lab.ufl.edu",
x = "",
y = "Margin (DEM - REP)",
fill = "Margin Direction"
) +
scale_y_continuous(labels = comma) +
theme_bw() +
theme(
legend.position = "top",
axis.text.x = element_text(angle = 45, hjust = 1),
panel.grid.major.y = element_line(color = "gray90"),
panel.grid.minor.y = element_blank()
)
# Save the chart
ggsave(
filename = "chart2.png", plot = chart, width = width, height = height,
units = "px", dpi = 72 * sf, device = grDevices::png, type = "cairo"
)
library(readr)
swing_states <- c("AZ", "GA", "MI", "NC", "NV", "PA", "WI")
df1 <- read_csv("https://election.lab.ufl.edu/data-downloads/turnoutdata/Turnout_1980_2022_v1.1.csv") |>
filter(YEAR %in% c(2016, 2020, 2024)) |>
select(STATE_ABV, YEAR, VEP, TOTAL_BALLOTS_COUNTED) |>
setNames(c("state", "year", "eligible_population", "votes"))
df2 <- read_csv("https://election.lab.ufl.edu/data-downloads/turnoutdata/Turnout_2024G_v0.3.csv") |>
mutate(YEAR = 2024) |>
select(STATE_ABV, YEAR, VEP, TOTAL_BALLOTS_COUNTED) |>
setNames(c("state", "year", "eligible_population", "votes"))
df <- rbind(df1, df2) |>
filter(!is.na(state)) |>
mutate(is_swing = state %in% swing_states) |>
group_by(year, is_swing) |>
summarize(
eligible_population = sum(eligible_population),
votes = sum(votes),
turnout = votes / eligible_population
) |>
select(year, is_swing, turnout)
# Generate plot
chart <-
ggplot(df, aes(x = is_swing, y = turnout, fill = is_swing)) +
geom_bar(
stat = "identity",
position = position_stack(reverse = TRUE)
) +
geom_text(
aes(label = scales::percent(turnout, accuracy = 0.1)),
position = position_stack(vjust = 0.5),
size = 4,
color = "white",
fontface = "bold"
) +
scale_fill_manual(values = c("TRUE" = "darkgreen", "FALSE" = "black")) +
facet_wrap(~year, nrow = 1) +
labs(
title = "2024 Swing State's Historical Popular Vote in US Presidential Elections",
subtitle = paste(
paste(swing_states, collapse = ", "),
"· @USMortality · Updated: 11/19/24 12:52pm"
),
caption = "Source: decisiondeskhq.com, election.lab.ufl.edu",
x = "Swing State",
y = "Turnout",
fill = "Swing State"
) +
scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
theme_bw() +
theme(
legend.position = "top",
axis.text.x = element_text(angle = 45, hjust = 1),
axis.ticks.x = element_line(color = "black")
)
ggsave(
filename = "chart3.png", plot = chart, width = width, height = height,
units = "px", dpi = 72 * sf, device = grDevices::png, type = "cairo"
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment