An introduction to R Leaflet

Contents

  1. My first Leaflet map
  2. Add point data
  3. Add polygon data
  4. Add popup graphs and images
  5. Add extra customisation and widgets
  6. Final map
  7. Further resources and R session info

1. My first Leaflet map

Leaflet is an open-source JavaScript library for creating interactive maps. It supports vector and raster GIS data and has lots of plugins, widgets and customisation options. R users can access most of the features of Leaflet though the RStudio leaflet package. In this demo, we will cover some of the basics of R Leaflet and introduce adding and customising basemaps, feature layers and interactive widgets to your Leaflet map, with a particular focus on code that I’ve found most useful to-date.

Install and load R packages

library(leaflet)
library(leafpop)
library(leaflet.extras)
library(htmltools)
library(sf)
library(tidyverse)
library(rnaturalearth)
library(lattice)
library(htmlwidgets)
library(widgetframe)

Create a map centred on the centre point of the UK. Add multiple basemaps and a layers control switch

# Coordinates of the centre point of the UK: Whitendale Hanging Stones
whitendale = c(-2.547855, 54.00366)

l1 = leaflet() %>%
  # Centre map on Whitendale Hanging Stones
  setView(lng = whitendale[1], lat = whitendale[2], zoom = 6) %>% 
  # Add OSM basemap
  addProviderTiles(providers$OpenStreetMap, group = "Open Street Map") %>% 
  # Add additional basemap layers
  addProviderTiles(providers$Esri.WorldImagery, group = "ESRI World Imagery") %>% 
  addProviderTiles(providers$Esri.OceanBasemap, group = "ESRI Ocean Basemap") %>% 
  # Add a User-Interface (UI) control to switch layers
  addLayersControl(
    baseGroups = c("Open Street Map","ESRI World Imagery","ESRI Ocean Basemap"),
    options = layersControlOptions(collapsed = FALSE)
    )

# widgetframe::frameWidget() function only required to render Leaflet map in RMarkdown
frameWidget(l1, width = "100%", height = "500")

Back to Contents

2. Add point data

Here, we download a boundary outline of the United Kingdom from the rnaturalearth package as an sf object. R Leaflet requires all spatial data to be supplied in longitude and latitude using WGS 84 (EPSG:4326). Then, we sample points randomly within the UK polygon and add these points to the map created in Step 1.

Download a polygon outline of the UK and sample 100 random points

# UK boundary outline
uk_outline = ne_countries(country = "United Kingdom", scale = "medium", returnclass = "sf") %>% 
  # Keep only geometry
  st_geometry() %>% 
  # Transform coordinate reference system (CRS) to WGS84
  st_transform(crs = 4326)
plot(uk_outline)

# Sample 100 random points within the UK polygon
set.seed(1234)
uk_pts = st_sample(uk_outline, size = 100)
plot(uk_pts, pch = 21, col = "black", bg = "yellow", add = TRUE)

Add points to the map as markers

This code adds the point data to the map as markers and a label for each marker appears on mouse hover.

l2 = l1 %>%
  # Add point data with a label
  addMarkers(
    data = uk_pts,
     # Label appears on mouse hover
     label = paste("Label", seq(1:100)),
     # Options to customise the label text and size
     labelOptions = labelOptions(
       textsize = "14px", # text size
       style = list(
        "font-weight" = "bold", # bold text
        padding = "5px" # padding around text
        )
       )
    )

# widgetframe::frameWidget() function only required to render Leaflet map in RMarkdown
frameWidget(l2, width = "100%", height = "500")

Add tree icons instead of markers to represent the points

# Link to icon
tree_icon = "https://cdn-icons-png.flaticon.com/512/490/490091.png"

l2 = l1 %>%
  # Add point data with a label
  addMarkers(
    data = uk_pts,
    group = "Tree icons",
    # Label appears on mouse hover
    label = paste("Label", seq(1:100)),
    # Options to customise the label text and size
    labelOptions = labelOptions(
      textsize = "14px", # text size
      style = list(
        "font-weight" = "bold", # bold text
        padding = "5px" # padding around text
      )
    ),
    # Change markers to custom icons
    icon = list(
      iconUrl = tree_icon,
      iconSize = c(20, 20)
      )
    )

# widgetframe::frameWidget() function only required to render Leaflet map in RMarkdown
frameWidget(l2, width = "100%", height = "500")

Back to Contents

3. Add polygon data

Create a polygon using a bounding box of four coordinates

# Boundary box
poly_df = data.frame(lon = c(-1.5,-0.9), lat = c(52.0,52.2))

# Convert to a polygon sf object
poly1 = st_as_sf(poly_df, coords = c("lon","lat"), crs = 4326) %>%
  st_bbox %>% 
  st_as_sfc %>% 
  st_as_sf
# plot(poly1)

Add polygon to the map

This code creates a blue polygon, the border of which is highlighted white on mouse hover and a popup label appears on mouse click.

l3 = l2 %>%
  # Add polygon to map
  addPolygons(
    data = poly1,
    group = "Polygon 1",
    # stroke parameters
    weight = 3, color = "blue",
    # fill parameters
    fillColor = "blue", fillOpacity = 0.1,
    # Popup label
    popup = "Polygon 1",
    # Options to customise polygon highlighting
    highlightOptions = highlightOptions(
      # Highlight stroke parameters
      weight = 3, color = "white",
      # Highlight fill parameters
      fillColor = "blue", fillOpacity = 0.1
      )
    )

# widgetframe::frameWidget() function only required to render Leaflet map in RMarkdown
frameWidget(l3, width = "100%", height = "500")

Back to Contents

4. Add popup graphs and images

Sample two additional random points within the UK boundary outline

# Sample two random points and visualise on UK outline 
set.seed(1234)
uk_pts2 = st_sample(uk_outline, size = 2)
plot(uk_outline)
plot(uk_pts, pch = 21, col = "black", bg = "yellow", add = TRUE)
plot(uk_pts2, pch = 21, col = "black", bg = "red", add = TRUE)

Prepare graph and image examples to popup on mouse click

# Example graph to show
graph1 = levelplot(t(volcano), col.regions = heat.colors(100), xlab = "", ylab = "")

# Example image to show (GIFs can also be used)
img1 = "https://www.r-project.org/logo/Rlogo.png"
# img1 = "https://upload.wikimedia.org/wikipedia/commons/d/d6/MeanMonthlyP.gif"

Add popup graph and image to the map

This code uses the addPopupGraphs() and addPopupImages() functions from the leafpop package. addPopupGraphs() expects a list of lattice or ggplot2 objects, while addPopupImages expects a vector of file paths or web-URLs to image files. When using more than one graph or image, the number should be the same as the number of points for the popups to render correctly. You may also need to check that the order of the graphs or images matches that of the order of the points so that the correct popup appears on the correct point.

l4 = l3 %>%
  # Add red circle point with a popup graph on mouse click
  addCircles(
    data = uk_pts2[1],
    # group argument essential for linking to popup graph
    group = "Circle point 1",
    # circle size
    radius = 10000,
    # circle stroke parameters
    weight = 1, color = "black",
    # circle fill parameterse
    fillColor = "red", fillOpacity = 0.8,
    # highlight options
    highlightOptions = highlightOptions(
      weight = 1, color = "white", fillOpacity = 0.8
      )
    ) %>% 
  # Add popup graph
  addPopupGraphs(
    graph = list(graph1), width = 200, height = 200,
    group = "Circle point 1"
    )%>%
  # Add red circle point with a popup image on mouse click
  addCircles(
    data = uk_pts2[2],
    # group argument essential for linking to popup image
    group = "Circle point 2",
    # circle size
    radius = 10000,
    # circle stroke parameters
    weight = 1, color = "black",
    # circle fill parameterse
    fillColor = "red", fillOpacity = 0.8,
    # highlight options
    highlightOptions = highlightOptions(
      weight = 1, color = "white", fillOpacity = 0.8
      )
    ) %>% 
  # Add popup image
  addPopupImages(
    image = img1, width = 100, height = 100,
    group = "Circle point 2"
    )

# widgetframe::frameWidget() function only required to render Leaflet map in RMarkdown
frameWidget(l4, width = "100%", height = "500")

Back to Contents

5. Add extra customisation and widgets

This code enables the following:

  • Button to reset the map view to its default setting
  • Minimap display which can be toggled on or off
  • Measurement widget to compute distances and areas
  • Scale bar
  • Layers control switch to toggle layers on or off
  • Define the zoom levels for which layers are displayed
l5 = l4 %>%
  # Reset map to default setting
  leaflet.extras::addResetMapButton() %>% 
  # Add an inset minimap
  addMiniMap(
    position = "topright",
    tiles = providers$Esri.WorldStreetMap,
    toggleDisplay = TRUE,
    minimized = FALSE
    ) %>%
  # Add measurement tool
  addMeasure(
    position = "topleft",
    primaryLengthUnit = "meters",
    secondaryLengthUnit = "kilometers",
    primaryAreaUnit = "sqmeters"
    ) %>%
  # Add scale bar
  addScaleBar(
    position = "bottomright",
    options = scaleBarOptions(imperial = FALSE)
    ) %>% 
  # Add a User-Interface (UI) control to switch layers
  addLayersControl(
    position = "topright",
    baseGroups = c("Open Street Map","ESRI World Imagery","ESRI Ocean Basemap"),
    # Add an option in layer control to toggle layers
    overlayGroups = c("Polygon 1","Circle point 1","Circle point 2","Tree icons"),
    # Choose to permanently display or collapse layers control switch
    options = layersControlOptions(collapsed = TRUE)
    ) %>% 
  # Only show tree icons at a defined zoom level
  groupOptions("Tree icons", zoomLevels = 8:20) 

6. Final map

Back to Contents

7. Further resources and R session info

Leaflet for R: vignette
R package: leaflet.extras
R package: leaflet.extras2
R package: leafpop
R package: leafem
R package: leafgl

sessionInfo()
## R version 4.1.1 (2021-08-10)
## Platform: x86_64-w64-mingw32/x64 (64-bit)
## Running under: Windows 10 x64 (build 19043)
## 
## Matrix products: default
## 
## locale:
## [1] LC_COLLATE=English_United Kingdom.1252 
## [2] LC_CTYPE=English_United Kingdom.1252   
## [3] LC_MONETARY=English_United Kingdom.1252
## [4] LC_NUMERIC=C                           
## [5] LC_TIME=English_United Kingdom.1252    
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] widgetframe_0.3.1    htmlwidgets_1.5.4    lattice_0.20-44     
##  [4] rnaturalearth_0.1.0  forcats_0.5.1        stringr_1.4.0       
##  [7] dplyr_1.0.7          purrr_0.3.4          readr_2.1.1         
## [10] tidyr_1.1.4          tibble_3.1.5         ggplot2_3.3.5       
## [13] tidyverse_1.3.1      sf_1.0-5             htmltools_0.5.2     
## [16] leaflet.extras_1.0.0 leafpop_0.1.0        leaflet_2.0.4.1     
## 
## loaded via a namespace (and not attached):
##  [1] fs_1.5.2                lubridate_1.8.0         httr_1.4.2             
##  [4] tools_4.1.1             backports_1.4.1         bslib_0.3.1            
##  [7] utf8_1.2.2              R6_2.5.1                KernSmooth_2.23-20     
## [10] rgeos_0.5-9             DBI_1.1.2               colorspace_2.0-2       
## [13] withr_2.4.3             sp_1.4-5                tidyselect_1.1.1       
## [16] rnaturalearthdata_0.1.0 compiler_4.1.1          cli_3.1.0              
## [19] rvest_1.0.2             xml2_1.3.3              bookdown_0.24          
## [22] sass_0.4.0              scales_1.1.1            classInt_0.4-3         
## [25] proxy_0.4-26            systemfonts_1.0.3       digest_0.6.28          
## [28] rmarkdown_2.11          svglite_2.0.0           base64enc_0.1-3        
## [31] pkgconfig_2.0.3         highr_0.9               dbplyr_2.1.1           
## [34] fastmap_1.1.0           rlang_0.4.12            readxl_1.3.1           
## [37] rstudioapi_0.13         jquerylib_0.1.4         generics_0.1.1         
## [40] jsonlite_1.7.2          crosstalk_1.2.0         magrittr_2.0.1         
## [43] s2_1.0.7                Rcpp_1.0.7              munsell_0.5.0          
## [46] fansi_0.5.0             lifecycle_1.0.1         stringi_1.7.6          
## [49] yaml_2.2.1              grid_4.1.1              crayon_1.4.2           
## [52] haven_2.4.3             hms_1.1.1               knitr_1.37             
## [55] pillar_1.6.4            uuid_1.0-3              markdown_1.1           
## [58] wk_0.5.0                reprex_2.0.1            glue_1.4.2             
## [61] evaluate_0.14           blogdown_1.6            leaflet.providers_1.9.0
## [64] modelr_0.1.8            vctrs_0.3.8             tzdb_0.2.0             
## [67] cellranger_1.1.0        gtable_0.3.0            assertthat_0.2.1       
## [70] xfun_0.27               broom_0.7.10            e1071_1.7-9            
## [73] class_7.3-19            units_0.7-2             ellipsis_0.3.2         
## [76] brew_1.0-6
Tom Jenkins
Tom Jenkins
Bioinformatician & Software Developer