This interactive map shows precinct-level results from the 2024 U.S. presidential election in Tennessee, along with borders for the state’s nine U.S. House districts after the 2022 redistricting. Redder shades indicate higher Republican margins, while bluer shades indicate higher Democratic margins. Data and precinct boundaries come from The New York Times and match the Tennessee portion of the Times’ Extremely Detailed Map of the 2024 Election.
Click or tap a precinct for details. Zoom or pan to explore specific areas. Click or tap the map layer icon in the lower-left corner to switch base maps.
This table shows approximate vote totals for each House district, based on the totals of each precinct within the district. If a precinct fell within two or more districts, the analysis placed the precinct within the district that contained the precinct’s geographic center.
| District | Dem Votes | GOP Votes | Total Votes | Dem % | GOP % | GOP Margin |
|---|---|---|---|---|---|---|
| Congressional District 1 (118th Congress), Tennessee | 71,440 | 272,148 | 347,144 | 20.6% | 78.4% | 57.8% |
| Congressional District 2 (118th Congress), Tennessee | 118,987 | 243,979 | 368,028 | 32.3% | 66.3% | 34.0% |
| Congressional District 3 (118th Congress), Tennessee | 113,598 | 243,930 | 362,269 | 31.4% | 67.3% | 36.0% |
| Congressional District 4 (118th Congress), Tennessee | 93,068 | 240,013 | 337,108 | 27.6% | 71.2% | 43.6% |
| Congressional District 5 (118th Congress), Tennessee | 148,153 | 212,052 | 366,086 | 40.5% | 57.9% | 17.5% |
| Congressional District 6 (118th Congress), Tennessee | 114,886 | 243,100 | 362,445 | 31.7% | 67.1% | 35.4% |
| Congressional District 7 (118th Congress), Tennessee | 128,974 | 203,330 | 337,242 | 38.2% | 60.3% | 22.0% |
| Congressional District 8 (118th Congress), Tennessee | 101,873 | 246,787 | 352,663 | 28.9% | 70.0% | 41.1% |
| Congressional District 9 (118th Congress), Tennessee | 165,286 | 61,526 | 230,957 | 71.6% | 26.6% | -44.9% |
This R code produced the map and table shown above.
# ============================================================
# Step 0. INSTALL AND LOAD REQUIRED PACKAGES
# ============================================================
if (!require("tidyverse")) install.packages("tidyverse")
if (!require("sf")) install.packages("sf")
if (!require("leaflet")) install.packages("leaflet")
if (!require("leaflet.extras2")) install.packages("leaflet.extras2")
if (!require("tidycensus")) install.packages("tidycensus")
if (!require("kableExtra")) install.packages("kableExtra")
library(tidyverse)
library(sf)
library(leaflet)
library(leaflet.extras2)
library(tidycensus)
library(kableExtra)
# ============================================================
# Step 1. READ PRECINCT-LEVEL 2024 RESULTS
# ============================================================
precincts <- st_read(
"TN-precincts-with-results.geojson",
quiet = TRUE
) %>%
st_transform(4326)
# ============================================================
# Step 2. DERIVE REPUBLICAN MARGIN
# ============================================================
precincts <- precincts %>%
mutate(
pct_rep_lead = (votes_rep - votes_dem) / votes_total
)
# ============================================================
# Step 3. SIMPLIFY PRECINCT GEOMETRY (FILE-SIZE REDUCTION)
# ============================================================
sf::sf_use_s2(FALSE)
precincts_simplified <- st_simplify(
precincts,
dTolerance = 0.0002,
preserveTopology = TRUE
)
sf::sf_use_s2(TRUE)
# ============================================================
# Step 4. LOAD POST-2022 CONGRESSIONAL DISTRICTS
# ============================================================
congressional_districts <- get_acs(
geography = "congressional district",
state = "TN",
variables = "B01001_001",
year = 2023,
survey = "acs5",
geometry = TRUE
) %>%
st_transform(4326) %>%
select(
district_geoid = GEOID,
district_name = NAME,
geometry
)
# ============================================================
# Step 5. MAP PRECINCT RESULTS (POSITRON DEFAULT + BASEMAP SWITCHER)
# ============================================================
pal <- colorNumeric(
palette = "RdBu",
domain = precincts_simplified$pct_rep_lead,
reverse = TRUE,
na.color = "transparent"
)
TN_Precinct_Map <- leaflet(precincts_simplified) %>%
# --- BASE MAPS (ORDER MATTERS: FIRST IS DEFAULT) ---
addProviderTiles("CartoDB.Positron", group = "Positron (Light)") %>%
addProviderTiles("Esri.WorldStreetMap", group = "Street Map") %>%
addProviderTiles("Esri.WorldImagery", group = "Satellite") %>%
# --- PRECINCT RESULTS ---
addPolygons(
fillColor = ~pal(pct_rep_lead),
fillOpacity = 0.75,
color = "#555555",
weight = 0.25,
popup = ~paste0(
"<b>Precinct GEOID:</b> ", GEOID, "<br><br>",
"<b>Dem votes:</b> ", scales::comma(votes_dem), "<br>",
"<b>Republican votes:</b> ", scales::comma(votes_rep), "<br>",
"<b>Total votes:</b> ", scales::comma(votes_total), "<br><br>",
"<b>Republican margin:</b> ",
round(100 * pct_rep_lead, 1), " pts"
),
group = "2024 Precinct Results"
) %>%
# --- CONGRESSIONAL DISTRICTS ---
addPolylines(
data = congressional_districts,
color = "black",
weight = 2,
opacity = 0.9,
group = "Congressional Districts"
) %>%
# --- LEGEND ---
addLegend(
pal = pal,
values = ~pct_rep_lead,
title = "Republican margin<br>(percentage points)",
position = "topright",
labFormat = labelFormat(
transform = function(x) x * 100,
suffix = "%"
)
) %>%
# --- LAYERS CONTROL (LOWER LEFT) ---
addLayersControl(
baseGroups = c(
"Positron (Light)",
"Street Map",
"Satellite"
),
overlayGroups = c(
"2024 Precinct Results",
"Congressional Districts"
),
options = layersControlOptions(
collapsed = TRUE,
position = "bottomleft"
)
)
TN_Precinct_Map
# ============================================================
# Step 6. ASSIGN PRECINCTS TO DISTRICTS (OPTION A)
# ============================================================
precinct_centroids <- precincts_simplified %>%
st_point_on_surface()
precincts_with_district <- precinct_centroids %>%
st_join(
congressional_districts,
join = st_within
)
# ============================================================
# Step 7. AGGREGATE PRECINCT VOTES TO DISTRICT TOTALS
# ============================================================
district_results <- precincts_with_district %>%
st_drop_geometry() %>%
group_by(district_name) %>%
summarise(
Dem_Votes = sum(votes_dem, na.rm = TRUE),
GOP_Votes = sum(votes_rep, na.rm = TRUE),
Total_Votes = sum(votes_total, na.rm = TRUE),
.groups = "drop"
) %>%
mutate(
`Dem %` = sprintf("%.1f%%", 100 * Dem_Votes / Total_Votes),
`GOP %` = sprintf("%.1f%%", 100 * GOP_Votes / Total_Votes),
`GOP Margin` = sprintf("%.1f%%",
100 * (GOP_Votes - Dem_Votes) / Total_Votes),
`Dem Votes` = scales::comma(Dem_Votes),
`GOP Votes` = scales::comma(GOP_Votes),
`Total Votes` = scales::comma(Total_Votes)
) %>%
select(
District = district_name,
`Dem Votes`,
`GOP Votes`,
`Total Votes`,
`Dem %`,
`GOP %`,
`GOP Margin`
)
# ============================================================
# Step 8. FORMAT AND DISPLAY DISTRICT RESULTS TABLE
# ============================================================
Table <- district_results %>%
kbl(
format = "html",
caption =
"2024 Presidential Election Results by Congressional District (Tennessee)",
align = "lrrrrrr"
) %>%
kable_styling(
full_width = FALSE,
bootstrap_options = c("striped", "hover", "condensed")
) %>%
row_spec(0, bold = TRUE)
Table