Lesson 8. Creating Interactive Spatial Maps in R Using Leaflet

Learning Objectives

After completing this tutorial, you will be able to:

  • Create an interactive leaflet map using R and rmarkdown.
  • Customize an interactive map with data-driven popups.

What You Need

You will need a computer with internet access to complete this lesson.

# load packages

Interactive Maps with Leaflet

Static maps are useful for creating figures for reports and presentation. Sometimes, however, you want to interact with your data. You can use the leaflet package for R to overlay your data on top of interactive maps. You can think about it like Google maps with your data overlaid on top!

What is Leaflet?

Leaflet is an open-source JavaScript library that can be used to create mobile-friendly interactive maps.


  • Is designed with simplicity, performance and usability in mind.
  • Has a beautiful, easy to use, and well-documented API.

The leaflet R package ‘wraps’ Leaflet functionality in an easy to use R package! Below, you can see some code that creates a basic web map.

r_birthplace_map <- leaflet() %>%
  addTiles() %>%  # use the default base map which is OpenStreetMap tiles
  addMarkers(lng=174.768, lat=-36.852,
             popup="The birthplace of R")

Grey Background When You Knit

If your interactive map has a grey background when you knit to html, you can try to change the provider tile background, as described below on this page.

Create Your Own Interactive Map

Let’s create your own interactive map of the surface water data that you used in the previous lessons using leaflet. To do this, you will follow the steps below:

  1. Request and get the data from the colorado.gov SODA API in R using fromJSON().
  2. Address column data types to ensure your quantitative data (number values) data are in fact numeric.
  3. Remove NA (missing data) values.

The code below is the same code that you used to process the surface water data in the previous lesson.

base_url <- "https://data.colorado.gov/resource/j5pc-4t32.json?"
full_url <- paste0(base_url, "station_status=Active",
water_data <- getURL(URLencode(full_url))

# you can then pipe this
water_data_df <- fromJSON(water_data) %>%
  flatten(recursive = TRUE) # remove the nested data frame

# turn columns to numeric and remove NA values
water_data_df <- water_data_df %>%
  mutate_at(vars(amount, location.latitude, location.longitude), funs(as.numeric)) %>%

Once your data are cleaned up, you can create your leaflet map. Notice that you are using pipes %>% to set the parameters for the leaflet map.

# create leaflet map
water_locations_map <- leaflet(water_data_df) %>%
  addTiles() %>%
  addCircleMarkers(lng = ~location.longitude,
                   lat = ~location.latitude)

Data Tip: The code below provides an example of creating the same map without using pipes.

water_locations_map <- leaflet(water_data_df)
water_locations_map <- addTiles(water_locations_map)
water_locations_map <- addCircleMarkers(water_locations_map, lng = ~location.longitude,
                        lat = ~location.latitude)

Customize Leaflet Maps

You can customize your leaflet map too. Let’s do the following:

  1. Add custom data-driven popups to your map.
  2. Adjust the point symbology.
  3. Adjust the basemap. Let’s use a basemap from CartoDB called Positron.

Notice in the code below that you can specify the popup text using the popup= argument.

addMarkers(lng=~location.longitude, lat = ~location.latitude, popup = ~station_name)

You specify the basemap using the addProviderTiles() argument. In the example below, you use the CartoDB.Positron basemap:


leaflet(water_data_df) %>%
  addProviderTiles("CartoDB.Positron") %>%
  addMarkers(lng = ~location.longitude, lat = ~location.latitude,
             popup = ~station_name)

Custom Icons

You can specify a custom icon, too. Below, you are using an icon from the web.

Notice also that you are customizing the popup even more, adding BOTH the station name AND the discharge value.

paste0(station_name, "<br/>Discharge: ", amount)

You are using paste0() to do this. Remember that paste0() will paste together a series of text strings and object values.

# let's look at the output of your popup text before calling it in leaflet
# use head() to just look at the first 6 lines of the output
head(paste0(water_data_df$station_name, "<br/>Discharge: ", water_data_df$amount))
## [1] "SMEAD DITCH<br/>Discharge: 3.78"            
## [2] "PECK PELLA CLOVER DITCH<br/>Discharge: 1.56"
## [3] "TRUE AND WEBSTER DITCH<br/>Discharge: 0.1"  
## [4] "DENIO TAYLOR DITCH<br/>Discharge: 0.01"     
## [5] "BONUS DITCH<br/>Discharge: 23.33"           
## [6] "BOULDER RESERVOIR INLET<br/>Discharge: 64"

The <br/> element in your popup above is HTML. This adds a line break to your popup so the Discharge text and value are on the second line - below the station name.

Let’s see what the custom icon and popup text looks like on your map.

# Specify custom icon
url <- "http://tinyurl.com/jeybtwj"
water <- makeIcon(url, url, 24, 24)

leaflet(water_data_df) %>%
  addProviderTiles("Stamen.Terrain") %>%
  addMarkers(lng = ~location.longitude, lat = ~location.latitude, icon=water,
             popup = ~paste0(station_name,
                           "<br/>Discharge: ",
url <- "http://tinyurl.com/jeybtwj"
water <-  makeIcon(url, url, 24, 24)

map = leaflet(water_data_df) %>%
  addProviderTiles("Stamen.Terrain") %>%
  addMarkers(lng = ~location.longitude, lat=~location.latitude, icon=water,
             popup = ~paste0(station_name, "<br/>Discharge: ", amount))

There is a lot more to learn about leaflet. Here, you’ve just scratched the surface.

# water_data_df
water_data_df$station_type <- factor(water_data_df$station_type)

new <- c("red", "green","blue")[water_data_df$station_type]

icons <- awesomeIcons(
  icon = 'ios-close',
  iconColor = 'black',
  library = 'ion',
  markerColor = new

unique_markers_map <- leaflet(water_data_df) %>%
  addProviderTiles("CartoDB.Positron") %>%
  addAwesomeMarkers(lng=~location.longitude, lat=~location.latitude, icon=icons,
saveWidget(widget = unique_markers_map,
           file = "water_map_unique_markers1.html",
           selfcontained = TRUE)

Here you use addAwesomeMarkers() and adjust the color of each point on the map accordingly.

You can also use addCircleMarkers() and adjust the colors of the markers accordingly. To use the code below, you need to install additional dependencies including the webshot package and PhantomJS.

pal <- colorFactor(c("navy", "red", "green"),
                   domain = unique(water_data_df$station_type))
unique_markers_map_2 <- leaflet(water_data_df) %>%
  addProviderTiles("CartoDB.Positron") %>%
    color = ~pal(station_type),
    stroke = FALSE, fillOpacity = 0.5,
    lng = ~location.longitude, lat = ~location.latitude,
    label = ~as.character(station_type)
saveWidget(widget = unique_markers_map_2,
           file = "water_map_unique_markers2.html",
           selfcontained = TRUE)

Leave a Comment