State Level Analysis


This section explores the relationship between voting behavior and demographics at the state level. We begin with a quick look at state-level election outcomes since WWII.

Section 2 takes a closer look at the demographic correlates of voting (Trump vs. Clinton) using a large number of state attributes (e.g. politics, religion, demographics, crime, & ‘psychographics’).

Section 3 provides simple multivariate analysis (PCA/Clustering). These are primarily class notes for introductory EDA (exporatory data analysis) for Data Driven Decision Making (D3M) class I teach at NYU-Stern.

Note: Analysis presented here is focused on visual interpretation of data patterns. All data and replication codes in R are provided. You can see R codes by clicking on the icons on the right side of the graphs.

1. Election History

Here we visualize the election outcomes at the state level since the end of WWII. Three different approaches are presented: small multiples, motion charts, and heatmaps. Visualizations in this section use R wrapper to Highchart library by Joshua Kunst

Note: Michigan, Arizona, and NH for 2016 are not declared as of this writing but are assigned Red-Blue based on projections.


Electoral Maps

Hover Maps for Details


ele2016 <- ed %>% filter(year == 2016)

ele2016$per_dem <- as.numeric(round(100*ele2016$per_dem))
ele2016$per_rep <- as.numeric(round(100*ele2016$per_rep))
ele2016$per_rep2 <- as.numeric(100*ele2016$per_rep2)

    #leave only necessary variables from state df
  dt.st <- ele2016 %>% 
    transmute(value = per_rep2, code = `FIPS Code`, per_clinton = per_dem, per_trump = per_rep,
              stlabel = State)
  ds.st <- list_parse(dt.st)
  
 highchart(type = 'map') %>%
    hc_add_series(
      mapData = usgeojson, data = ds.st, joinBy = c("statefips", "code"),
      borderWidth = 0.4, dataLabels = list(enabled = FALSE, format = '{point.properties.postalcode}'),
      tooltip = list( 
        useHTML = TRUE,
        headerFormat = "<p>",
        pointFormat = paste0("<b>{point.stlabel}</b><br>",
                             "<b style=\"color:#1874CD\">% Clinton:</b> {point.per_clinton:.0f}<br>",
                             "<b style=\"color:red\">% Trump:</b> {point.per_trump:.0f}<br>"
        )
      )) %>%
    hc_title(text = "2016 Presidential Election") %>%
    hc_colorAxis(dataClasses = color_classes(c(seq(0, 92, by = 46), 120), colors = c(c("#1874CD") ,"red", "#CD3700"))) %>%
    hc_legend(enabled = FALSE) %>%
    hc_add_theme(hc_theme_flatdark())



elen2016 <- ed %>% filter(year != 2016)

elen2016$per_dem <- as.numeric(round(100*elen2016$per_dem))
elen2016$per_rep <- as.numeric(round(100*elen2016$per_rep))
elen2016$per_rep2 <- as.numeric(round(100*elen2016$per_rep2))
  
fig <- (lapply(split(elen2016, elen2016$year), function(elen2016) {
  
  
    #leave only necessary variables from state df
  dt.st <- elen2016 %>% 
    transmute(value = per_rep2, code = `FIPS Code`, per_dem = per_dem, per_rep = per_rep, stlabel = State)
  ds.st <- list_parse(dt.st)
  
 highchart(type = 'map') %>%
    hc_add_series(
      mapData = usgeojson, data = ds.st, joinBy = c("statefips", "code"),
      borderWidth = 0.4, dataLabels = list(enabled = FALSE, format = '{point.properties.postalcode}'),
      tooltip = list( 
        useHTML = TRUE,
        headerFormat = "<p>",
        pointFormat = paste0("<b>{point.stlabel}</b><br>",
                             "<b style=\"color:#1874CD\">% Democrat:</b> {point.per_dem:.0f}<br>",
                             "<b style=\"color:red\">% Republican:</b> {point.per_rep:.0f}<br>"
        )
      )) %>%
    hc_title(text = unique(elen2016$title)) %>%
    hc_colorAxis(dataClasses = color_classes(c(seq(0, 100, by = 50), 120), colors = c(c("#1874CD"),"red",
                                                                                      "#EECA00"))) %>%
    hc_legend(enabled = FALSE) %>%
    hc_add_theme(hc_theme_flatdark())
}))

hw_grid(fig, rowheight = 300, ncol = 2)  %>% browsable()