--- title: Maps and spatial data author: Abhijit Dasgupta, PhD --- ```{r setup, include=F, child = here::here('slides/templates/setup.Rmd')} ``` ```{r setup1, include=F} theme_439 <- theme_classic()+theme(axis.text = element_text(size=14), axis.title = element_text(size=16), legend.text = element_text(size=14), legend.title = element_text(size=16), plot.title = element_text(size=18), plot.subtitle = element_text(size=16), plot.caption = element_text(size=12)) theme_set(theme_439) ``` layout: true
BIOF 339: Practical R
--- class: middle, inverse, center # Maps --- #### Toolsets Visualizing spatial and geographic data is a specialized area on its own R has increasing capabilities in this regard, and its increasingly mature. Some of the packages that we might need are .pull-left[ #### Data + `sf` + `sp` + `raster` + `spData` + `rnaturalearthdata` ] .pull-right[ #### Visualization + `ggplot` + `ggmap` + `geom_sf` + `tmap` + `leaflet` ] > Several parts of this lecture are inspired by [Chapter 8](https://geocompr.robinlovelace.net/adv-map.html) of Geocomputation with R by Lovelace, Nowosad and Muenchow (2019), also available on [Amazon](https://www.amazon.com/Geocomputation-Chapman-Hall-Robin-Lovelace/dp/1138304514/) --- #### Toolset We'll start of loading the following packages ```{r} library(ggplot2) library(sf) library(spData) ``` The **sf** package provides [simple features access](https://en.wikipedia.org/wiki/Simple_Features) for R, and helps to store and process geographic data within the tidyverse framework, while linking to several geospatial packages that are standard in the geography world. .pull-left[ ```{r, echo=FALSE, out.height="70%", out.width="70%",fig.pos='h'} knitr::include_graphics('img/sfcartoon.jpg') ```
Illustration by Allison Horst
] .pull-right[To use **sf** you may need to install some additional software. At the very least you will need to install the R packages **rgdal** and **rgeos**. Additional information is available [here](htps://r-spacial.github.io/sf/) ] --- ## Chloropleth maps Chloropleth maps are maps with some geometries filled in to signify levels of some variable. .pull-left[ ```{r, echo=FALSE, fig.caption='Smoking rates in USA in 2012 (NY Times, March 24, 2014)'} knitr::include_graphics('img/Smoking-rates.png') ``` .small[Smoking rates in USA in 2012 (NY Times, March 24, 2014)] ] .pull-right[ ```{r, echo=FALSE, out.height="120%", out.width="120%"} knitr::include_graphics('img/Figure-1-1.png') ``` .small[Observed to Expected Ratios (OERs) for Rates of Primary Total Knee Arthroplasty Among White Medicare Beneficiaries by Health Referral Region [(Ward & Dasgupta, 2020)](https://jamanetwork.com/journals/jamanetworkopen/fullarticle/2765054)]] --- ### A chloropleth of life expectancy We'll start off with a world map .left-column70[ ```{r e1, eval = T, echo = T} library(sf); library(spData) ggplot(data = world) + geom_sf() # a special geometry for plotting maps ``` ] .right-column70[ There are several ways of getting map geometries, which are specifications of polygons. If you look at `world`, you'll see it's a data.frame, with one column named `geometry`. This column provides the shapes of the polygons, and what `geom_sf` looks for ] --- ### A chloropleth of life expectancy If you look at `world`, it also provides life expectancy estimates from 2014 (World Bank). The data set is tidy, with one row corresponding to one country. We'll use our known **ggplot2** way of filling things in. .left-column70[ ```{r} ggplot(data = spData::world) + geom_sf(aes(fill = lifeExp)) # a special geometry for plotting maps ``` ] .right-column70[ We need a more distinctive color palette. ] --- ### A chloropleth of life expectancy If you look at `world`, it also provides life expectancy estimates from 2014 (World Bank). The data set is tidy, with one row corresponding to one country. We'll use our known **ggplot2** way of filling things in. ```{r, out.width='60%', out.height='60%'} ggplot(data = spData::world) + geom_sf(aes(fill = lifeExp)) + # a special geometry for plotting maps viridis::scale_fill_viridis('Life Exp', option='plasma', trans='sqrt', labels = scales::label_number_si()) ``` --- ## The electoral picture in Florida, 2000 ```{r, echo=FALSE} library(spData) library(maps) states <- st_as_sf(maps::map('state', plot = F, fill = T)) %>% cbind(st_coordinates(st_centroid(.))) %>% mutate(ID = str_to_title(ID)) counties <- st_as_sf(maps::map('county', plot = F, fill = T)) counties <- counties %>% dplyr::filter(str_detect(ID, 'florida')) counties <- counties %>% separate(ID, c('State','County'), sep = ',') %>% mutate_at(vars(State:County), str_to_title) florida_election <- readRDS(here::here('slides','lectures','data', 'florida_election.rds')) election_by_county <- counties %>% left_join(florida_election) plt_map <- ggplot()+ geom_sf(data = us_states, fill = NA) + geom_sf(data = election_by_county, aes(fill=Gore_perc)) + geom_label(data = states %>% #<< dplyr::filter(ID != 'Florida'), #<< aes(X, Y, label = ID), #<< size = 5) + coord_sf(xlim = c(-88, -78), ylim = c(24.5, 33), expand = F) + labs(x = '', y = '', fill = 'Percentage for Gore') + scale_fill_viridis_c(option = 'plasma') plt_map ``` We'll develop this map in a tutorial --- class: middle, center ## Using tmap --- ## Using tmap The **tmap** package uses many synactical structures similar to **ggplot2**, but can be nicer in some ways .left-column70[ ```{r} library(tmap) tm_shape(spData::world) + tm_polygons(col = "lifeExp", style='jenks', title = 'Life expectancy') ``` ] .right-column70[ It's more "publication-ready" by default It makes some nice choices ] --- ## tmap (interactive) ```{r, out.width='100%', out.height='100%', echo=F, eval=!fs::file_exists(here::here('docs/slides/lectures/week3/img/map_tmap.html'))} library(htmlwidgets) tmap_mode('view') #<< tm <- tm_shape(spData::world) + tm_polygons(col = 'pop', style='jenks', palette='Reds', title='Population', popup.vars = c('pop'), id='name_long') tmap_save(tm, here::here('docs/slides/lectures/week3/img/map_tmap.html')) ``` ```{r, eval=F, echo=T} tmap_mode('view') #<< tm <- tm_shape(spData::world) + tm_polygons(col = 'pop', style='jenks', palette='Reds', title='Population', popup.vars = c('pop'), id='name_long') ``` --- ## Street maps The easiest ways to overlay data on street maps is with the **leaflet** package. ```{r, eval=!fs::file_exists(here::here('docs/slides/lectures/week3/img/map1.html')), cache=FALSE} library(leaflet) library(leaflet.providers) load(file.path(here::here('slides','lectures','data', 'exdata.rda'))) leaflet(gpx) %>% addTiles() %>% addCircleMarkers(~Longitude, ~Latitude, radius=1) ``` --- ## Street maps You can also use the **mapview** package, which calls **leaflet** and has a bit more compact syntax .pull-left[ ```{r, echo=TRUE, eval=FALSE} load(file.path(here::here('slides','lectures','data', 'exdata.rda'))) gpx <- sf::st_as_sf(gpx, coords=c("Longitude", "Latitude"), crs = 4267) # Need to make sf object mapview::mapview(gpx, color='blue', map.type = 'OpenStreetMap.Mapnik', cex = 0.2, # size of points legend=FALSE) ``` ] .pull-right[ ```{r, echo=FALSE} knitr::include_graphics('img/run.png') ``` ] --- ## Street maps You can also use the **mapview** package, which calls **leaflet** and has a bit more compact syntax .pull-left[ ```{r, echo=TRUE, eval=FALSE} load(file.path(here::here('slides','lectures','data', 'exdata.rda'))) gpx <- st_as_sf(gpx, coords=c("Longitude", "Latitude"), crs = 4267) # Need to make sf object mapview::mapview(gpx, color='blue', map.type = 'Stamen.Watercolor', #<< cex = 0.2, # size of points legend=FALSE) ``` You can also have some stylistic fun with maps. More possibilities at [http://leaflet-extras.github.io/leaflet-providers/preview/](http://leaflet-extras.github.io/leaflet-providers/preview/) ] .pull-right[ ```{r, echo=FALSE} knitr::include_graphics('img/run2.png') ``` ] --- ## Dot density maps .pull-left[ ```{r, fig.height=4} library(ggmap) crime1 <- crime %>% filter(between(crime$lon, -95.4, -95.34) & between(crime$lat, 29.746, 29.784)) qmplot(lon, lat, data=crime1, maptype='toner-lite', color = I('red')) ``` ] .pull-right[ **ggmap** was built for Google Maps Google Maps requires a credit card now Better option is Stamen Maps, which uses OpenStreetMap data ] --- ## Dot density maps .pull-left[ ![](img/dot_density.png) ] .pull-right[ Code is available [here](./dot_density.R) Based on [this blog](https://tarakc02.github.io/dot-density/) by Tarak Shah ] --- ## Facetted maps .pull-left[ ```{r qm1, eval=F, echo=TRUE} library(ggmap) crime1 <- crime1 %>% filter(!(offense %in% c('auto theft','theft', 'burglary'))) qmplot(lon, lat, data=crime1, maptype='toner-background', color = offense)+ facet_wrap(~offense) ``` ] .pull-right[ ```{r, echo=FALSE, ref.label='qm1'} ``` ] --- ## Facetted maps .pull-left[ ```{r, eval=FALSE} library(tmap) world1 <- world %>% filter(continent %in% c('Europe','Asia', 'North America', 'South America')) %>% mutate(continent = fct_reorder(continent, lifeExp, na.rm=T)) tm_shape(world1)+tm_polygons(col='lifeExp') + tm_facets(by='continent', ncol=2) ``` ] .pull-right[ ```{r, echo=FALSE, out.height="100%", out.width="100%"} knitr::include_graphics('img/tmap_facet.png') ``` ]