Even though Davidson County is the fifth fastest growing city per 100 residents in the last five years, there is no denying how many people live there. According to the U.S. Census, it has the highest population density within the Nashville-Metropolitan area despite being the seven biggest county. In fact, it has nearly 1,000 residents per square mile more than Rutherford County. What is interesting is that most of the largest counties have a high percentage change within the last five years, yet they do not have as high of a population density compared to Davidson County.
Below is a table that represents the latest data from the U.S. Census Bureau’s American Community Survey which includes the counties’ land area and population density. It is sorted by population density, starting with Davidson County at about 1,419 people per square mile.
| County | CurrentPop | EarlierPop | Region | Change | Percent_change | Square_Miles | Density | Density_Category |
|---|---|---|---|---|---|---|---|---|
| Davidson | 715388 | 598184 | Davidson | 117204 | 0.1959330 | 504 | 1419.42063 | High Density |
| Rutherford | 360646 | 292425 | Doughnut | 68221 | 0.2332940 | 620 | 581.68710 | High Density |
| Williamson | 260351 | 208242 | Doughnut | 52109 | 0.2502329 | 583 | 446.57118 | Medium Density |
| Sumner | 204424 | 174773 | Doughnut | 29651 | 0.1696544 | 529 | 386.43478 | Medium Density |
| Wilson | 158805 | 129918 | Doughnut | 28887 | 0.2223479 | 571 | 278.11734 | Medium Density |
| Maury | 107791 | 88738 | Non-doughnut | 19053 | 0.2147107 | 613 | 175.84176 | Medium Density |
| Robertson | 75539 | 67517 | Doughnut | 8022 | 0.1188145 | 476 | 158.69538 | Medium Density |
| Cheatham | 41829 | 39087 | Doughnut | 2742 | 0.0701512 | 302 | 138.50662 | Medium Density |
| Dickson | 55983 | 51608 | Non-doughnut | 4375 | 0.0847737 | 490 | 114.25102 | Medium Density |
| Trousdale | 11957 | 10131 | Non-doughnut | 1826 | 0.1802389 | 114 | 104.88596 | Medium Density |
| Macon | 26240 | 23261 | Non-doughnut | 2979 | 0.1280684 | 307 | 85.47231 | Low Density |
| Smith | 20389 | 19389 | Non-doughnut | 1000 | 0.0515756 | 314 | 64.93312 | Low Density |
| Cannon | 14818 | 13958 | Non-doughnut | 860 | 0.0616134 | 266 | 55.70677 | Low Density |
| Hickman | 25436 | 24561 | Non-doughnut | 875 | 0.0356256 | 612 | 41.56209 | Low Density |
Below is the R code used to produce the analysis.
# ============================================================
# Step 1: Install and load required packages
# ============================================================
if (!require("tidyverse")) {
install.packages("tidyverse")
}
library(tidyverse)
if (!require("knitr")) {
install.packages("knitr")
}
library(knitr)
if (!require("kableExtra")) {
install.packages("kableExtra")
}
library(kableExtra)
# ============================================================
# Step 2: Create a vector containing county names
# ============================================================
County <- c("Cannon", "Cheatham", "Davidson", "Dickson", "Hickman", "Macon",
"Maury", "Robertson", "Rutherford", "Smith", "Sumner", "Trousdale",
"Williamson", "Wilson")
# ============================================================
# Step 3: Create a vector containing current population values
# ============================================================
CurrentPop <- c(14818, 41829, 715388, 55983, 25436, 26240, 107791, 75539,
360646, 20389, 204424, 11957, 260351, 158805)
# ============================================================
# Step 4: Create a vector containing earlier population values
# ============================================================
EarlierPop <- c(13958, 39087, 598184, 51608, 24561, 23261, 88738, 67517,
292425, 19389, 174773, 10131, 208242, 129918)
# ============================================================
# Step 5: Create a vector identifying each county's region
# ============================================================
Region <- c("Non-doughnut", "Doughnut", "Davidson", "Non-doughnut",
"Non-doughnut", "Non-doughnut", "Non-doughnut", "Doughnut",
"Doughnut", "Non-doughnut", "Doughnut", "Non-doughnut",
"Doughnut", "Doughnut")
# ============================================================
# Step 6: Combine vectors into a Population data frame
# ============================================================
Population <- data.frame(
County,
CurrentPop,
EarlierPop,
Region
)
# ============================================================
# Step 7: Display the Population data frame
# ============================================================
Population
# ============================================================
# Step 8: Sort the Population data frame by CurrentPop
# in descending order
# ============================================================
Population <- Population %>%
arrange(desc(CurrentPop))
# ============================================================
# Step 9: Display the sorted Population data frame
# ============================================================
Population
# ============================================================
# Step 10: Add a Change variable showing population growth
# (CurrentPop minus EarlierPop)
# ============================================================
Population <- Population %>%
mutate(Change = CurrentPop - EarlierPop)
# ============================================================
# Step 11: Display the updated data frame with Change
# ============================================================
Population
# ============================================================
# Step 12: Create a Change_only data frame containing
# County and Change, sorted by Change descending
# ============================================================
Change_only <- Population %>%
select(County, Change) %>%
arrange(desc(Change))
# ============================================================
# Step 13: Display the Change_only data frame
# ============================================================
Change_only
# ============================================================
# Step 14: Create a Doughnut data frame containing only
# Davidson and Doughnut region counties, sorted
# by Change descending
# ============================================================
Doughnut <- Population %>%
filter(Region %in% c("Davidson", "Doughnut")) %>%
arrange(desc(Change))
# ============================================================
# Step 15: Display the Doughnut data frame
# ============================================================
Doughnut
# ============================================================
# Step 16: Create a Summary data frame that totals
# CurrentPop, EarlierPop, and Change by Region
# ============================================================
Summary <- Population %>%
group_by(Region) %>%
summarize(
CurrentPop = sum(CurrentPop),
EarlierPop = sum(EarlierPop),
Change = sum(Change)
)
# ============================================================
# Step 17: Display the Summary data frame
# ============================================================
Summary
# ============================================================
# Step 18: Copy the Population data frame to Population_v2
# ============================================================
Population_v2 <- Population
# ============================================================
# Step 19: Add a Percent_change variable to Population_v2
# (Change divided by EarlierPop)
# ============================================================
Population_v2 <- Population_v2 %>%
mutate(Percent_change = Change / EarlierPop)
# ============================================================
# Step 20: Sort Population_v2 by Percent_change
# in descending order
# ============================================================
Population_v2 <- Population_v2 %>%
arrange(desc(Percent_change))
# ============================================================
# Step 21: Display the Population_v2 data frame
# ============================================================
Population_v2
# ============================================================
# Step 22: Create and display a formatted table for
# the Population data frame
# ============================================================
Population_tbl <- Population %>%
kbl(caption = "Population Data") %>%
kable_styling(full_width = FALSE)
Population_tbl
# ============================================================
# Step 23: Create and display a formatted table for
# the Change_only data frame
# ============================================================
Change_only_tbl <- Change_only %>%
kbl(caption = "Population Change by County") %>%
kable_styling(full_width = FALSE)
Change_only_tbl
# ============================================================
# Step 24: Create and display a formatted table for
# the Doughnut data frame
# ============================================================
Doughnut_tbl <- Doughnut %>%
kbl(caption = "Davidson and Doughnut Counties") %>%
kable_styling(full_width = FALSE)
Doughnut_tbl
# ============================================================
# Step 25: Create and display a formatted table for
# the Summary data frame
# ============================================================
Summary_tbl <- Summary %>%
kbl(caption = "Regional Population Summary") %>%
kable_styling(full_width = FALSE)
Summary_tbl
# ============================================================
# Step 26: Create and display a formatted table for
# the Population_v2 data frame
# ============================================================
Population_v2_tbl <- Population_v2 %>%
kbl(caption = "Population Growth Rates") %>%
kable_styling(full_width = FALSE)
Population_v2_tbl
# ============================================================
# Download Tennessee County Gazetteer File
# ============================================================
# Import county land-area data from the U.S. Census Bureau.
TN_Counties <- read_delim(
"https://www2.census.gov/geo/docs/maps-data/data/gazetteer/2025_Gazetteer/2025_gaz_counties_47.txt",
delim = "|",
show_col_types = FALSE
)
# ============================================================
# Create Land_Area Data Frame
# ============================================================
# Keep county name and land area in square miles.
# Remove " County" from county names.
# Round land area to the nearest whole square mile.
Land_Area <- TN_Counties %>%
transmute(
County = str_remove(NAME, " County"),
Square_Miles = round(ALAND_SQMI)
)
# ============================================================
# Display Results
# ============================================================
# View the completed land-area data frame.
Land_Area
library(dplyr)
Population_v2 <- Population_v2 %>%
left_join(
Land_Area %>% select(County, Square_Miles),
by = "County"
)%>%
mutate(Density = CurrentPop / Square_Miles)
library(dplyr)
Population_v2 <- Population_v2 %>%
mutate(
Density_Category = case_when(
Density >= 500 ~ "High Density",
Density >= 100 & Density <= 499 ~ "Medium Density",
Density < 100 ~ "Low Density"
)
)
library(dplyr)
Population_v2 <- Population_v2 %>%
arrange(desc(Density))
# Create kableExtra-formatted tables
Population_v2_table <- Population_v2 %>%
kable("html") %>%
kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover"))
Land_Area_table <- Land_Area %>%
kable("html") %>%
kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover"))
# Display the tables
Population_v2_table
Land_Area_table