Interactive Mapping with Leaflet in R

[This article was first published on spatialRecology - r, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Contents

Introduction

Leaflet lets you create interactive maps right from the R console. Interactive panning and zooming allows for an explorative view on your pinpointed location. Leaflet provides a simple and fast way to host interactive maps online in R, requiring only 2 lines of code for a basic web map. It is developed by the RStudio team and has therefore a great integration in a workflow with shiny.

The basic usage looks like this:

  1. Create a map widget
  2. Add layers of your interest
  3. Render the map
  4. … enjoy your beautiful map

1. First Steps

But, where to start? The first step will be the installation of leaflet:

devtools::install_github("rstudio/leaflet")

We have to use devtools because leaflet is not yet on CRAN.

The creation of a basic map-widget is afterwards rather simple:

library(leaflet)
your.map <- leaflet() %>% addTiles()
your.map # print the map

The function leaflet() creates a map widget. You can pass your data at this point with the data argument, or add it later on.

For the sake of simplicity, it is very handy to use the pipe operator %>% of the magrittr package (Ctl+Shift+M in R-Studio). Since most of the leaflet functions use the argument data as their first one, this approach makes your code a lot easier to read and you avoid nested bracketted commands. This way we can gradually add elements to our map, one-by-one.

… voilà, your interactive map-widget with the default OpenStreetMap tile layer.

1.2 Adding Data

There are now several ways to illustrate your data:

addControl addTiles addWMSTiles addPopups
addMarkers addCircleMarkers addCircles addPolylines
addRectangles addPolygons addGeoJSON  

With these commands you can add graphics elements and layers to your map. The package provides four options to pass data to the map-widget:

  1. Data from base R:
    • lat/long matrix
    • data.frame with lat/long columns
  2. Data from the sp package:
    • any of the spatial classes provided by sp
  3. Data from maps package:
    • any of the maps from the map database
  4. JSON format:
    • add your data in GeoJSON or TopoJSON format via jsonlite

1.2.1 Example

Let’s try adding a hiking trail, one that I plan to hopefully hike in the near future: The Pacific Coast Trail (PCT). The trail spans 2,650 miles (4,265 kilometers) from Mexico to Canada through California, Oregon, and Washington.

First download some data and prepare the layers we want to add:

library(rgdal)
library(maps)

# Fetch the route of the PCT and convert it into a SpatialLine object
url <- "http://hiking.waymarkedtrails.org/en/routebrowser/1225378/gpx"
download.file(url, destfile = "pct.gpx", method = "wget")
pct <- readOGR("pct.gpx", layer = "tracks")

# Import list with shapefiles of the three states the PCT is crossing
mapStates <- map("state", fill = TRUE,
                 plot = FALSE,
                 region = c('california', 'oregon', 'washington:main'))

Now we use the appropriate functions to display the layers on the map-widget:

your.map <- leaflet(pct) %>%

            # Add layer
            addTiles(urlTemplate = "http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png") %>%
            addPolylines(color="red", popup="PCT")  %>%
            addMarkers(-116.4697, 32.60758, popup = "Campo") %>%
            addMarkers(-120.7816, 49.06465, popup = "Manning Park, Canada") %>%
            addPolygons(data=mapStates, fillColor = heat.colors(3, alpha = NULL), stroke = FALSE) %>%
            
            # Add legend
            addLegend(position = 'topright', colors = "red", labels = "PCT", opacity = 0.4,
                      title = 'Legend')
your.map

1.4 Useful commands from other spatial R packages

  • getData from the raster package. With getData you can retrieve geographic data for anywhere in the world - probably most important will be the possibility to communicate with the spatial database for global administrative areas.
  • geocode from the ggmap package. Retrieves the coordinates of a spatial search query using Google Maps.

3. Exporting your Web Widget

To my current knowledge there are three ways to export the map-widget from R:

2.1 Shiny

We can render the leaflet object with the following lines of code:

library(shiny)

app <- shinyApp(
  ui <- fluidPage(leafletOutput('myMap')),
  server <- function(input, output) {
    map <- your.map
    output$myMap <- renderLeaflet(map)
  }
)

if (interactive()) print(app)

2.2 RStudio GUI

RStudio offers a “clickable” solution to export the map-widget:

Viewer -> Export -> Save as Web Page...

However, these option is only avaible for small layers. The trail of the PCT has over 99,000 vertices and the export fails with:

Stack space overflow: current size 16777216 bytes.
Use `+RTS -Ksize -RTS' to increase it.
Error: pandoc document conversion failed with error 2

2.3 Rmarkdown

By embedding the leaflet object in a rmarkdown document, which will be rendered into a html:

---
title: "Untitled"
output: html_document
self_contained: no
---


```{r, echo=F, warning=F, message=F}
#load leaflet package for R
library(leaflet)
library(maps)
library(rgdal)

url <- "http://hiking.waymarkedtrails.org/en/routebrowser/1225378/gpx"
download.file(url, destfile = "pct.gpx", method = "wget")
pct <- readOGR("pct.gpx", layer = "tracks")

mapStates = map("state", fill = TRUE, plot = FALSE, region = c('california', 'oregon', 'washington:main'))

your.map <- leaflet(pct) %>%

            # Add layer
            addTiles(urlTemplate = "http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png") %>%
            addPolylines(color="red", , weight = 4,  popup="PCT")  %>%
            addMarkers(-116.4697, 32.60758, popup = "Campo") %>%
            addMarkers(-120.7816, 49.06465, popup = "Manning Park, Canada") %>%
            addPolygons(data=mapStates, fillColor = heat.colors(3, alpha = NULL), stroke = FALSE) %>%
            
            # Add legend
            addLegend(position = 'topright', colors = "red", labels = "PCT", opacity = 0.4,
                      title = 'Legend')
your.map
```

Note that with self_contained: no you fix the pandoc conversion error from the RStudio GUI.

2.4 Update

I just found this nice funtion from the htmlwidgets package:

saveWidget(widget = your.map, file="your_map.html", selfcontained = FALSE)

Seems to be the smoothest way to export the map-widget, which works even for very big datasets.

3. A closer look on addTile() and addLayersControl()

For me, one of the fascinating things about the leaflet package was the diverse range of available tiles. With addTile(urlTemplate = ...) the integration of any tile is straightforward and lets you compose beautiful maps. A good resource of available tiles can be found here:

… but wouldn’t it be cool to stack your favorite tiles and chose between them in your map-widget? Of course it would and the guys from RStudio just implemented these with addLayersControl. The function is like the whole package very simple. You define two groups: i) the baseGroup and ii) the overlayGroup. Then you pass each individual layer with the parameter group into one of the two groups. For the baseGroups can only one group at a time be viewed and for the overlayGroups each layer can be individually checked or unchecked.

your.map <- leaflet(pct) %>%

            # Add tiles as baseGroup
            addProviderTiles("OpenTopoMap", group = "MapQuestOpen.Aerial") %>%
            addProviderTiles("MapQuestOpen.Aerial", group = "MapQuestOpen.Aerial") %>%
            addProviderTiles("OpenMapSurfer.Roads", group = "OpenMapSurfer.Roads") %>%
            
            # Add layers as overlayGroup
            addPolylines(color="red", , weight = 4,  popup="PCT", , group = "PCT")  %>%
            addMarkers(-116.4697, 32.60758, popup = "Campo", group="Southern Terminus") %>%
            addMarkers(-120.7816, 49.06465, popup = "Manning Park, Canada", group="Northern Terminus") %>%
            hideGroup("Southern Terminus") %>%
            hideGroup("Northern Terminus") %>%
            addPolygons(data=mapStates, fillColor = heat.colors(3, alpha = NULL), stroke = FALSE,
                        group = "States")  %>%
                        
            # Layers control
            addLayersControl(
              baseGroups = c("MapQuestOpen.Aerial", "OpenTopoMap", "OpenMapSurfer.Roads"),
              overlayGroups = c("PCT", "Southern Terminus", "Northern Terminus", "States"),
              options = layersControlOptions(collapsed = FALSE)
            ) 

your.map

Conclusion

In my opinion the possibility to embed the map-widget in a Shiny application makes the leaflet package very useful for every kind of spatial analysis. With an app created by shiny in combination with leaflet we can let the user of the app control the parameters of the display of the map, as well as the parameters for any sort of statistical analyse or underlying model. For more details have a look at http://rstudio.github.io/leaflet/shiny.html.

To leave a comment for the author, please follow the link and comment on their blog: spatialRecology - r.

R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Never miss an update!
Subscribe to R-bloggers to receive
e-mails with the latest R posts.
(You will not see this message again.)

Click here to close (This popup will not appear again)