Leaflet in R

Handouts for this lesson need to be saved on your computer. Download and unzip this material into the directory (a.k.a. folder) where you plan to work.


Introduction

Leaflet is a powerful open-source Javascript library that powers interactive maps on the web. This lesson provides an overview of using leaflet, the namesake package in R, to create “slippy” web maps from R and integrate them into RShiny apps.

Like static plotting and mapping, there lots of options for interactive mapping in R. The leaflet package is actively maintained by RStudio. Some other packages for interactive maps that build off of leaflet, or other interactive plotting libraries, are: tmap, ggiraph, rbokeh, plotly, highcharter, mapedit, mapview, leaflet.extras, and leaflet.esri.

Objectives for this lesson

Top of Section


What’s a Leaflet?

leaflet produces maps have controls to zoom, pan and toggle layers on and off, and can combine local data with base layers from web mapping services.

Maps will appear in RStudio’s Viewer pane, and can also be viewed in a web browser and saved as html files.

The leaflet() function creates an empty leaflet map to which layers can be added using the pipe (%>%) operator. The addTiles() functions adds a base tiled map; by default, it uses tiles made from OpenStreetMap data. Center and set an initial zoom level the map with setView(). Switch to the “Viewer” tab in RStudio to see the result.

library(leaflet)
library(webshot)

leaflet() %>%
    addTiles() %>%
    setView(lng = -76.505206, lat = 38.9767231, zoom = 7)

Add a new layer with a point marker using addMarkers(), with a custom message that displays when the marker is clicked.

leaflet() %>%
  addTiles() %>%
  setView(lng = -76.505206, lat = 38.9767231, zoom = 7) %>%
  addMarkers(lng = -76.505206, lat = 38.9767231, popup = "I am here!")

In addition to OSM, there are many other data providers that make sets of tiles available to use as basemaps. There is a R list object called providers with the names of these options.

leaflet() %>%
  addProviderTiles(providers$Esri.WorldImagery) %>%
  setView(lng = -76.505206, lat = 38.9767231, zoom = 7) %>%
  addMarkers(lng = -76.505206, lat = 38.9767231, popup = "I am here!")

Zoom all the way out. What projection does it look like this map is using? dragons

Read more about the intracacies of web mercator e.g. why it is considered unsuitable for geospatial intelligence purposes. Learn how to define a custom leafletCRS here or see examples.

Top of Section


Layers Control

Layers can be assigned to named groups which can be toggled on and off by the user. baseGroups are selected with radio buttons (can only choose one at a time), and overlayGroups get checkboxes.

To implement layers control, add group names to individual layers with the group = argument AND add the layers control layer using addLayersControl().

leaflet() %>%
  addTiles(group = "OSM") %>%
  addProviderTiles(providers$Esri.WorldImagery, group = "Esri World Imagery") %>%
  setView(lng = -76.505206, lat = 38.9767231, zoom = 7) %>%
  addMarkers(lng = -76.505206, lat = 38.9767231, popup = "I am here!", group = "SESYNC") %>%
  addLayersControl(baseGroups = c("OSM", "Esri World Imagery"), 
                   overlayGroups = c("SESYNC"),
                   options = layersControlOptions(collapsed = FALSE))

Another type of tile layer is avaible through many web mapping services (WMS), such as the real-time weather radar data from the Iowa Environmental Mesonet.

leaflet() %>%
  addTiles() %>%
  setView(lng = -76.505206, lat = 38.9767231, zoom = 5) %>%
  addWMSTiles(
    "http://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi",
    layers = "nexrad-n0r-900913", 
    options = WMSTileOptions(format = "image/png", transparent = TRUE),
    attribution = "Weather data © 2012 IEM Nexrad"
  )

or USGS topographic maps from the National Map:

nhd_wms_url <- "https://basemap.nationalmap.gov/arcgis/services/USGSTopo/MapServer/WmsServer"

leaflet() %>% 
  setView(lng = -111.846061, lat = 36.115847, zoom = 12) %>%
  addWMSTiles(nhd_wms_url, layers = "0")

Thanks USGS! Check out more USGS Web Mapping Services, and R packages for accessing, processing, and modeling data on github.

In addition to tile layers and markers, many other map features can be added and customized with add*() functions. Refer to the help documentation (eg. ?addMiniMap) to see all of the customization options and learn the default settings.

leaflet() %>% 
  setView(lng = -111.846061, lat = 36.115847, zoom = 12) %>%
  addWMSTiles(nhd_wms_url, layers = "0") %>%
  addMiniMap(zoomLevelOffset = -4)

Add layers with common map elements and customize them with add*. Even more new features coming soon!

leaflet() %>% 
  setView(lng = -111.846061, lat = 36.115847, zoom = 12) %>%
  addWMSTiles(nhd_wms_url, layers = "0") %>%
  addMiniMap(zoomLevelOffset = -4) %>%
  addGraticule() %>%
  addTerminator() %>% 
  addMeasure() %>%
  addScaleBar()

Trigger custom javascript logic with EasyButtons.

leaflet() %>%
  addTiles() %>% 
  addEasyButton(easyButton(
    icon="fa-crosshairs", title = "Locate me", 
    onClick=JS("function(btn, map){ map.locate({setView: true}); }")))

The fine print: Note that RStudio’s viewer pane or external window does not always behave the same as a web brower.

Top of Section


Add data Layers

Spatial objects (points, lines, polygons, rasters) in your R environment can also be added as map layers, provided that they have a CRS defined with a datum. Leaflet will try to make the necessary trasnformation to display your data in EPSG:3857.

Read in data using sf and raster packages. Points are from the Water Quality Portal accessed via the dataRetrieval package. County boundaries are from the Census and Watershed boundaries are from USGS.

library(sf)
library(raster)
library(dplyr)
wqp_sites <- st_read("data/wqp_sites")
counties_md <- st_read("data/cb_2016_us_county_5m") %>% 
  filter(STATEFP == "24") %>% st_transform(4326)
wbd_reg2 <- st_read("data/huc250k/") %>%
  filter(REG == "02") %>% st_transform(4326)
nlcd <- raster("data/nlcd_crop.grd")

Add a polygons layer, being sure to specify the data = argument. All of the add* layers have “map” as the first argument, facilitating use of the pipe (%>%) operator, but data is not the second argument so it must be named.

leaflet() %>%
  addTiles() %>%
  addPolygons(data = counties_md)

Customize Polygons with border and fill colors and opacities.

leaflet() %>%
  addTiles() %>%
  addPolygons(data = counties_md, 
              color = "green", 
              fillColor = "gray", 
              fillOpacity = 0.75, 
              weight = 1)

Attributes can be referred to using formula syntax ~ to access attribute data from an sf object or Spatial*DataFrame. What is the difference between a popup and a label?

leaflet() %>%
  addTiles() %>%
  addPolygons(data = counties_md, popup = ~NAME, group = "click") %>%
  addPolygons(data = counties_md, label = ~NAME, group = "hover") %>%
  addLayersControl(baseGroups = c("click", "hover"))

For numeric or categorical data, create a color palette from colorbrewer using colorNumeric(), colorFactor(), colorBin(), or colorQuantile().

pal <- colorNumeric("PiYG", wbd_reg2$AREA)
leaflet() %>%
  addTiles() %>%
  addPolygons(data = wbd_reg2, 
              fillColor = ~pal(AREA), 
              fillOpacity = 1, 
              weight =1)