Choropleth Maps With Leaflet

Choropleth maps are useful in displaying data across geographic regions. In these plots, the scale is represented by color and typically contained in defined spatial boundaries.

There are a number of ways to make choropleth visualizations in R, including the ggmap package and the choroplethr package. Both of the methods above seem to work fine. But I recently started using Leaflet, which is a JavaScript mapping library that’s bound to R with the Leaflet pakcage.

A couple advantages to using Leaflet:

  1. Interactivity (e.g. zooming, panning, popups on hover, etc.)
  2. Diversity of “provider tiles” (i.e. styles of maps)

Dropping geocoded points on map with Leaflet is easy enough. All you need to do is:

  1. Create a basemap with leaflet()
  2. Add a map “tile” (style) with addTiles()
  3. Add marker(s) for according to the latitude and longitude of the point(s) with addMarkers()

nb leaflet supports piping with magrittr

library(leaflet)
library(magrittr)

leaflet() %>%
    addTiles() %>%
    addMarkers(lat = -22.9754567, lng = -43.3923875)

But that’s just a point on a map … what about the choropleth?

To color regions that by a density or value of a given metric, you first need to define the geographic boundaries. As the leaflet documentation points out the package can “Easily render Spatial objects from the sp package.”

For this example, we’ll use data on reported Zika cases as released by the CDC on Github to look at prevalence of Zika in the United States.

So to compare state to state in a choropleth map, we first need the geographic definitions of each state. These are publicly available on census.gov as shape files.

Once they are downloaded, the rgdal package can read the data in.

library(rgdal)

states <- readOGR(dsn = path.expand("cb_2015_us_state_20m"), layer = "cb_2015_us_state_20m")

Alternatively you can use the geojsonio package to read in the data from a JSON API hosted on Github:

library(geojsonio)
# get data for map
json_api <- "https://raw.githubusercontent.com/PublicaMundi/MappingAPI/master/data/geojson/us-states.json"
states <- geojson_read(json_api, what = "sp")

The sp object created above (“states”) stores its data in slots, which can be accessed with the “@” operator.

states@data

With the boundaries created, you can attach whatever data you’d like to map. Again in this case, we’ll be using Zika incidence for a single week in the United States. The code below reads the data (stored as a CSV on Github) and then aggregates it by state and attaches it as a column to the states@data data frame.

library(readr)
library(dplyr)
uszikaraw <- read_csv("https://raw.githubusercontent.com/cdcepi/zika/master/United_States/CDC_Report/data/CDC_Report-2016-06-29.csv")

uszika <-
    uszikaraw %>%
    filter(location_type == "state") %>%
    mutate(name = gsub("United_States-", "", location)) %>%
    group_by(name) %>%
    summarise(Zika.Cases = sum(value))

states@data <- left_join(states@data, uszika)

After the data have been prepared, onto the mapping …

First create a palette …

pal <- colorNumeric(
    palette = "YlGnBu",
    domain = states@data$Zika.Cases
)

Then the “popup” text to appear on hover …

casecountpopup <- paste0("<strong>", states@data$name, "</strong>", "<br>", "Number of Cases: ", states@data$Zika.Cases)

Now the Leaflet map itself.

nb the data will be mapped as “polygons” instead of “markers” and will be colored by number of Zika cases

leaflet(data = states) %>%
    addProviderTiles("OpenStreetMap.BlackAndWhite") %>%
    addPolygons(fillColor = ~pal(Zika.Cases), 
        fillOpacity = 0.8, 
        color = "#BDBDC3", 
        weight = 1,
        popup = casecountpopup) %>%
    addLegend(position = "bottomleft",pal = pal, values = ~Zika.Cases, title = "<strong>USA Zika Cases</strong><br>(Week of 6/29/16)") %>%
    setView(lat = 38.0110306, lng = -110.4080342, zoom = 3)

The leaflet documentation provides resources on how to further customize Leaflet maps. And this tutorial details a similar workflow for how to create a Leaflet choropleth with R.

Related