Davidson County election analysis

One pattern in the Harris-focused percentage map of Davidson County is that Harris received the highest levels of support in precincts located near the urban center of Nashville, with her percentages dropping off in the more suburban and rural precincts.

In the stacked bar chart of precinct-level vote totals, a noticeable pattern is that the total length of each bar shows how many people voted in that precinct, and the dark blue sections representing Harris are often the largest. This makes it easy to see that Harris won many precincts and also shows which races were close and which were not.

Code:

# Required packages

if (!require("tidyverse"))
  install.packages("tidyverse")
if (!require("mapview"))
  install.packages("mapview")
if (!require("sf"))
  install.packages("sf")
if (!require("leaflet"))
  install.packages("leaflet")
if (!require("leaflet.extras2"))
  install.packages("leaflet.extras2")
if (!require("plotly"))
  install.packages("plotly")

library(tidyverse)
library(mapview)
library(sf)
library(leaflet)
library(leafpop)
library(readxl)
library(plotly)

# Getting the election data

VoteData <- read.csv("https://github.com/drkblake/Data/raw/refs/heads/main/Davidson_Vote_Data.csv")

# Getting the map

download.file("https://github.com/drkblake/Data/raw/refs/heads/main/Davidson_Precincts.zip","DavidsonPrecinctMap.zip")

unzip("DavidsonPrecinctMap.zip")

MapInfo <- read_sf("Davidson_Precincts.shp")

# Enhancing the data

VoteData2 <- VoteData %>% 
  mutate(Total = Trump + Harris + Other,
         Pct_Trump = round((Trump / Total)*100,1),
         Pct_Harris = round((Harris / Total)*100,1),
         Pct_Other = round((Other / Total)*100,1),
         Margin_Trump = Trump - Harris,
         Margin_Harris = Harris - Trump,
         Winner = case_when(Trump > Harris ~ "Trump",
                            Harris > Trump ~ "Harris",
                            Other > (Trump + Harris) ~ "Other",
                            .default = "Tie"))

# Merging the data and the map

DataAndMap <- left_join(VoteData2,MapInfo)

# Converting the merged data and map into an sf object

DataAndMap <- st_as_sf(DataAndMap)

# Harris percentage map

mypalette = colorRampPalette(c('red', 'blue'))


PctHarrisMap <- mapview(
  DataAndMap,
  zcol = "Pct_Harris",
  col.regions = mypalette,
  map.types = ("OpenStreetMap"),
  layer.name = "Pct. Harris",
  popup = popupTable(
    DataAndMap,
    feature.id = FALSE,
    row.numbers = FALSE,
    zcol = c(
      "Precinct",
      "Trump",
      "Harris",
      "Other",
      "Total",
      "Pct_Trump",
      "Pct_Harris",
      "Pct_Other",
      "Margin_Trump",
      "Margin_Harris",
      "Winner"
    )
  )
)

PctHarrisMap

# Sort the data by the Total variable
# and make it stay sorted in the chart

ChartData <- DataAndMap %>% 
  arrange(Total) %>% 
  mutate(Precinct = factor(Precinct, levels = Precinct))

# Create and format the chart

Chart <- plot_ly(data = ChartData, orientation = 'h') %>% 
  add_trace(
    x = ~Trump, 
    y = ~Precinct, 
    name = 'Trump', 
    type = 'bar',
    marker = list(color = 'red') # We have made the red bars
  ) %>% 
  add_trace(
    x = ~Harris, 
    y = ~Precinct, 
    name = 'Harris', 
    type = 'bar',
    marker = list(color = 'darkblue') # We have added the blue bars
  ) %>% 
  add_trace(
    x = ~Other, 
    y = ~Precinct, 
    name = 'Other', 
    type = 'bar',
    marker = list(color = 'gray') #We have added the gray bars
  ) %>% 
  add_trace(
    x = ~Other,
    y = ~Precinct,
    type = 'bar',
    name = '',
    marker = list(color = 'rgba(0,0,0,0)'),
    text = ~Winner,
    textposition = 'outside',
    showlegend = FALSE # We have added the "winner" labels
  ) %>%
  layout(
    barmode = 'stack',
    xaxis = list(title = 'Number of Votes'),
    yaxis = list(title = 'Precinct',
                 tickfont = list(size = 10),
                 automargin = TRUE)) # We have made it a stacked bar chart

# Show the plot

Chart