Create Maps in R

Setup and get New Hampshire and USGEO data

# set file names and FIPS codes for NH and SC

nhdatafile <- "NHD2016.xlsx"
nhdatafilecsv <- "NHD2016.csv"
usshapefile <- "cb_2014_us_county_5m/cb_2014_us_county_5m.shp"
nhfipscode <- "33"
scdatafile <- "SCGOP2016.csv"
scfipscode <- "45"

pacman::p_load(tidyverse, tmap, tmaptools, leaflet, leaflet.extras, sf, dplyr, rio, sp)

Read New Hampshire data

setwd("C:/Users/Owner/Desktop/My Documents/School/DataFiles/GIS")

nhdata <- import(nhdatafilecsv)

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

nhdata$SandersMarginVotes <- nhdata$Sanders - nhdata$Clinton  # add Sanders margins
nhdata$SandersPct <- (nhdata$Sanders) / (nhdata$Sanders + nhdata$Clinton) # add Sanders Pct
nhdata$ClintonPct <- (nhdata$Clinton) / (nhdata$Sanders + nhdata$Clinton) # add Clinton Pct
nhdata$SandersMarginPctgPoints <- nhdata$SandersPct - nhdata$ClintonPct # add Sanders margin Pct

Read USGEO data shapefile

# Read the shape file for US states and counties

pacman::p_load(raster, rgdal)

setwd("C:/Users/Owner/Desktop/My Documents/School/DataFiles/GIS/")

usgeo <- shapefile("cb_2014_us_county_5m/cb_2014_us_county_5m.shp")

Quick plot view of USGEO shapes

qtm(usgeo)        # test plot US geo shapes

#view(usgeo)      # look at the usgeo data

Quickplot view of NH shapes & reconcile county names between files

nhgeo <- usgeo[usgeo$STATEFP==nhfipscode,]  # get New Hampshire shapes

qtm(nhgeo)  # test plot New Hampshire data

str(nhgeo$NAME)     # look at nhgeo county name
##  chr [1:10] "Grafton" "Hillsborough" "Coos" "Belknap" "Rockingham" ...
str(nhdata$County)  # look at nhdata county name
##  chr [1:10] "Belknap" "Carroll" "Cheshire" "Coos" "Grafton" "Hillsborough" ...
identical(nhgeo$NAME,nhdata$County)      # check if they're the same
## [1] FALSE
nhgeo$NAME <- as.character(nhgeo$NAME)   # make the county names plain char

nhgeo <- nhgeo[order(nhgeo$NAME),]       # order nhgeo by county name   
nhdata <- nhdata[order(nhdata$County),]  # order nhdata by county name
identical(nhgeo$NAME,nhdata$County)      # check if they're the same
## [1] TRUE

Create New Hampshire map data

nhmap <- merge(nhgeo, nhdata, by.x = "NAME", by.y = "County")
str(nhmap)                                                    # look at NH map data
## Formal class 'SpatialPolygonsDataFrame' [package "sp"] with 5 slots
##   ..@ data       :'data.frame':  10 obs. of  15 variables:
##   .. ..$ NAME                   : chr [1:10] "Belknap" "Carroll" "Cheshire" "Coos" ...
##   .. ..$ STATEFP                : chr [1:10] "33" "33" "33" "33" ...
##   .. ..$ COUNTYFP               : chr [1:10] "001" "003" "005" "007" ...
##   .. ..$ COUNTYNS               : chr [1:10] "00873174" "00873175" "00873176" "00873177" ...
##   .. ..$ AFFGEOID               : chr [1:10] "0500000US33001" "0500000US33003" "0500000US33005" "0500000US33007" ...
##   .. ..$ GEOID                  : chr [1:10] "33001" "33003" "33005" "33007" ...
##   .. ..$ LSAD                   : chr [1:10] "06" "06" "06" "06" ...
##   .. ..$ ALAND                  : chr [1:10] "1036582289" "2411458935" "1830366195" "4648216798" ...
##   .. ..$ AWATER                 : chr [1:10] "177039345" "158933434" "57990901" "90773891" ...
##   .. ..$ Clinton                : int [1:10] 3495 3230 5132 2013 6918 28147 12250 22829 8813 2497
##   .. ..$ Sanders                : int [1:10] 6005 5638 12441 3639 14245 39245 18107 31065 15881 5915
##   .. ..$ SandersMarginVotes     : int [1:10] 2510 2408 7309 1626 7327 11098 5857 8236 7068 3418
##   .. ..$ SandersPct             : num [1:10] 0.632 0.636 0.708 0.644 0.673 ...
##   .. ..$ ClintonPct             : num [1:10] 0.368 0.364 0.292 0.356 0.327 ...
##   .. ..$ SandersMarginPctgPoints: num [1:10] 0.264 0.272 0.416 0.288 0.346 ...
##   ..@ polygons   :List of 10
##   .. ..$ :Formal class 'Polygons' [package "sp"] with 5 slots
##   .. .. .. ..@ Polygons :List of 1
##   .. .. .. .. ..$ :Formal class 'Polygon' [package "sp"] with 5 slots
##   .. .. .. .. .. .. ..@ labpt  : num [1:2] -71.4 43.5
##   .. .. .. .. .. .. ..@ area   : num 0.136
##   .. .. .. .. .. .. ..@ hole   : logi FALSE
##   .. .. .. .. .. .. ..@ ringDir: int 1
##   .. .. .. .. .. .. ..@ coords : num [1:33, 1:2] -71.7 -71.7 -71.7 -71.7 -71.7 ...
##   .. .. .. ..@ plotOrder: int 1
##   .. .. .. ..@ labpt    : num [1:2] -71.4 43.5
##   .. .. .. ..@ ID       : chr "1100"
##   .. .. .. ..@ area     : num 0.136
##   .. ..$ :Formal class 'Polygons' [package "sp"] with 5 slots
##   .. .. .. ..@ Polygons :List of 1
##   .. .. .. .. ..$ :Formal class 'Polygon' [package "sp"] with 5 slots
##   .. .. .. .. .. .. ..@ labpt  : num [1:2] -71.2 43.9
##   .. .. .. .. .. .. ..@ area   : num 0.288
##   .. .. .. .. .. .. ..@ hole   : logi FALSE
##   .. .. .. .. .. .. ..@ ringDir: int 1
##   .. .. .. .. .. .. ..@ coords : num [1:73, 1:2] -71.6 -71.4 -71.4 -71.3 -71.4 ...
##   .. .. .. ..@ plotOrder: int 1
##   .. .. .. ..@ labpt    : num [1:2] -71.2 43.9
##   .. .. .. ..@ ID       : chr "3077"
##   .. .. .. ..@ area     : num 0.288
##   .. ..$ :Formal class 'Polygons' [package "sp"] with 5 slots
##   .. .. .. ..@ Polygons :List of 1
##   .. .. .. .. ..$ :Formal class 'Polygon' [package "sp"] with 5 slots
##   .. .. .. .. .. .. ..@ labpt  : num [1:2] -72.3 42.9
##   .. .. .. .. .. .. ..@ area   : num 0.208
##   .. .. .. .. .. .. ..@ hole   : logi FALSE
##   .. .. .. .. .. .. ..@ ringDir: int 1
##   .. .. .. .. .. .. ..@ coords : num [1:161, 1:2] -72.6 -72.6 -72.6 -72.6 -72.6 ...
##   .. .. .. ..@ plotOrder: int 1
##   .. .. .. ..@ labpt    : num [1:2] -72.3 42.9
##   .. .. .. ..@ ID       : chr "1877"
##   .. .. .. ..@ area     : num 0.208
##   .. ..$ :Formal class 'Polygons' [package "sp"] with 5 slots
##   .. .. .. ..@ Polygons :List of 1
##   .. .. .. .. ..$ :Formal class 'Polygon' [package "sp"] with 5 slots
##   .. .. .. .. .. .. ..@ labpt  : num [1:2] -71.3 44.7
##   .. .. .. .. .. .. ..@ area   : num 0.539
##   .. .. .. .. .. .. ..@ hole   : logi FALSE
##   .. .. .. .. .. .. ..@ ringDir: int 1
##   .. .. .. .. .. .. ..@ coords : num [1:511, 1:2] -71.8 -71.8 -71.8 -71.7 -71.7 ...
##   .. .. .. ..@ plotOrder: int 1
##   .. .. .. ..@ labpt    : num [1:2] -71.3 44.7
##   .. .. .. ..@ ID       : chr "922"
##   .. .. .. ..@ area     : num 0.539
##   .. ..$ :Formal class 'Polygons' [package "sp"] with 5 slots
##   .. .. .. ..@ Polygons :List of 1
##   .. .. .. .. ..$ :Formal class 'Polygon' [package "sp"] with 5 slots
##   .. .. .. .. .. .. ..@ labpt  : num [1:2] -71.8 43.9
##   .. .. .. .. .. .. ..@ area   : num 0.508
##   .. .. .. .. .. .. ..@ hole   : logi FALSE
##   .. .. .. .. .. .. ..@ ringDir: int 1
##   .. .. .. .. .. .. ..@ coords : num [1:327, 1:2] -72.3 -72.3 -72.3 -72.3 -72.3 ...
##   .. .. .. ..@ plotOrder: int 1
##   .. .. .. ..@ labpt    : num [1:2] -71.8 43.9
##   .. .. .. ..@ ID       : chr "685"
##   .. .. .. ..@ area     : num 0.508
##   .. ..$ :Formal class 'Polygons' [package "sp"] with 5 slots
##   .. .. .. ..@ Polygons :List of 1
##   .. .. .. .. ..$ :Formal class 'Polygon' [package "sp"] with 5 slots
##   .. .. .. .. .. .. ..@ labpt  : num [1:2] -71.7 42.9
##   .. .. .. .. .. .. ..@ area   : num 0.255
##   .. .. .. .. .. .. ..@ hole   : logi FALSE
##   .. .. .. .. .. .. ..@ ringDir: int 1
##   .. .. .. .. .. .. ..@ coords : num [1:45, 1:2] -72.1 -72 -72 -72 -72 ...
##   .. .. .. ..@ plotOrder: int 1
##   .. .. .. ..@ labpt    : num [1:2] -71.7 42.9
##   .. .. .. ..@ ID       : chr "866"
##   .. .. .. ..@ area     : num 0.255
##   .. ..$ :Formal class 'Polygons' [package "sp"] with 5 slots
##   .. .. .. ..@ Polygons :List of 1
##   .. .. .. .. ..$ :Formal class 'Polygon' [package "sp"] with 5 slots
##   .. .. .. .. .. .. ..@ labpt  : num [1:2] -71.7 43.3
##   .. .. .. .. .. .. ..@ area   : num 0.274
##   .. .. .. .. .. .. ..@ hole   : logi FALSE
##   .. .. .. .. .. .. ..@ ringDir: int 1
##   .. .. .. .. .. .. ..@ coords : num [1:49, 1:2] -72.1 -72.1 -72 -72.1 -72.1 ...
##   .. .. .. ..@ plotOrder: int 1
##   .. .. .. ..@ labpt    : num [1:2] -71.7 43.3
##   .. .. .. ..@ ID       : chr "2773"
##   .. .. .. ..@ area     : num 0.274
##   .. ..$ :Formal class 'Polygons' [package "sp"] with 5 slots
##   .. .. .. ..@ Polygons :List of 1
##   .. .. .. .. ..$ :Formal class 'Polygon' [package "sp"] with 5 slots
##   .. .. .. .. .. .. ..@ labpt  : num [1:2] -71.1 43
##   .. .. .. .. .. .. ..@ area   : num 0.208
##   .. .. .. .. .. .. ..@ hole   : logi FALSE
##   .. .. .. .. .. .. ..@ ringDir: int 1
##   .. .. .. .. .. .. ..@ coords : num [1:123, 1:2] -71.5 -71.4 -71.4 -71.4 -71.4 ...
##   .. .. .. ..@ plotOrder: int 1
##   .. .. .. ..@ labpt    : num [1:2] -71.1 43
##   .. .. .. ..@ ID       : chr "1278"
##   .. .. .. ..@ area     : num 0.208
##   .. ..$ :Formal class 'Polygons' [package "sp"] with 5 slots
##   .. .. .. ..@ Polygons :List of 1
##   .. .. .. .. ..$ :Formal class 'Polygon' [package "sp"] with 5 slots
##   .. .. .. .. .. .. ..@ labpt  : num [1:2] -71 43.3
##   .. .. .. .. .. .. ..@ area   : num 0.11
##   .. .. .. .. .. .. ..@ hole   : logi FALSE
##   .. .. .. .. .. .. ..@ ringDir: int 1
##   .. .. .. .. .. .. ..@ coords : num [1:177, 1:2] -71.2 -71.2 -71.2 -71.2 -71.1 ...
##   .. .. .. ..@ plotOrder: int 1
##   .. .. .. ..@ labpt    : num [1:2] -71 43.3
##   .. .. .. ..@ ID       : chr "2676"
##   .. .. .. ..@ area     : num 0.11
##   .. ..$ :Formal class 'Polygons' [package "sp"] with 5 slots
##   .. .. .. ..@ Polygons :List of 1
##   .. .. .. .. ..$ :Formal class 'Polygon' [package "sp"] with 5 slots
##   .. .. .. .. .. .. ..@ labpt  : num [1:2] -72.2 43.4
##   .. .. .. .. .. .. ..@ area   : num 0.159
##   .. .. .. .. .. .. ..@ hole   : logi FALSE
##   .. .. .. .. .. .. ..@ ringDir: int 1
##   .. .. .. .. .. .. ..@ coords : num [1:118, 1:2] -72.5 -72.4 -72.4 -72.4 -72.4 ...
##   .. .. .. ..@ plotOrder: int 1
##   .. .. .. ..@ labpt    : num [1:2] -72.2 43.4
##   .. .. .. ..@ ID       : chr "3167"
##   .. .. .. ..@ area     : num 0.159
##   ..@ plotOrder  : int [1:10] 4 5 2 7 6 3 8 10 1 9
##   ..@ bbox       : num [1:2, 1:2] -72.6 42.7 -70.7 45.3
##   .. ..- attr(*, "dimnames")=List of 2
##   .. .. ..$ : chr [1:2] "x" "y"
##   .. .. ..$ : chr [1:2] "min" "max"
##   ..@ proj4string:Formal class 'CRS' [package "sp"] with 1 slot
##   .. .. ..@ projargs: chr "+proj=longlat +datum=NAD83 +no_defs"

New Hampshire static maps

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

qtm(nhmap, "SandersMarginPctgPoints")

NH Map with some formatting

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.62, 0.62, 0.62, 0.57, 0.53. Increase legend.width (argument of tm_layout) to make the legend wider and therefore the labels larger.

NH Map using Classic style format

nhstaticmap <- tm_shape(nhmap) +
  tm_fill("SandersMarginVotes", title = "Sanders Margin, Total Votes", palette = "PRGn") +
  tm_borders(alpha = .5) +
  tm_text("NAME", size=0.8) +
  tm_style("classic")
nhstaticmap                              # I like it with the PRGn palette
## Some legend labels were too wide. These labels have been resized to 0.62, 0.62, 0.62, 0.57, 0.53. Increase legend.width (argument of tm_layout) to make the legend wider and therefore the labels larger.

Save NH map as a jpg

tmap_save(nhstaticmap, filename="nhdemprimary.jpg")
## Map saved to C:\Users\Owner\Desktop\My Documents\School\RMD source files\nhdemprimary.jpg
## Resolution: 1501.336 by 2937.385 pixels
## Size: 5.004452 by 9.791282 inches (300 dpi)

NH interactive map

clintonPalette <- colorNumeric(palette = "Blues", domain=nhmap$ClintonPct) # create palette

# create popup, round percentages to two decimal places

pacman::p_load(scales, raster)
nhpopup <- paste0(nhmap$NAME, " County: ",  "Sanders ", percent(nhmap$SandersPct, accuracy = 0.01), " - Clinton ", percent(nhmap$ClintonPct, accuracy = 0.01))

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 map

Get South Carolina data and geo shapes

setwd("C:/Users/Owner/Desktop/My Documents/School/DataFiles/GIS")
scdata <- rio::import(scdatafile)

# sc shapefile

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

Create new columns for percentages and winners

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]))
}

Get the SC college education data

setwd("C:/Users/Owner/Desktop/My Documents/School/DataFiles/GIS")
sced <- rio::import("SCdegree.xlsx")

Reconcile the county names in SC data and SC geo data frames

str(scgeo$NAME)
##  chr [1:46] "Edgefield" "Lee" "Horry" "Allendale" "Marion" "Dorchester" ...
str(scdata$County)
##  chr [1:46] "Abbeville" "Aiken" "Allendale" "Anderson" "Bamberg" "Barnwell" ...
# Change scgeo county names to plain char

scgeo$NAME <- as.character(scgeo$NAME)

# Order by county name

scgeo <-  scgeo[order(scgeo$NAME),]
scdata <- scdata[order(scdata$County),]

identical(scgeo$NAME, scdata$County)   # check if identical
## [1] TRUE

Create the South Carolina map data frame, create palettes

# add election results

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

# get min max for 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 palettes

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 = sced$PctCollegeDegree)

Create popup

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%" )

Create the projection of scmap data onto the World Geodetic System

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

Create the SC interactive map

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", "Rubio"))

Add layers to SC interactive map for candidates, winners, and education

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", "Rubio")) %>% 
  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 as shown in the tutorial
              group="College degs") %>%

  addLayersControl(
      baseGroups=c("Winners", "Trump", "Rubio", "Cruz", "College degs"),  
      position = "bottomleft",
      options = layersControlOptions(collapsed = FALSE))

# display the map

scGOPmap

Save the SC map as an HTML file with dependencies in another directory

#htmlwidgets::saveWidget(widget = scGOPmap, file = "scGOPprimary.html", selfcontained = FALSE, libdir = "js")