The map below shows voters (number of accepted ballots) by precinct in Washington in the 2024 general election. Hovering over the precinct shows the county and precinct name. Click on a precinct to see chart showing accepted ballots broken down by imputed race. The full dataset, “Voters by Race, Precinct, Year, and Election”, contains years 2020-2024, and is available for download in the Datasets tab, under Section 2.1.

Please allow up to 60 seconds for the interface to load

shp <- read_sf('P:/Projects/UWED/Master Team Folder/Data/Inputs/SoS/Precinct_Shapefiles/2024/Statewide_Precincts_2024General.shp')
cvap <- fread('P:/Projects/UWED/Master Team Folder/Data/Outputs/CVAP_by_Precinct_Race_2010-2024_2025-07-16.csv')
registrants <- fread('P:/Projects/UWED/Master Team Folder/Data/Outputs/Registrant_Population_by_Precinct_Race_Year2025-07-25.csv')
voters <- fread('P:/Projects/UWED/Master Team Folder/Data/Outputs/Voter_Population_by_Precinct_Race_Year2025-07-25.csv')
shp_no_geo <- st_drop_geometry(shp) 

  

registrants <- registrants %>%
    mutate(PrecName = tolower(PrecName)) %>%
    rename(precinctname = PrecName,
           countycode = County)

voters <- voters %>%
    mutate(PrecName = tolower(PrecName)) %>%
    rename(precinctname = PrecName,
           countycode = County)

make_voter_pl <- function(i, overwrite = FALSE, verbose = FALSE){
    message(i)
    x <- shp_no_geo[i,]
    # year-create image dirs
    # id, etc.
    stcode <- x$St_Code
    # county, precinct
    mycounty <- x$CountyName
    ctycode <- x$County
    myprecinct <- x$PrecinctNa
    myprecinctnum <- x$PrecinctNu
    mytitle <- str_c(mycounty, str_to_title(myprecinct), myprecinctnum, sep = ", " )

    vot_sub <- voters %>% 
        filter(St_Code == stcode,
               Election_date == "2024-11-05")

    all <- vot_sub %>%
      pivot_longer(cols = c('Total_Pop', "Black_Pop", "White_Pop", "Hispanic_Pop", "Asian_Pop", "OtherRace_Pop")) %>%
        rename(Race = name,
               Population = value) %>%
        filter(Race != "Total_Pop") %>%
        mutate(
            Race = str_remove_all(string = Race, pattern = "_Pop") %>%
                factor(levels = c("White", "Black", "Asian", "Hispanic", "OtherRace"), 
                       labels = c("White", "Black", "Asian", "Hispanic", "Other"))
        )
    
    
      
    g1 <- ggplot(data = all, aes(x = Race, y = Population)) +
         geom_col(aes(), show.legend = F) +
         theme_minimal() +
         geom_text(aes(label=ceiling(Population)), vjust = -1, color = "gray20") +
         ggtitle(paste0("Voting Population by Imputed Race in ", mycounty, " County, \n", str_to_title(myprecinct), " Precinct, ", " 2024 General Election")) +
         theme(axis.text.x = element_text(angle = 45, hjust=1)) +
         ylim(c(0, max(all$Population)+ 0.05*max(all$Population))) 


 return(g1)
}


# a function to create a pie chart
make_cvap_pl <- function(i, overwrite = FALSE, verbose = FALSE){
    message(i)
    x <- shp_no_geo[i,]
    # year-create image dirs
    # id, etc.
    stcode <- x$St_Code
    # county, precinct
    mycounty <- x$CountyName
    ctycode <- x$County
    myprecinct <- x$PrecinctNa
    myprecinctnum <- x$PrecinctNu
    mytitle <- str_c(mycounty, str_to_title(myprecinct), myprecinctnum, sep = ", " )

    cvap_sub <- cvap %>% 
        filter(St_Code == stcode,
               Year == 2024)

    all <- cvap_sub %>%
       mutate(Other = AIAN_White_CVAP + Asian_White_CVAP + Black_White_CVAP + TwoOrMore_CVAP + AIAN_Black_CVAP) %>%
      select(-Total_CVAP,-NotHispanic_CVAP, -AIAN_White_CVAP, -Asian_White_CVAP, -Black_White_CVAP, -TwoOrMore_CVAP, -AIAN_Black_CVAP) %>%
      rename(AIAN = AIANAlone_CVAP,
             Asian = AsianAlone_CVAP,
             Black = BlackAlone_CVAP,
             NHOPI = NHOPIAlone_CVAP,
             White = WhiteAlone_CVAP,
             Hispanic = Hispanic_CVAP) %>%
      pivot_longer(cols = c("White", "Black", "Hispanic", "AIAN", "Asian", "NHOPI", "Other")) %>%
        rename(Race = name,
               Population = value) %>%
      mutate(
            Race = 
                factor(Race, levels = c("White", "Black", "Hispanic","AIAN", "Asian","NHOPI", "Other"), 
                       labels = c("White", "Black", "Hispanic","AIAN", "Asian","NHOPI", "Other"))
        )

    
      
    g1 <- ggplot(data = all, aes(x = Race, y = Population)) +
         geom_col( show.legend = F) +
         theme_minimal() +
         geom_text(aes(label=ceiling(Population)), vjust = -1, color = "gray20") +
         ggtitle(paste0("Citizen Voting Age Population by Race in ", mycounty, " County, \n", str_to_title(myprecinct), " Precinct, ", " 2024")) +
         theme(axis.text.x = element_text(angle = 45, hjust=1)) +
         ylim(c(0, max(all$Population)+ 0.05*max(all$Population))) +
         labs(caption = "*AIAN: American Indian/Alaska Native\nNHOPI: Native Hawaiin/Pacific Islander ")

 return(g1)
}

make_reg_pl <- function(i, overwrite = FALSE, verbose = FALSE){
    message(i)
    x <- shp_no_geo[i,]
    # year-create image dirs
    # id, etc.
    stcode <- x$St_Code
    # county, precinct
    mycounty <- x$CountyName
    ctycode <- x$County
    myprecinct <- x$PrecinctNa
    myprecinctnum <- x$PrecinctNu
    mytitle <- str_c(mycounty, str_to_title(myprecinct), myprecinctnum, sep = ", " )

    reg_sub <- registrants %>% 
        filter(St_Code == stcode,
               Year == "2024")

    all <- reg_sub %>%
      pivot_longer(cols = c('Total_Pop', "Black_Pop", "White_Pop", "Hispanic_Pop", "Asian_Pop", "OtherRace_Pop")) %>%
        rename(Race = name,
               Population = value) %>%
        filter(Race != "Total_Pop") %>%
        mutate(
            Race = str_remove_all(string = Race, pattern = "_Pop") %>%
                factor(levels = c("White", "Black", "Asian", "Hispanic", "OtherRace"), 
                       labels = c("White", "Black", "Asian", "Hispanic", "Other"))
        )
    
    
      
    g1 <- ggplot(data = all, aes(x = Race, y = Population)) +
         geom_col(aes(), show.legend = F) +
         theme_minimal() +
         geom_text(aes(label=ceiling(Population)), vjust = -1, color = "gray20") +
         ggtitle(paste0("Voter Registrant Population by Imputed Race in ", mycounty, " County, \n", str_to_title(myprecinct), " Precinct, ", " 2024 General Election")) +
         theme(axis.text.x = element_text(angle = 45, hjust=1)) +
         ylim(c(0, max(all$Population)+ 0.05*max(all$Population))) 


 return(g1)
}

#cvap_pls <- lapply(c(1:nrow(shp_no_geo)), make_cvap_pl)
vote_pls <- lapply(c(1:nrow(shp_no_geo)), make_voter_pl)
#reg_pls <- lapply(c(1:nrow(shp_no_geo)), make_reg_pl)



# labels for hover
labels <- shp_no_geo %>%
    mutate(labs = paste0("County: ", CountyName, "<br  />Precinct: ", str_to_title(PrecinctNa)))%>%
    pull(labs) %>% 
    lapply(htmltools::HTML)

shp_simple <- shp
#shp_simple <- ms_simplify(shp, keep_shapes = TRUE)

# cvap <- leaflet(data = shp_simple, width = "100%") %>%
#     addProviderTiles(providers$CartoDB.Positron) %>%
#     addPolygons(weight = 2, label = ~labels, group = "shp_simple", color = 'gray',
#                 fillColor = 'gray', opacity = 0.5,
#                 highlight = highlightOptions(
#                       weight = 3,
#                       fillOpacity = 0.6,
#                       color = "gray",
#                       opacity = 1.0,
#                       bringToFront = TRUE,
#                       sendToBack = TRUE) ) %>% 
#     leafpop::addPopupGraphs(graph = cvap_pls, group = "shp_simple", height = 450, width = 300)

# registrants <- leaflet(data = shp_simple, width = "100%") %>%
#     addProviderTiles(providers$CartoDB.Positron) %>%
#     addPolygons(weight = 2, label = ~labels, group = "shp_simple", color = 'gray',
#                 fillColor = 'gray', opacity = 0.5,
#                 highlight = highlightOptions(
#                       weight = 3,
#                       fillOpacity = 0.6,
#                       color = "gray",
#                       opacity = 1.0,
#                       bringToFront = TRUE,
#                       sendToBack = TRUE) ) %>%
#     leafpop::addPopupGraphs(graph = reg_pls, group = "shp_simple", height = 450, width = 300)


voters <- leaflet(data = shp_simple, width = "100%") %>%
    addProviderTiles(providers$CartoDB.Positron) %>%
    addPolygons(weight = 2, label = ~labels, group = "shp_simple", color = 'gray',
                fillColor = 'gray', opacity = 0.5,
                highlight = highlightOptions(
                      weight = 3,
                      fillOpacity = 0.6,
                      color = "gray",
                      opacity = 1.0,
                      bringToFront = TRUE,
                      sendToBack = TRUE) ) %>%
    leafpop::addPopupGraphs(graph = vote_pls, group = "shp_simple", height = 450, width = 300)

#cvap
#registrants
voters