This tutorial is part of Computerworld’s How to Make a Map with R

In 10 (fairly) Easy Steps https://www.computerworld.com/article/3038270/data-analytics/create-maps-in-r-in-10-fairly-easy-steps.html by Sharon Machlis

# Set various values needed, including names of files and FIPS codes for New Hampshire and South Carolina
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"

Run any of the install.packages() commands below for packages that are not yet on your system

install.packages(“shiny”) install.packages(“urltools”) install.packages(“tmap”) install.packages(“tmaptools”) install.packages(“leaflet”) install.packages(“scales”) install.packages(“leaflet.extras”) install.packages(“rio”) install.packages(“htmlwidgets”) install.packages(“sf”) install.packages(“dplyr”)

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

library(tidyverse)
## -- Attaching packages --------------------------------------- tidyverse 1.3.0 --
## v ggplot2 3.3.3     v purrr   0.3.4
## v tibble  3.1.0     v dplyr   1.0.5
## v tidyr   1.1.3     v stringr 1.4.0
## v readr   1.4.0     v forcats 0.5.1
## -- Conflicts ------------------------------------------ tidyverse_conflicts() --
## x dplyr::filter() masks stats::filter()
## x dplyr::lag()    masks stats::lag()
library(tmap)
library(tmaptools)
library(leaflet)
library(sf)
## Linking to GEOS 3.9.0, GDAL 3.2.1, PROJ 7.2.1
library(leaflet.extras)
library(dplyr)
library(rio)
library(sp)

Step 1: Read in the NH election results file:

setwd("C:/Users/MCuser/Dropbox/Rachel/MontColl/Datasets/GIS")
#nhdata <- import(nhdatafile)
nhdata <- import(nhdatafilecsv)

If you have any problems with this, there is also a CSV version of the file – sometimes reading Excel between Mac and Windows can be tricky. Try

nhdata <- rio::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

Add columns for percents and margins:

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

Read in the shapefile for US states and counties:

  • If libraries with raster and rgdal don’t work (see next chunk), try library(sf) with the command st_read

  • All these options are here and should help you get the qtm command in the next chunk

#install.packages("raster")
#install.packages("rgdal")
setwd("C:/Users/MCuser/Dropbox/Rachel/MontColl/Datasets/GIS")
library(raster)
## 
## Attaching package: 'raster'
## The following object is masked from 'package:dplyr':
## 
##     select
## The following object is masked from 'package:tidyr':
## 
##     extract
library(rgdal)
## rgdal: version: 1.5-23, (SVN revision 1121)
## Geospatial Data Abstraction Library extensions to R successfully loaded
## Loaded GDAL runtime: GDAL 3.2.1, released 2020/12/29
## Path to GDAL shared files: C:/Users/MCuser/Documents/R/win-library/4.0/rgdal/gdal
## GDAL binary built with GEOS: TRUE 
## Loaded PROJ runtime: Rel. 7.2.1, January 1st, 2021, [PJ_VERSION: 721]
## Path to PROJ shared files: C:/Users/MCuser/Documents/R/win-library/4.0/rgdal/proj
## PROJ CDN enabled: FALSE
## Linking to sp version:1.4-5
## To mute warnings of possible GDAL/OSR exportToProj4() degradation,
## use options("rgdal_show_exportToProj4_warnings"="none") before loading rgdal.
## Overwritten PROJ_LIB was C:/Users/MCuser/Documents/R/win-library/4.0/rgdal/proj
usgeo <- shapefile("cb_2014_us_county_5m/cb_2014_us_county_5m.shp")
## Warning in rgdal::readOGR(dirname(x), fn, stringsAsFactors = stringsAsFactors, :
## Z-dimension discarded

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

qtm(usgeo)

# (pause to wait for map to render, may take a few seconds)
view(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)
## Formal class 'SpatialPolygonsDataFrame' [package "sp"] with 5 slots
##   ..@ data       :'data.frame':  10 obs. of  9 variables:
##   .. ..$ STATEFP : chr [1:10] "33" "33" "33" "33" ...
##   .. ..$ COUNTYFP: chr [1:10] "009" "011" "007" "001" ...
##   .. ..$ COUNTYNS: chr [1:10] "00873178" "00873179" "00873177" "00873174" ...
##   .. ..$ AFFGEOID: chr [1:10] "0500000US33009" "0500000US33011" "0500000US33007" "0500000US33001" ...
##   .. ..$ GEOID   : chr [1:10] "33009" "33011" "33007" "33001" ...
##   .. ..$ NAME    : chr [1:10] "Grafton" "Hillsborough" "Coos" "Belknap" ...
##   .. ..$ LSAD    : chr [1:10] "06" "06" "06" "06" ...
##   .. ..$ ALAND   : chr [1:10] "4425927252" "2269220216" "4648216798" "1036582289" ...
##   .. ..$ AWATER  : chr [1:10] "105375486" "41604851" "90773891" "177039345" ...
##   ..@ 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.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.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.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.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] -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 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] -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.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.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] 3 1 9 8 2 6 5 10 4 7
##   ..@ 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"
# Check if county names are in the same format in both files
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),]
if (identical(nhgeo$NAME,nhdata$County)) {
nhmap <- merge(nhgeo, nhdata, by.x = "NAME", by.y = "County")  # Merge geo and vote datasets
} else {stop}

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

nhmap <- merge(nhgeo, nhdata, by.x = "NAME", by.y = "County")
# See the new data structure with
str(nhmap)
## 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"

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

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)
## Warning in sp::proj4string(obj): CRS object has comment, which is lost in output
## 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.

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
## Warning in sp::proj4string(obj): CRS object has comment, which is lost in output
## 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 the map to a jpg file with tmap’s tmap_save():

tmap_save(nhstaticmap, filename="nhdemprimary.jpg") 
## Warning in sp::proj4string(obj): CRS object has comment, which is lost in output

## Warning in sp::proj4string(obj): CRS object has comment, which is lost in output
## Map saved to C:\Users\MCuser\Dropbox\Rachel\MontColl\DATA110\Notes\nhdemprimary.jpg
## Resolution: 1501.336 by 2937.385 pixels
## Size: 5.004452 by 9.791282 inches (300 dpi)

Part 6

Next up: Code for a basic interactive map, this time for Clinton percentages in NH

Create a palette

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

and a pop-up window

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))  # popup content

Step 7: Now generate the interactive map:

# add the appropriate projection, WGS84
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("C:/Users/MCuser/Dropbox/Rachel/MontColl/Datasets/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("C:/Users/MCuser/Dropbox/Rachel/MontColl/Datasets/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" ...
str(scdata$County)
##  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),]
# check name and county columns are identical
if (identical(scgeo$NAME,scdata$County )) {
scmap <- merge(scgeo, scdata, by.x = "NAME", by.y = "County")
} else {stop}

# 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),]
str(scgeo$NAME)
##  chr [1:46] "Abbeville" "Aiken" "Allendale" "Anderson" "Bamberg" "Barnwell" ...
str(scdata$County)
##  chr [1:46] "Abbeville" "Aiken" "Allendale" "Anderson" "Bamberg" "Barnwell" ...

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

Put top 3 candidates in their own layers and add education layer, store in scGOPmap2 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", "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
              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", selfcontained=FALSE, libdir = "js")