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)
## Warning: package 'tidyverse' was built under R version 4.0.5
## -- Attaching packages --------------------------------------- tidyverse 1.3.0 --
## v ggplot2 3.3.3     v purrr   0.3.4
## v tibble  3.0.6     v dplyr   1.0.3
## v tidyr   1.1.2     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)
## Warning: package 'tmap' was built under R version 4.0.5
library(tmaptools)
## Warning: package 'tmaptools' was built under R version 4.0.5
library(leaflet)
## Warning: package 'leaflet' was built under R version 4.0.5
library(sf)
## Warning: package 'sf' was built under R version 4.0.5
## Linking to GEOS 3.9.0, GDAL 3.2.1, PROJ 7.2.1
library(leaflet.extras)
## Warning: package 'leaflet.extras' was built under R version 4.0.5
library(dplyr)
library(rio)
## Warning: package 'rio' was built under R version 4.0.5
library(sp)
## Warning: package 'sp' was built under R version 4.0.5

Step 1: Read in the NH election results file:

getwd()
## [1] "C:/Users/small/Desktop/MCollege/2021/DATA110/week10"
setwd("C:/Users/small/Desktop/MCollege/2021/DATA110/week10/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")]
nhdata
##          County Clinton Sanders
## 1       Belknap    3495    6005
## 2       Carroll    3230    5638
## 3      Cheshire    5132   12441
## 4          Coos    2013    3639
## 5       Grafton    6918   14245
## 6  Hillsborough   28147   39245
## 7     Merrimack   12250   18107
## 8    Rockingham   22829   31065
## 9     Strafford    8813   15881
## 10     Sullivan    2497    5915

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
nhdata
##          County Clinton Sanders SandersMarginVotes SandersPct ClintonPct
## 1       Belknap    3495    6005               2510  0.6321053  0.3678947
## 2       Carroll    3230    5638               2408  0.6357691  0.3642309
## 3      Cheshire    5132   12441               7309  0.7079611  0.2920389
## 4          Coos    2013    3639               1626  0.6438429  0.3561571
## 5       Grafton    6918   14245               7327  0.6731087  0.3268913
## 6  Hillsborough   28147   39245              11098  0.5823392  0.4176608
## 7     Merrimack   12250   18107               5857  0.5964687  0.4035313
## 8    Rockingham   22829   31065               8236  0.5764092  0.4235908
## 9     Strafford    8813   15881               7068  0.6431117  0.3568883
## 10     Sullivan    2497    5915               3418  0.7031621  0.2968379
##    SandersMarginPctgPoints
## 1                0.2642105
## 2                0.2715381
## 3                0.4159222
## 4                0.2876858
## 5                0.3462175
## 6                0.1646783
## 7                0.1929374
## 8                0.1528185
## 9                0.2862234
## 10               0.4063243

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/small/Desktop/MCollege/2021/DATA110/week10/GIS")
library(raster)
## Warning: package 'raster' was built under R version 4.0.5
## 
## Attaching package: 'raster'
## The following object is masked from 'package:dplyr':
## 
##     select
## The following object is masked from 'package:tidyr':
## 
##     extract
library(rgdal)
## Warning: package 'rgdal' was built under R version 4.0.5
## 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/small/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/small/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/small/Documents/R/win-library/4.0/rgdal/proj
library(sf)
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
#usgeo <- st_read("cb_2014_us_county_5m/cb_2014_us_county_5m.shp")

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)
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),]
# 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)
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                : num [1:10] 3495 3230 5132 2013 6918 ...
##   .. ..$ Sanders                : num [1:10] 6005 5638 12441 3639 14245 ...
##   .. ..$ SandersMarginVotes     : num [1:10] 2510 2408 7309 1626 7327 ...
##   .. ..$ 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\small\Desktop\MCollege\2021\DATA110\week10\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

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)

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
library(raster)
nhpopup <- paste0("County: ", nhmap$County,
"Sanders ", percent(nhmap$SandersPct), " - Clinton ", percent(nhmap$ClintonPct))

Step 7: Now generate the interactive map:

# re-project
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/small/Desktop/MCollege/2021/DATA110/week10/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/small/Desktop/MCollege/2021/DATA110/week10/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),]

# Are the two county columns identical now? They should be:
identical(scgeo$NAME,scdata$County )
## [1] TRUE

Add the election results and rename county column

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

Step 8: Add palettes for a multi-layer map

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$County, "<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"))

Step 9: Add map layers and controls

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

Step 10: Save your interactive map

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