Created
November 11, 2025 21:09
-
-
Save tor-gu/26ece04c44cc8e84532664f079c53dbf to your computer and use it in GitHub Desktop.
Generate a map comparing the performance of Kim vs Harris in NJ in 2024
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| library(tigris) | |
| library(njmunicipalities) | |
| library(njelections) | |
| library(purrr) | |
| library(dplyr) | |
| library(ggplot2) | |
| library(tidyr) | |
| library(glue) | |
| library(stringr) | |
| # Get the county names | |
| county_names <- njmunicipalities::counties |> pull(county) | |
| # Get the map of NJ | |
| options(tigris_use_cache = TRUE) | |
| nj_municipality_map <- county_names %>% | |
| map_df( ~ county_subdivisions("NJ", county = ., class = "sf")) |> | |
| filter(ALAND > 0) | |
| # Get a map of congressional district NJ-03 | |
| nj_03_map <- congressional_districts(state="NJ", year=2024) |> filter(GEOID==3403) | |
| # Calculate the statewide Kim - Harris vote share delta | |
| kim_harris_delta <- election_statewide |> | |
| filter(year==2024) |> | |
| filter(party %in% c("Democratic", "Republican")) |> | |
| select(office, party, vote) |> | |
| group_by(office) |> | |
| mutate(vote_share=vote/sum(vote)) |> | |
| filter(party=="Democratic") |> | |
| select(office, vote_share) |> | |
| arrange(office) |> # This will put President before Senate | |
| pull(vote_share) |> diff() | |
| # Calculate the relative delta of Kim over Harris by municipality | |
| delta_by_geoid <- election_by_municipality |> | |
| filter(year==2024) |> | |
| filter(party %in% c("Democratic", "Republican")) |> | |
| select(GEOID, office, party, vote) |> | |
| group_by(GEOID, office) |> | |
| mutate(vote_share=vote/sum(vote)) |> | |
| ungroup() |> | |
| filter(party=="Democratic") |> | |
| select(GEOID, office, vote_share) |> | |
| pivot_wider(names_from=office, values_from = vote_share) |> | |
| mutate(delta=Senate-President-kim_harris_delta) |> | |
| select(GEOID, delta) | |
| # Now glue our election data to the map | |
| map_with_values <- nj_municipality_map |> | |
| left_join(delta_by_geoid, by="GEOID") | |
| # Plot our map | |
| plot_kim_harris <- map_with_values |> | |
| ggplot() + | |
| geom_sf(aes(fill=delta, geometry=geometry, size=.2)) + | |
| geom_sf(data=nj_03_map, color="darkgreen", fill=NA, aes(geometry=geometry, size=.6)) + | |
| ggrepel::geom_label_repel( | |
| data=nj_03_map, | |
| color="darkgreen", | |
| mapping = aes(label = "NJ-03", geometry = geometry), | |
| stat = "sf_coordinates", | |
| nudge_x = -.5, | |
| nudge_y = .2, | |
| ) + | |
| scale_size_identity() + | |
| scale_fill_gradient2( | |
| na.value = "lightgrey", | |
| low = "purple", | |
| high = "green", | |
| mid = "lightgrey", | |
| midpoint = kim_harris_delta, | |
| limits = c(-.05,.05), | |
| oob = scales::squish, | |
| breaks = c(-.05, 0, .05), | |
| labels=c("More Harris", glue("State Average (Kim +{round(kim_harris_delta, 3)})"), "More Kim"), | |
| name="Margin" | |
| ) + | |
| theme( | |
| axis.ticks = element_blank(), | |
| axis.text.x = element_blank(), | |
| axis.text.y = element_blank(), | |
| axis.title.x = element_blank(), | |
| axis.title.y = element_blank(), | |
| panel.background = element_rect(fill = "lightblue"), | |
| panel.grid.major = element_line(color = "lightblue"), | |
| legend.position = "bottom", | |
| legend.key.width = unit(2, "cm"), | |
| legend.title = element_blank(), | |
| plot.title = element_text(hjust=0.5), | |
| plot.subtitle = element_text(hjust=0.5), | |
| plot.title.position = "panel", | |
| ) + | |
| labs(title=str_wrap("Relative overperformance of Andy Kim vs. Kamala Harris", width=45), | |
| subtitle = str_wrap("Two-party vote share in elections for Senate and President 2024", width=50), | |
| caption="Source: NJ Division of Elections") | |
| # Save plot | |
| # ggsave("kim_harris.png", plot = plot_kim_harris ) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment