This interactive map shows Tennessee’s tract-level Black population counts and percentages from the 2020 Census, along with borders for the state’s nine U.S. House districts before the Tennessee General Assembly redrew them in 2022.
This interactive map shows Tennessee’s tract-level Black population counts and percentages from the 2020 Census, along with borders for the state’s nine U.S. House districts after the Tennessee General Assembly redrew them in 2022.
Click or tap a tract for details. Some tracts have no data due to exceptionally small population counts. Zoom or pan to explore specific areas. Click or tap the map layer icon in the lower-left corner to switch base maps.
The R code below produced the maps. It uses the tidycensus package to pull data from the 2020 U.S. Census and the 2023 American Community Survey.
# ============================================================
# 0. INSTALL AND LOAD REQUIRED PACKAGES
# ============================================================
if (!require("tidyverse")) install.packages("tidyverse")
if (!require("tidycensus")) install.packages("tidycensus")
if (!require("sf")) install.packages("sf")
if (!require("leaflet")) install.packages("leaflet")
if (!require("leaflet.extras2")) install.packages("leaflet.extras2")
library(tidyverse)
library(tidycensus)
library(sf)
library(leaflet)
library(leaflet.extras2)
# ============================================================
# 1. CENSUS API KEY
# ============================================================
# census_api_key("PasteYourAPIKeyBetweenTheseQuoteMarks", install = TRUE)
# ============================================================
# 2. FETCH 2020 CENSUS TRACT DATA (PL 94-171)
# ============================================================
tract_data <- get_decennial(
geography = "tract",
state = "TN",
variables = c(
Hispanic = "P2_002N",
White = "P2_005N",
Black = "P2_006N",
Native = "P2_007N",
Asian = "P2_008N"
),
summary_var = "P2_001N",
year = 2020,
geometry = TRUE
) %>%
mutate(percent = 100 * (value / summary_value)) %>%
filter(variable == "Black") %>%
st_transform(4326)
# ============================================================
# 3. COLOR PALETTE (SHARED)
# ============================================================
pal <- colorNumeric(
palette = "viridis",
domain = tract_data$percent,
na.color = "transparent"
)
# ============================================================
# 4. POPUP FUNCTION (SHARED)
# ============================================================
popup_text <- ~paste0(
"<b>", NAME, "</b><br>",
"Tract GEOID: ", GEOID, "<br><br>",
"Black population: ", scales::comma(value), "<br>",
"Total population: ", scales::comma(summary_value), "<br>",
"<b>Percent Black: ", round(percent, 1), "%</b>"
)
# ============================================================
# 5. CONGRESSIONAL DISTRICTS – BEFORE REDISTRICTING (2020)
# ============================================================
cd_2020 <- get_decennial(
geography = "congressional district",
state = "TN",
variables = "P2_001N", # dummy variable
year = 2020,
geometry = TRUE
) %>%
st_transform(4326)
# ============================================================
# 6. CONGRESSIONAL DISTRICTS – AFTER REDISTRICTING (POST‑2022)
# ============================================================
cd_2023 <- get_acs(
geography = "congressional district",
state = "TN",
variables = "B01001_001", # dummy variable
year = 2023,
survey = "acs5",
geometry = TRUE
) %>%
st_transform(4326)
# ============================================================
# 7. MAP 1: BEFORE REDISTRICTING
# ============================================================
BlackPct_PreRedistricting <- leaflet(tract_data) %>%
addProviderTiles("CartoDB.Positron", group = "Positron (Light)") %>%
addProviderTiles("Esri.WorldStreetMap", group = "ESRI Streets") %>%
addProviderTiles("Esri.WorldImagery", group = "ESRI Satellite") %>%
addPolygons(
fillColor = ~pal(percent),
fillOpacity = 0.75,
color = "#444444",
weight = 0.4,
popup = popup_text
) %>%
addPolylines(
data = cd_2020,
color = "black",
weight = 2,
opacity = 0.9
) %>%
addLegend(
pal = pal,
values = ~percent,
title = "Percent Black",
position = "topright"
) %>%
addLayersControl(
baseGroups = c(
"Positron (Light)",
"ESRI Streets",
"ESRI Satellite"
),
options = layersControlOptions(
collapsed = TRUE,
position = "bottomleft"
)
)
BlackPct_PreRedistricting
# ============================================================
# 8. MAP 2: AFTER REDISTRICTING
# ============================================================
BlackPct_PostRedistricting <- leaflet(tract_data) %>%
addProviderTiles("CartoDB.Positron", group = "Positron (Light)") %>%
addProviderTiles("Esri.WorldStreetMap", group = "ESRI Streets") %>%
addProviderTiles("Esri.WorldImagery", group = "ESRI Satellite") %>%
addPolygons(
fillColor = ~pal(percent),
fillOpacity = 0.75,
color = "#444444",
weight = 0.4,
popup = popup_text
) %>%
addPolylines(
data = cd_2023,
color = "black",
weight = 2,
opacity = 0.9
) %>%
addLegend(
pal = pal,
values = ~percent,
title = "Percent Black",
position = "topright"
) %>%
addLayersControl(
baseGroups = c(
"Positron (Light)",
"ESRI Streets",
"ESRI Satellite"
),
options = layersControlOptions(
collapsed = TRUE,
position = "bottomleft"
)
)
BlackPct_PostRedistricting