library(tidyverse)
library(leaflet)
library(sf)
library(readxl)
library(DT)
library(plotly)
library(broom)
library(tidycensus)
census_api_key("869f0f8db207fe77c709b9b24681536a0abc2956")
To install your API key for use in future sessions, run this function with `install = TRUE`.
senate_counties <- read_xlsx("Statewide Results.xlsx", sheet = 1)
New names:
* `` -> ...2
* `` -> ...3
* `` -> ...4
* `` -> ...5
senate_counties <- read_xlsx("Statewide Results.xlsx", sheet = 1, range = "B7:E63")
senate_counties <- senate_counties %>% 
  rename(Republican = "MATT ROSENDALE\r\nRepublican") %>% 
  rename(Democrat = "JON TESTER\r\nDemocrat") %>% 
  rename(Libertarian = "RICK BRECKENRIDGE\r\nLibertarian")
senate_counties <- senate_counties %>% 
  mutate(total_votes = Republican + Democrat + Libertarian) %>% 
  mutate(Repub_advantage = Republican/total_votes - Democrat/total_votes) %>% 
  mutate(Repub_advantage = round(Repub_advantage*100, 1))

senate_counties %>% 
  arrange(-Repub_advantage)

First, let’s find the Republican Advantage.

mt_counties <- get_acs(geography = "county",
                       variables = "B01003_001",
                       state = "MT",
                       geometry = TRUE) 
Getting data from the 2014-2018 5-year ACS
Downloading feature geometry from the Census website.  To cache shapefiles for use in future sessions, set `options(tigris_use_cache = TRUE)`.
Using FIPS code '30' for state 'MT'
senate_counties[25, "County"] <- "Lewis and Clark"              

mt_counties <- mt_counties %>% 
  mutate(County = gsub(" County, Montana", "", NAME)) %>%      
  rename(Population = estimate)                                
senate_election <- mt_counties %>% 
  full_join(senate_counties)
Joining, by = "County"
senate_election %>%
  as_tibble() %>% 
  select(County, Population, Democrat, Republican, Libertarian, total_votes, Repub_advantage) %>% 
  datatable()

And then clean it up.

vote_colors <- colorNumeric(palette = "viridis", domain = senate_election$Repub_advantage)

senate_election %>%
  leaflet() %>% 
  addTiles() %>%
  addPolygons(weight = 1,
              fillColor = ~vote_colors(Repub_advantage), 
              label = ~paste0(County, ", Republican advantage = ", Repub_advantage),
              highlight = highlightOptions(weight = 2)) %>% 
  setView(-110, 47, zoom = 6) %>% 
  addLegend(pal = vote_colors, values = ~Repub_advantage)
sf layer has inconsistent datum (+proj=longlat +datum=NAD83 +no_defs).
Need '+proj=longlat +datum=WGS84'

Here is a choropleth map of the same data; the colors go from purple to yellow, which represent lowest to highest Republican advantage, respectfully.

sen_pop_model <- lm(Repub_advantage ~ Population, data = senate_election)
tidy(sen_pop_model)
glance(sen_pop_model)

Here are some slick statistics showing the hypothesis is confirmed.

pop_model <- lm(Repub_advantage ~ Population, data = senate_election)

senate_election %>%
  plot_ly(x = ~Population, 
          y = ~Repub_advantage,
          hoverinfo = "text", 
          text = ~paste("County:", 
                        County, "<br>", 
                        "Population: ", Population, "<br>", 
                        "Republican advantage: ", Repub_advantage)) %>% 
  add_markers(marker = list(opacity = 0.7), showlegend = F) %>%
  layout(title = "Predicting Republican Vote Advantage from Population, by County",
         xaxis = list(title = "County population"),
         yaxis = list(title = "Republican vote advantage"))     %>% 
  add_lines(y = ~fitted(pop_model)) 

Same information #(higher populations offer less Republican advantage.)

senate_election <- senate_election %>% 
  mutate(Longitude = as_tibble(st_coordinates(st_centroid(senate_election$geometry)))$X) %>% 
  mutate(Latitude = as_tibble(st_coordinates(st_centroid(senate_election$geometry)))$Y)
st_centroid does not give correct centroids for longitude/latitude datast_centroid does not give correct centroids for longitude/latitude data
sen_longitude_lm <- lm(Repub_advantage ~ Longitude, data = senate_election)
tidy(sen_longitude_lm)
glance(sen_longitude_lm)

Here are the statistics based of location rather than population (since the second part of the hypothesis is West vs East Republican advantage).

senate_election %>% 
  plot_ly(x = ~Longitude, 
          y = ~Repub_advantage,
          hoverinfo = "text", 
          text = ~paste("County:", County, "<br>", "Longitude: ", Longitude, "<br>", "Republican advantage: ", Repub_advantage)) %>% 
  add_markers(marker = list(opacity = 0.7), showlegend = F) %>%
  layout(title = "Predicting Republican Vote Advantage from Longitude, by County",
         xaxis = list(title = "County longitude"),
         yaxis = list(title = "Republican vote advantage")) %>% 
  add_lines(y = ~fitted(sen_longitude_lm))

I want to overlay this graph on a map of Montana.

sen_multiple_lm <- lm(Repub_advantage ~ Population + Longitude, data = senate_election)
tidy(sen_multiple_lm)
glance(sen_multiple_lm)

These statistics show that roughly 27% of the vote variance comes from the location and the population.

senate_election %>% 
  plot_ly(x = ~Longitude, y = ~Population, z = ~Repub_advantage, 
          text = ~County, hoverinfo = "text") %>% 
  add_markers(opacity = .7, showlegend = F)

Here’s a 3-D plot that addresses the data we have with multiple regression lines to explore the correlations between location and population. The hypothesis has been proven accurate.

LS0tCnRpdGxlOiAiQVByYXR0IE1UX2VsZWN0aW9uIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkobGVhZmxldCkKbGlicmFyeShzZikKbGlicmFyeShyZWFkeGwpCmxpYnJhcnkoRFQpCmxpYnJhcnkocGxvdGx5KQpsaWJyYXJ5KGJyb29tKQpsaWJyYXJ5KHRpZHljZW5zdXMpCmBgYAoKYGBge3J9CmNlbnN1c19hcGlfa2V5KCIiKQpgYGAKCmBgYHtyfQpzZW5hdGVfY291bnRpZXMgPC0gcmVhZF94bHN4KCJTdGF0ZXdpZGUgUmVzdWx0cy54bHN4Iiwgc2hlZXQgPSAxKQpgYGAKYGBge3J9CnNlbmF0ZV9jb3VudGllcyA8LSByZWFkX3hsc3goIlN0YXRld2lkZSBSZXN1bHRzLnhsc3giLCBzaGVldCA9IDEsIHJhbmdlID0gIkI3OkU2MyIpCmBgYApgYGB7cn0Kc2VuYXRlX2NvdW50aWVzIDwtIHNlbmF0ZV9jb3VudGllcyAlPiUgCiAgcmVuYW1lKFJlcHVibGljYW4gPSAiTUFUVCBST1NFTkRBTEVcclxuUmVwdWJsaWNhbiIpICU+JSAKICByZW5hbWUoRGVtb2NyYXQgPSAiSk9OIFRFU1RFUlxyXG5EZW1vY3JhdCIpICU+JSAKICByZW5hbWUoTGliZXJ0YXJpYW4gPSAiUklDSyBCUkVDS0VOUklER0VcclxuTGliZXJ0YXJpYW4iKQpgYGAKYGBge3J9CnNlbmF0ZV9jb3VudGllcyA8LSBzZW5hdGVfY291bnRpZXMgJT4lIAogIG11dGF0ZSh0b3RhbF92b3RlcyA9IFJlcHVibGljYW4gKyBEZW1vY3JhdCArIExpYmVydGFyaWFuKSAlPiUgCiAgbXV0YXRlKFJlcHViX2FkdmFudGFnZSA9IFJlcHVibGljYW4vdG90YWxfdm90ZXMgLSBEZW1vY3JhdC90b3RhbF92b3RlcykgJT4lIAogIG11dGF0ZShSZXB1Yl9hZHZhbnRhZ2UgPSByb3VuZChSZXB1Yl9hZHZhbnRhZ2UqMTAwLCAxKSkKCnNlbmF0ZV9jb3VudGllcyAlPiUgCiAgYXJyYW5nZSgtUmVwdWJfYWR2YW50YWdlKQpgYGAKRmlyc3QsIGxldCdzIGZpbmQgdGhlIFJlcHVibGljYW4gQWR2YW50YWdlLiAKYGBge3J9Cm10X2NvdW50aWVzIDwtIGdldF9hY3MoZ2VvZ3JhcGh5ID0gImNvdW50eSIsCiAgICAgICAgICAgICAgICAgICAgICAgdmFyaWFibGVzID0gIkIwMTAwM18wMDEiLAogICAgICAgICAgICAgICAgICAgICAgIHN0YXRlID0gIk1UIiwKICAgICAgICAgICAgICAgICAgICAgICBnZW9tZXRyeSA9IFRSVUUpIApgYGAKYGBge3J9CnNlbmF0ZV9jb3VudGllc1syNSwgIkNvdW50eSJdIDwtICJMZXdpcyBhbmQgQ2xhcmsiICAgICAgICAgICAgICAKCm10X2NvdW50aWVzIDwtIG10X2NvdW50aWVzICU+JSAKICBtdXRhdGUoQ291bnR5ID0gZ3N1YigiIENvdW50eSwgTW9udGFuYSIsICIiLCBOQU1FKSkgJT4lICAgICAgCiAgcmVuYW1lKFBvcHVsYXRpb24gPSBlc3RpbWF0ZSkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIApgYGAKCmBgYHtyfQpzZW5hdGVfZWxlY3Rpb24gPC0gbXRfY291bnRpZXMgJT4lIAogIGZ1bGxfam9pbihzZW5hdGVfY291bnRpZXMpCmBgYAoKYGBge3J9CnNlbmF0ZV9lbGVjdGlvbiAlPiUKICBhc190aWJibGUoKSAlPiUgCiAgc2VsZWN0KENvdW50eSwgUG9wdWxhdGlvbiwgRGVtb2NyYXQsIFJlcHVibGljYW4sIExpYmVydGFyaWFuLCB0b3RhbF92b3RlcywgUmVwdWJfYWR2YW50YWdlKSAlPiUgCiAgZGF0YXRhYmxlKCkKYGBgCkFuZCB0aGVuIGNsZWFuIGl0IHVwLiAKYGBge3J9CnZvdGVfY29sb3JzIDwtIGNvbG9yTnVtZXJpYyhwYWxldHRlID0gInZpcmlkaXMiLCBkb21haW4gPSBzZW5hdGVfZWxlY3Rpb24kUmVwdWJfYWR2YW50YWdlKQoKc2VuYXRlX2VsZWN0aW9uICU+JQogIGxlYWZsZXQoKSAlPiUgCiAgYWRkVGlsZXMoKSAlPiUKICBhZGRQb2x5Z29ucyh3ZWlnaHQgPSAxLAogICAgICAgICAgICAgIGZpbGxDb2xvciA9IH52b3RlX2NvbG9ycyhSZXB1Yl9hZHZhbnRhZ2UpLCAKICAgICAgICAgICAgICBsYWJlbCA9IH5wYXN0ZTAoQ291bnR5LCAiLCBSZXB1YmxpY2FuIGFkdmFudGFnZSA9ICIsIFJlcHViX2FkdmFudGFnZSksCiAgICAgICAgICAgICAgaGlnaGxpZ2h0ID0gaGlnaGxpZ2h0T3B0aW9ucyh3ZWlnaHQgPSAyKSkgJT4lIAogIHNldFZpZXcoLTExMCwgNDcsIHpvb20gPSA2KSAlPiUgCiAgYWRkTGVnZW5kKHBhbCA9IHZvdGVfY29sb3JzLCB2YWx1ZXMgPSB+UmVwdWJfYWR2YW50YWdlKQpgYGAKSGVyZSBpcyBhIGNob3JvcGxldGggbWFwIG9mIHRoZSBzYW1lIGRhdGE7IHRoZSBjb2xvcnMgZ28gZnJvbSBwdXJwbGUgdG8geWVsbG93LCB3aGljaCByZXByZXNlbnQgbG93ZXN0IHRvIGhpZ2hlc3QgUmVwdWJsaWNhbiBhZHZhbnRhZ2UsIHJlc3BlY3RmdWxseS4gCmBgYHtyfQpzZW5fcG9wX21vZGVsIDwtIGxtKFJlcHViX2FkdmFudGFnZSB+IFBvcHVsYXRpb24sIGRhdGEgPSBzZW5hdGVfZWxlY3Rpb24pCnRpZHkoc2VuX3BvcF9tb2RlbCkKYGBgCmBgYHtyfQpnbGFuY2Uoc2VuX3BvcF9tb2RlbCkKYGBgCkhlcmUgYXJlIHNvbWUgc2xpY2sgc3RhdGlzdGljcyBzaG93aW5nIHRoZSBoeXBvdGhlc2lzIGlzIGNvbmZpcm1lZC4gCmBgYHtyfQpwb3BfbW9kZWwgPC0gbG0oUmVwdWJfYWR2YW50YWdlIH4gUG9wdWxhdGlvbiwgZGF0YSA9IHNlbmF0ZV9lbGVjdGlvbikKCnNlbmF0ZV9lbGVjdGlvbiAlPiUKICBwbG90X2x5KHggPSB+UG9wdWxhdGlvbiwgCiAgICAgICAgICB5ID0gflJlcHViX2FkdmFudGFnZSwKICAgICAgICAgIGhvdmVyaW5mbyA9ICJ0ZXh0IiwgCiAgICAgICAgICB0ZXh0ID0gfnBhc3RlKCJDb3VudHk6IiwgCiAgICAgICAgICAgICAgICAgICAgICAgIENvdW50eSwgIjxicj4iLCAKICAgICAgICAgICAgICAgICAgICAgICAgIlBvcHVsYXRpb246ICIsIFBvcHVsYXRpb24sICI8YnI+IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICJSZXB1YmxpY2FuIGFkdmFudGFnZTogIiwgUmVwdWJfYWR2YW50YWdlKSkgJT4lIAogIGFkZF9tYXJrZXJzKG1hcmtlciA9IGxpc3Qob3BhY2l0eSA9IDAuNyksIHNob3dsZWdlbmQgPSBGKSAlPiUKICBsYXlvdXQodGl0bGUgPSAiUHJlZGljdGluZyBSZXB1YmxpY2FuIFZvdGUgQWR2YW50YWdlIGZyb20gUG9wdWxhdGlvbiwgYnkgQ291bnR5IiwKICAgICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIkNvdW50eSBwb3B1bGF0aW9uIiksCiAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJSZXB1YmxpY2FuIHZvdGUgYWR2YW50YWdlIikpICAgICAlPiUgCiAgYWRkX2xpbmVzKHkgPSB+Zml0dGVkKHBvcF9tb2RlbCkpIApgYGAKU2FtZSBpbmZvcm1hdGlvbiAjKGhpZ2hlciBwb3B1bGF0aW9ucyBvZmZlciBsZXNzIFJlcHVibGljYW4gYWR2YW50YWdlLikKYGBge3J9CnNlbmF0ZV9lbGVjdGlvbiA8LSBzZW5hdGVfZWxlY3Rpb24gJT4lIAogIG11dGF0ZShMb25naXR1ZGUgPSBhc190aWJibGUoc3RfY29vcmRpbmF0ZXMoc3RfY2VudHJvaWQoc2VuYXRlX2VsZWN0aW9uJGdlb21ldHJ5KSkpJFgpICU+JSAKICBtdXRhdGUoTGF0aXR1ZGUgPSBhc190aWJibGUoc3RfY29vcmRpbmF0ZXMoc3RfY2VudHJvaWQoc2VuYXRlX2VsZWN0aW9uJGdlb21ldHJ5KSkpJFkpCmBgYAoKYGBge3J9CnNlbl9sb25naXR1ZGVfbG0gPC0gbG0oUmVwdWJfYWR2YW50YWdlIH4gTG9uZ2l0dWRlLCBkYXRhID0gc2VuYXRlX2VsZWN0aW9uKQp0aWR5KHNlbl9sb25naXR1ZGVfbG0pCmBgYAoKYGBge3J9CmdsYW5jZShzZW5fbG9uZ2l0dWRlX2xtKQpgYGAKSGVyZSBhcmUgdGhlIHN0YXRpc3RpY3MgYmFzZWQgb2YgbG9jYXRpb24gcmF0aGVyIHRoYW4gcG9wdWxhdGlvbiAoc2luY2UgdGhlIHNlY29uZCBwYXJ0IG9mIHRoZSBoeXBvdGhlc2lzIGlzIFdlc3QgdnMgRWFzdCBSZXB1YmxpY2FuIGFkdmFudGFnZSkuCmBgYHtyfQpzZW5hdGVfZWxlY3Rpb24gJT4lIAogIHBsb3RfbHkoeCA9IH5Mb25naXR1ZGUsIAogICAgICAgICAgeSA9IH5SZXB1Yl9hZHZhbnRhZ2UsCiAgICAgICAgICBob3ZlcmluZm8gPSAidGV4dCIsIAogICAgICAgICAgdGV4dCA9IH5wYXN0ZSgiQ291bnR5OiIsIENvdW50eSwgIjxicj4iLCAiTG9uZ2l0dWRlOiAiLCBMb25naXR1ZGUsICI8YnI+IiwgIlJlcHVibGljYW4gYWR2YW50YWdlOiAiLCBSZXB1Yl9hZHZhbnRhZ2UpKSAlPiUgCiAgYWRkX21hcmtlcnMobWFya2VyID0gbGlzdChvcGFjaXR5ID0gMC43KSwgc2hvd2xlZ2VuZCA9IEYpICU+JQogIGxheW91dCh0aXRsZSA9ICJQcmVkaWN0aW5nIFJlcHVibGljYW4gVm90ZSBBZHZhbnRhZ2UgZnJvbSBMb25naXR1ZGUsIGJ5IENvdW50eSIsCiAgICAgICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICJDb3VudHkgbG9uZ2l0dWRlIiksCiAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJSZXB1YmxpY2FuIHZvdGUgYWR2YW50YWdlIikpICU+JSAKICBhZGRfbGluZXMoeSA9IH5maXR0ZWQoc2VuX2xvbmdpdHVkZV9sbSkpCmBgYApJIHdhbnQgdG8gb3ZlcmxheSB0aGlzIGdyYXBoIG9uIGEgbWFwIG9mIE1vbnRhbmEuIApgYGB7cn0Kc2VuX211bHRpcGxlX2xtIDwtIGxtKFJlcHViX2FkdmFudGFnZSB+IFBvcHVsYXRpb24gKyBMb25naXR1ZGUsIGRhdGEgPSBzZW5hdGVfZWxlY3Rpb24pCnRpZHkoc2VuX211bHRpcGxlX2xtKQpgYGAKYGBge3J9CmdsYW5jZShzZW5fbXVsdGlwbGVfbG0pCmBgYApUaGVzZSBzdGF0aXN0aWNzIHNob3cgdGhhdCByb3VnaGx5IDI3JSBvZiB0aGUgdm90ZSB2YXJpYW5jZSBjb21lcyBmcm9tIHRoZSBsb2NhdGlvbiBhbmQgdGhlIHBvcHVsYXRpb24uIAoKYGBge3J9CnNlbmF0ZV9lbGVjdGlvbiAlPiUgCiAgcGxvdF9seSh4ID0gfkxvbmdpdHVkZSwgeSA9IH5Qb3B1bGF0aW9uLCB6ID0gflJlcHViX2FkdmFudGFnZSwgCiAgICAgICAgICB0ZXh0ID0gfkNvdW50eSwgaG92ZXJpbmZvID0gInRleHQiKSAlPiUgCiAgYWRkX21hcmtlcnMob3BhY2l0eSA9IC43LCBzaG93bGVnZW5kID0gRikKYGBgCkhlcmUncyBhIDMtRCBwbG90IHRoYXQgYWRkcmVzc2VzIHRoZSBkYXRhIHdlIGhhdmUgd2l0aCBtdWx0aXBsZSByZWdyZXNzaW9uIGxpbmVzIHRvIGV4cGxvcmUgdGhlIGNvcnJlbGF0aW9ucyBiZXR3ZWVuIGxvY2F0aW9uIGFuZCBwb3B1bGF0aW9uLiBUaGUgaHlwb3RoZXNpcyBoYXMgYmVlbiBwcm92ZW4gYWNjdXJhdGUuIAoK