La’Vergne and Murfreesboro lead the Davidson County subdivisions in Employed 19 and 64-year-olds with no health insurance

District One, in La’Vergne leads the subdivisions with 1,859 persons who match the criteria while District Thirteen, in Murfeesboro, seconds it with 1,844.

Code:

# ----------------------------------------------------------
# Step 1: Install required packages (if missing)
# ----------------------------------------------------------

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("htmlwidgets"))
  install.packages("htmlwidgets")
if (!require("plotly"))
  install.packages("plotly")   # For the interactive dot plot

# ----------------------------------------------------------
# Step 2: Load libraries
# ----------------------------------------------------------

library(tidyverse)
library(tidycensus)
library(sf)
library(leaflet)
library(htmlwidgets)
library(plotly)

# ----------------------------------------------------------
# Step 3: Transmit Census API key (uncomment and paste yours)
# ----------------------------------------------------------

census_api_key("904ea9b9c6b5f8f7d6b1d4846a59ee8cc3b48d1f")

# ----------------------------------------------------------
# Step 4: Fetch ACS codebooks (for variable lookup if needed)
# ----------------------------------------------------------

DetailedTables <- load_variables(2024, "acs5", cache = TRUE)
SubjectTables  <- load_variables(2024, "acs5/subject", cache = TRUE)
ProfileTables  <- load_variables(2024, "acs5/profile", cache = TRUE)

# ----------------------------------------------------------
# Step 5: Specify target variable(s)
# ----------------------------------------------------------

VariableList <- c(Estimate_ = "DP03_0108")

# ----------------------------------------------------------
# Step 6: Fetch ACS data (county subdivision, Tennessee)
# ----------------------------------------------------------

mydata <- get_acs(
  geography = "county subdivision",
  state = "TN",
  variables = VariableList,
  year = 2024,
  survey = "acs5",
  output = "wide",
  geometry = TRUE
)

# ----------------------------------------------------------
# Step 7: Reformat the NAME field into Area / County / State
# ----------------------------------------------------------

mydata <- separate_wider_delim(
  mydata,
  NAME,
  delim = ", ",
  names = c("Area", "County", "State")
)

# ----------------------------------------------------------
# Step 8: Filter to Rutherford County
# ----------------------------------------------------------

filtereddata <- mydata %>%
  filter(County %in% c("Rutherford County"))

# ----------------------------------------------------------
# Step 9: Prepare data for mapping (rename, as sf, CRS)
# ----------------------------------------------------------

mapdata <- filtereddata %>%
  rename(
    Estimate = Estimate_E,
    Range = Estimate_M
  ) %>%
  st_as_sf()

# Ensure CRS is WGS84 for Leaflet
mapdata <- st_transform(mapdata, 4326)

# ----------------------------------------------------------
# Step 10: Build color palette with quantile-based breaks
# ----------------------------------------------------------

qs <- quantile(mapdata$Estimate, probs = seq(0, 1, length.out = 6), na.rm = TRUE)

pal <- colorBin(
  palette = "Blues", # Can specify other palettes here
  domain = mapdata$Estimate,
  bins = qs,
  pretty = FALSE
)

# ----------------------------------------------------------
# Step 11: Build the plotly dot plot with error bars
# ----------------------------------------------------------

# Add point color from the same Leaflet palette and ordered y factor
filtereddata <- filtereddata %>%
  mutate(
    point_color = pal(Estimate_E),
    y_ordered   = reorder(Area, Estimate_E),
    hover_text  = dplyr::if_else(
      !is.na(Area),
      paste0("Area: ", Area),
      Area
    )
  )

# Create the plotly scatter with horizontal error bars and thin gray borders
mygraph <- plot_ly(
  data = filtereddata,
  x = ~Estimate_E,
  y = ~y_ordered,
  type = "scatter",
  mode = "markers",
  marker = list(
    color = ~point_color,
    size  = 8,
    line  = list(
      color = "rgba(120,120,120,0.9)",  # thin gray border for contrast
      width = 0.5
    )
  ),
  error_x = list(
    type       = "data",
    array      = ~Estimate_M,      # + side
    arrayminus = ~Estimate_M,      # - side
    color      = "rgba(0,0,0,0.65)",
    thickness  = 1
  ),
  text = ~hover_text,
  # Show District (from hover_text) and the X value with thousands separators
  hovertemplate = "%{text}<br>%{x:,}<extra></extra>"
) %>%
  layout(
    title = list(text = "Estimates by area<br><sup>County subdivisions. Brackets show error margins.</sup>"),
    xaxis = list(title = "ACS estimate"),
    yaxis = list(title = "")
  )

# display the plot
mygraph

# ----------------------------------------------------------
# Step 12: Create popup content for the map
# ----------------------------------------------------------

mapdata$popup <- paste0(
  "<strong>", mapdata$Area, "</strong><br/>",
  "<hr>",
  "Estimate: ", format(mapdata$Estimate, big.mark = ","), "<br/>",
  "Plus/Minus: ", format(mapdata$Range, big.mark = ",")
)

# ----------------------------------------------------------
# Step 13: Build the Leaflet map
# ----------------------------------------------------------

DivisionMap <- leaflet(mapdata) %>%
  # Choose one basemap:
  addProviderTiles(providers$CartoDB.Positron) %>%
  # addProviderTiles(providers$Esri.WorldStreetMap, group = "Streets (Esri World Street Map)") %>%
  # addProviderTiles(providers$Esri.WorldImagery,   group = "Satellite (Esri World Imagery)") %>%
  addPolygons(
    fillColor   = ~pal(Estimate),
    fillOpacity = 0.5, 
    color       = "black",
    weight      = 1,
    popup       = ~popup
  ) %>%
  addLegend(
    pal    = pal,
    values = ~Estimate,
    title  = "Estimate",
    labFormat = labelFormat(big.mark = ",")
  )

DivisionMap

# ----------------------------------------------------------
# Step 14: Export graph as a standalone HTML file
# ----------------------------------------------------------
# This creates a fully self-contained HTML file for the dot plot.

saveWidget(
  widget = as_widget(mygraph),
  file = "ACSGraph.html",
  selfcontained = TRUE
)

# ----------------------------------------------------------
# Step 15: Export map as a standalone HTML file
# ----------------------------------------------------------
# This creates a fully self-contained HTML you can open or share.
# Adjust the path/filename as you like.

saveWidget(
  widget = DivisionMap,
  file = "ACSMap.html",
  selfcontained = TRUE
)