Set various values needed

nhdatafilecsv <- "NHD2016.csv" 
nhfipscode <- "33" 
scdatafile <- "SCGOP2016.csv" 
scfipscode <- "45" 

Load the tmap, tmaptools, and leaflet packages into the working session

library(tidyverse) 
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.1 ──
## ✔ ggplot2 3.4.0     ✔ purrr   1.0.1
## ✔ tibble  3.1.8     ✔ dplyr   1.1.0
## ✔ tidyr   1.3.0     ✔ stringr 1.5.0
## ✔ readr   2.1.3     ✔ forcats 0.5.2
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
library(tmap) 
library(tmaptools) 
library(leaflet) 
library(sf) 
## Linking to GEOS 3.11.0, GDAL 3.5.3, PROJ 9.1.0; sf_use_s2() is TRUE
library(leaflet.extras) 
library(dplyr) 
library(rio) 
library(sp) 

Step 1: Read in the NH election results file

setwd("/Users/Linh/Desktop/DATA 110/GIS")
nhdata <- import(nhdatafilecsv) 

Eliminate columns for minor candidates and just use County, Clinton and Sanders columns

nhdata <- nhdata[,c("County", "Clinton", "Sanders")] 

Step 2: Decide what data to map

nhdata$SandersMarginVotes <- nhdata$Sanders - nhdata$Clinton 
nhdata$SandersPct <- (nhdata$Sanders) / (nhdata$Sanders + nhdata$Clinton)  
# Will use formatting later to multiply by a hundred 
nhdata$ClintonPct <- (nhdata$Clinton) / (nhdata$Sanders + nhdata$Clinton) 
nhdata$SandersMarginPctgPoints <- nhdata$SandersPct - nhdata$ClintonPct

Step 3: Get geographic data files

setwd("/Users/Linh/Desktop/DATA 110/GIS")
library(raster) 
## 
## Attaching package: 'raster'
## The following object is masked from 'package:dplyr':
## 
##     select
library(rgdal) 
## Please note that rgdal will be retired during 2023,
## plan transition to sf/stars/terra functions using GDAL and PROJ
## at your earliest convenience.
## See https://r-spatial.org/r/2022/04/12/evolution.html and https://github.com/r-spatial/evolution
## rgdal: version: 1.6-5, (SVN revision 1199)
## Geospatial Data Abstraction Library extensions to R successfully loaded
## Loaded GDAL runtime: GDAL 3.5.3, released 2022/10/21
## Path to GDAL shared files: /Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/library/rgdal/gdal
##  GDAL does not use iconv for recoding strings.
## GDAL binary built with GEOS: TRUE 
## Loaded PROJ runtime: Rel. 9.1.0, September 1st, 2022, [PJ_VERSION: 910]
## Path to PROJ shared files: /Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/library/rgdal/proj
## PROJ CDN enabled: FALSE
## Linking to sp version:1.6-0
## To mute warnings of possible GDAL/OSR exportToProj4() degradation,
## use options("rgdal_show_exportToProj4_warnings"="none") before loading sp or rgdal.
usgeo <- shapefile("cb_2014_us_county_5m/cb_2014_us_county_5m.shp") 
## Warning: [vect] Z coordinates ignored

Do a quick plot (qtm stands for quick thematic map) of the shapefile and check its structure:

qtm(usgeo) 

Subset just the NH data from the US shapefile

nhgeo <- usgeo[usgeo$STATEFP==nhfipscode,] 

tmap test plot of the New Hampshire data

qtm(nhgeo)

structure of the object

str(nhgeo$NAME) 
##  chr [1:10] "Grafton" "Hillsborough" "Coos" "Belknap" "Rockingham" ...
str(nhdata$County)
##  chr [1:10] "Belknap" "Carroll" "Cheshire" "Coos" "Grafton" "Hillsborough" ...
# They're not. Change the county names to plain characters in nhgeo: 
nhgeo$NAME <- as.character(nhgeo$NAME) 

Order each data set by county name

nhgeo <- nhgeo[order(nhgeo$NAME),] 
nhdata <- nhdata[order(nhdata$County),] 
# Are the two county columns identical now? They should be: 
identical(nhgeo$NAME,nhdata$County) 
## [1] TRUE

Step 4: Merge geo data with results data using the merge function

library(sf)  # sf stands for simple features#
nhmap <- merge(nhgeo, nhdata, by.x = "NAME", by.y = "County") 
# See the new data structure with 
#str(nhmap) 

Step 5: Create a static map with tmap’s qtm() function:

qtm(nhmap, "SandersMarginVotes")
## Some legend labels were too wide. These labels have been resized to 0.63, 0.63, 0.63, 0.58, 0.54. Increase legend.width (argument of tm_layout) to make the legend wider and therefore the labels larger.

qtm(nhmap, "SandersMarginPctgPoints") 

For more control over look and feel, use the tm_shape() function:

tm_shape(nhmap) + 
  tm_fill("SandersMarginVotes", title="Sanders Margin, Total Votes", palette = "PRGn") + 
  tm_borders(alpha=.5) + 
  tm_text("NAME", size=0.8)
## Some legend labels were too wide. These labels have been resized to 0.63, 0.63, 0.63, 0.58, 0.54. Increase legend.width (argument of tm_layout) to make the legend wider and therefore the labels larger.

Same code as above, but store the static map in a variable, and change the theme to “classic” style:

nhstaticmap <- tm_shape(nhmap) + 
  tm_fill("SandersMarginVotes", title="Sanders Margin, Total Votes", palette = "viridis") + 
  #I like viridis 
  tm_borders(alpha=.5) + 
  tm_text("NAME", size=0.8) +  
  tm_style("classic")

View the map

nhstaticmap 
## Some legend labels were too wide. These labels have been resized to 0.63, 0.63, 0.63, 0.58, 0.54. Increase legend.width (argument of tm_layout) to make the legend wider and therefore the labels larger.

### save the map to a jpg file with tmap’s tmap_save():

tmap_save(nhstaticmap, filename="nhdemprimary.jpg")  
## Map saved to /Users/Linh/Desktop/DATA 110/GIS/nhdemprimary.jpg
## Resolution: 1501.336 by 2937.385 pixels
## Size: 5.004452 by 9.791282 inches (300 dpi)

Step 6: Create palette and pop-ups for interactive map

clintonPalette <- colorNumeric(palette = "Blues", domain=nhmap$ClintonPct) 
library(scales) 
## 
## Attaching package: 'scales'
## The following object is masked from 'package:purrr':
## 
##     discard
## The following object is masked from 'package:readr':
## 
##     col_factor
nhpopup <- paste0("County: ", nhmap$NAME, 
                  "Sanders ", percent(nhmap$SandersPct), " - Clinton ", percent(nhmap$ClintonPct)) 

Step 7: Now generate the interactive map:

nhmap_projected <- sp::spTransform(nhmap, "+proj=longlat +datum=WGS84") 
leaflet(nhmap_projected) %>%   
  addProviderTiles("CartoDB.Positron") %>%   
  addPolygons(stroke=FALSE,                
              smoothFactor = 0.2,                
              fillOpacity = .8,                
              popup=nhpopup,                
              color= ~clintonPalette(nhmap$ClintonPct) 
)

South Carolina data

setwd("/Users/Linh/Desktop/DATA 110/GIS")
scdata <- rio::import(scdatafile) 

South Carolina shapefile and Quick plot of scgeo SC geospatial object:

scgeo <- usgeo[usgeo@data$STATEFP=="45",] 
qtm(scgeo)

Add a column with percent of votes for each candidate. Candidates are in columns 2-7:

candidates <- colnames(scdata[2:7]) 
for(i in 2:7){ 
  j = i + 7 
  temp <- scdata[[i]] / scdata$Total 
  scdata[[j]] <- temp 
  colnames(scdata)[j] <- paste0(colnames(scdata)[i], "Pct") 
  }   
winner <- colnames(scdata[2:7]) 

Get winner in each precinct

for(i in 1:nrow(scdata)){   
  scdata$winner[i] <- names(which.max(scdata[i,2:7])) 
  } 

Import spreadsheet with percent of adult population holding at least a 4-yr college degree

setwd("/Users/Linh/Desktop/DATA 110/GIS")
sced <- rio::import("SCdegree.xlsx")

Check if county names are in the same format in both files

str(scgeo$NAME) 
##  chr [1:46] "Edgefield" "Lee" "Horry" "Allendale" "Marion" "Dorchester" ...
##  chr [1:46] "Edgefield" "Lee" "Horry" "Allendale" "Marion" "Dorchester" ... 
str(scdata$County) 
##  chr [1:46] "Abbeville" "Aiken" "Allendale" "Anderson" "Bamberg" "Barnwell" ...
##  chr [1:46] "Abbeville" "Aiken" "Allendale" "Anderson" "Bamberg" "Barnwell" ... 
# Change the county names to plain characters in scgeo: 
scgeo$NAME <- as.character(scgeo$NAME)
# Order each data set by county name 
scgeo <- scgeo[order(scgeo$NAME),] 
scdata <- scdata[order(scdata$County),]  
# Are the two county columns identical now? They should be: 
identical(scgeo$NAME,scdata$County ) 
## [1] TRUE
## [1] TRUE 

Add the election results and rename county column

scmap <- merge(scgeo, scdata, by.x = "NAME", by.y = "County")

Instead of just coloring the winner, let’s color by strength of win with multiple layers

# Use same intensity for all - get minimum and maximum for the top 3 combined 
minpct <- min(c(scdata$`Donald J TrumpPct`, scdata$`Marco RubioPct`, scdata$`Ted CruzPct` )) 
maxpct <- max(c(scdata$`Donald J TrumpPct`, scdata$`Marco RubioPct`, scdata$`Ted CruzPct` ))

Create leaflet palettes for each layer of the map:

trumpPalette <- colorNumeric(palette = "Purples", domain=c(minpct, maxpct)) 
rubioPalette <- colorNumeric(palette = "Reds", domain = c(minpct, maxpct)) 
cruzPalette <- colorNumeric(palette = "Oranges", domain = c(minpct, maxpct))  
winnerPalette <- colorFactor(palette=c("#984ea3", "#e41a1c"), domain = scmap$winner) 
edPalette <- colorNumeric(palette = "Blues", domain=scmap$PctCollegeDegree)

Create a pop-up:

scpopup <- paste0("<b>County: ", scmap$NAME, "<br />Winner: ", scmap$winner, "</b><br />< br />Trump: ", percent(scmap$`Donald J TrumpPct`), "<br />Rubio: ", percent(scmap$`Marco RubioPct`), "<br />Cruz: ", percent(scmap$`Ted CruzPct`), "<br /><br />Pct w college ed: ", sced$PctCollegeDegree, "% vs state-wide avg of 25%") 

Add the projection we know from the NH map we’ll need for this data on a Leaflet map:

scmap <- sp::spTransform(scmap, "+proj=longlat +datum=WGS84") 

Basic interactive map showing winner in each county:

leaflet(scmap) %>%   
  addProviderTiles("CartoDB.Positron") %>%   
  addPolygons(stroke=TRUE,                                                               
              weight=1,               
              smoothFactor = 0.2,               
              fillOpacity = .75,               
              popup=scpopup,                
              color= ~winnerPalette(scmap$winner),               
              group="Winners") %>%     
  addLegend(position="bottomleft", colors=c("#984ea3", "#e41a1c"), labels=c("Trump", "R ubio")) 

Put top 3 candidates in their own layers and add education layer, store in scGOPmap variable

scGOPmap <- leaflet(scmap) %>%   
  addProviderTiles("CartoDB.Positron") %>%   
  addPolygons(stroke=TRUE,               
              weight=1,               
              smoothFactor = 0.2,               
              fillOpacity = .75,               
              popup=scpopup,                
              color= ~winnerPalette(scmap$winner),               
              group="Winners") %>%      
  addLegend(position="bottomleft", colors=c("#984ea3", "#e41a1c"), labels=c("Trump", "R ubio"))  %>%    
  addPolygons(stroke=TRUE,      
              weight=1,      
              smoothFactor = 0.2,       
              fillOpacity = .75,       
              popup=scpopup,       
              color= ~trumpPalette(scmap$`Donald J TrumpPct`),      
              group="Trump") %>%    
  addPolygons(stroke=TRUE,               
              weight=1,               
              smoothFactor = 0.2,                
              fillOpacity = .75,                
              popup=scpopup,              
              color= ~rubioPalette(scmap$`Marco RubioPct`),               
              group="Rubio") %>%    
  addPolygons(stroke=TRUE,               
                                                
              weight=1,               
              smoothFactor = 0.2,                
              fillOpacity = .75,                
              popup=scpopup,                
              color= ~cruzPalette(scmap$`Ted CruzPct`),               
              group="Cruz") %>%    
  addPolygons(stroke=TRUE,               
              weight=1,               
              smoothFactor = 0.2,                
              fillOpacity = .75,                
              popup=scpopup,                
              color= ~edPalette(sced$PctCollegeDegree), 
              #this data is in the sced table, not scmaps               
              group="College degs") %>%    
  addLayersControl(       
    baseGroups=c("Winners", "Trump", "Rubio", "Cruz", "College degs"),       
    position = "bottomleft",       
    options = layersControlOptions(collapsed = FALSE))  
# Now display the map scGOPmap 

save as a self-contained HTML file

#htmlwidgets::saveWidget(scGOPmap2, file="scGOPwidget2.html")  
# save as an HTML file with dependencies in another directory: 
#htmlwidgets::saveWidget(widget=scGOPmap2, file="scGOPprimary_withdependencies.html", sel fcontained=FALSE, libdir = "js")