3 Interactive maps with R

Code for this lesson

Learning objectives:

After this tutorial, you will be able to create an interactive map in R using the leaflet package.



Why interactive maps?

While static maps are useful for reports and presentations, interactive maps allow you to pan around and zoom into any part of a your geographic dataset using a web map to put your data into context.

Interactive maps also provide options for different interactivity types, for e.g. popups which provide information about your data when clicked on the map.

The package we use for making interactive maps is called Leaflet, and it has an excellent documentation website: check it out here.

R packages needed for this session

library(dplyr)
library(leaflet)
library(htmlwidgets)

Reading in data

events = read.csv("data/sample/event_short.csv", stringsAsFactors = FALSE)
animals = read.csv("data/sample/animal_short.csv", stringsAsFactors = FALSE)

Check what we just imported

# Check what we have:
head(events)

# What's the structure of our event data?
str(events)

Similarly, for the animals data:

head(animals)

str(animals)

Getting unique sites for mapping (to avoid overlapping)

sites = events %>%
    group_by(SiteName, StateProv, District, SiteLatitude, SiteLongitude) %>%
    summarise(n = n())

Starting with leaflet

The leaflet package enables us to create beautiful interactive maps in R.

To begin, let’s create an empty map. See what running the following command gives you.

leaflet() %>% addTiles()


Use a more aesthetic base map, similar to the ones we used in the QGIS session. To see all your options fo extra base maps, see here.

leaflet() %>% addProviderTiles(providers$Esri.NatGeoWorldMap)


That’s better.

Map your data

Now, let’s add our site data. We do that with the addCircleMarkers function. If you want to see what arguments it needs, run ?addCircleMarkers in your R console.

map_sites = leaflet() %>%
    addProviderTiles(providers$Esri.NatGeoWorldMap) %>%
    addCircleMarkers(data = sites,
                     lng = ~SiteLongitude,
                     lat = ~SiteLatitude)

map_sites


Now adjust the size of the site circle markers.

map_sites = leaflet() %>%
    addProviderTiles(providers$Esri.NatGeoWorldMap) %>%
    addCircleMarkers(data = sites,
                     lng = ~SiteLongitude,
                     lat = ~SiteLatitude,
                     radius = 4)

map_sites


Show popups

How about we add some popup information? If you click on a point, a popup will display whatever information you set it up to show.

map_sites = leaflet() %>%
    addProviderTiles(providers$Esri.NatGeoWorldMap) %>%
    addCircleMarkers(data = sites,
                     lng = ~SiteLongitude,
                     lat = ~SiteLatitude,
                     radius = 4,
                     popup = ~SiteName)

map_sites


For the above, we set it so the Site Name would pop up. We can add much more information from our dataset.

# More detailed popups
sites$site_info = paste0("Site name: ", sites$SiteName, "<br>",
                   "StateProv: ", sites$StateProv, "<br>",
                   "District: ", sites$District, "<br>",
                   "Latitude: ", sites$SiteLatitude, "<br>",
                   "Longitude: ", sites$SiteLongitude)


map_site_info = leaflet() %>%
    addProviderTiles(providers$Esri.NatGeoWorldMap) %>%
    addCircleMarkers(data = sites,
                     lng = ~SiteLongitude,
                     lat = ~SiteLatitude,
                     radius = 4,
                     popup = ~site_info)

map_site_info


Adding a country polygon

To help put our site locations into context, we import a polygon layer for our country, and display it below the site data.

ctry_poly = readRDS("data/GIS/country_polygons/USA/gadm36_USA_1_sp.rds")

map_ctry_poly = leaflet() %>%
    addProviderTiles(providers$Esri.NatGeoWorldMap) %>%
    addPolygons(data = ctry_poly)

map_ctry_poly
# change the color of the polygon
map_ctry_poly = leaflet() %>%
    addProviderTiles(providers$Esri.NatGeoWorldMap) %>%
    addPolygons(data = ctry_poly,
                color = "green")

map_ctry_poly


Put it all together

map = leaflet() %>%
    addProviderTiles(providers$Esri.NatGeoWorldMap) %>%
    addPolygons(data = ctry_poly,
                color = "green") %>%
    addCircleMarkers(data = sites,
                     lng = ~SiteLongitude,
                     lat = ~SiteLatitude,
                     weight = 3,
                     radius = 4,
                     opacity = 0.7,
                     popup = ~site_info)

map

Give options for turning layers on/off

map = leaflet() %>%
    addProviderTiles(providers$Esri.NatGeoWorldMap,
                     group = "NatGeo") %>%
    addPolygons(data = ctry_poly,
                color = "green",
                group = "USA regions") %>%
    addCircleMarkers(data = sites,
                     lng = ~SiteLongitude,
                     lat = ~SiteLatitude,
                     weight = 3,
                     radius = 4,
                     opacity = 0.7,
                     popup = ~site_info,
                     group = "Sites")


map = map %>%
    addLayersControl(
    overlayGroups = c("USA regions", "Sites"),
    options = layersControlOptions(collapsed = FALSE))

map


Add the animal sampling data

We add the animal data and use the clusterOptions argument so that leaflet aggregates the numbers for us.

# first, let's map animals as is (without sites)
map_animals = leaflet() %>%
    addProviderTiles(providers$Esri.NatGeoWorldMap,
                     group = "NatGeo") %>%
    addPolygons(data = ctry_poly,
                color = "green",
                group = "USA regions") %>%
    addCircleMarkers(data = animals, lng = ~SiteLongitude, lat = ~SiteLatitude,
                     weight = 2,
                     radius = 4,
                     group = "Animal clusters")

map_animals
# now, let's try the aggregation argument `clusterOptions`, which enables us to
# show numbers of animals
map_animals = leaflet() %>% 
    addProviderTiles(providers$Esri.NatGeoWorldMap,
                     group = "NatGeo") %>%
    addPolygons(data = ctry_poly, group = "USA regions") %>%
    addCircleMarkers(data = animals, lng = ~SiteLongitude, lat = ~SiteLatitude,
                     weight = 2,
                     radius = 4,
                     group = "Animal clusters",
                     clusterOptions = markerClusterOptions())
    
map_animals
# Finally, let's add our animal data to the map with event data in it
# ==============================================================================
map = leaflet() %>%
    addProviderTiles(providers$Esri.NatGeoWorldMap,
                     group = "NatGeo") %>%
    addPolygons(data = ctry_poly,
                color = "green",
                group = "USA regions") %>%
    addCircleMarkers(data = sites,
                     lng = ~SiteLongitude,
                     lat = ~SiteLatitude,
                     weight = 3,
                     radius = 4,
                     opacity = 0.7,
                     popup = ~site_info,
                     group = "Sites") %>%
    addCircleMarkers(data = animals, lng = ~SiteLongitude, lat = ~SiteLatitude,
                     weight = 2,
                     radius = 4,
                     group = "Animal clusters",
                     clusterOptions = markerClusterOptions())


map = map %>%
    addLayersControl(
    overlayGroups = c("USA regions", "Sites", "Animal clusters"),
    options = layersControlOptions(collapsed = FALSE))


map

Now, save your map

saveWidget(map, "map_sites_animal.html")