Search code examples
rr-leaflet

Nested Markers in R Leaflet


I have a dataframe containing nested ecological survey data. A conceptual description of the data - at the 'top' level is a survey site; within sites are n traps; within traps there can be n animals caught.

I would like to display a Leaflet map showing markers which correspond to the data's top level (i.e. survey sites). When you click on a survey site, it should fan out and show markers of each trap within a survey site. When clicking a trap, it should then display a list of the animals caught within the trap (a regular Leaflet pop up would be fine at this point).

I've no idea whether this is even possible within R Leaflet, despite many searches of Google and/or SO. I did find one potential Javascript solution but I don't know whether it would translate exactly to resolve the issue I'm facing. At the very least, however, the act of hovering on a marker and it displaying nested markers is the functionality that I'm after when viewing traps within sites.

I have included below an example nested dataframe of some dummy data, plus a barebones Leaflet reprex. In the dummy data, and for simplicity, I have assigned each site the same lat/lon. When clicking on any site (001, 002, 003), the traps will fan out from that site. At Site 001 there is only 1 unique trap (ID = 001-001) but Site 2 has two unique traps (002-001 and 002-002). Site 003 has only one trap.

library(leaflet)
library(tidyverse)

x<-as_tibble(data.frame(site = c("001", "001", "001", "002", "002", "002", "003"), 
              trap = c("001-001", "001-001", "001-001", "002-001", "002-001", "002-002", "003-001"),
              animal = c("001-001-001", "001-001-002", "001-001-003", "002-001-001", "002-001-002", "002-002-003", "003-001-001"),
              lat = c(51.1, 51.1, 51.1, 52.4, 52.4, 52.4, 51.5),
              lon = c(-1.1, -1.1, -1.1, -1.7, -1.7, -1.7, -1.2)))


leaflet() %>%
  addProviderTiles(providers$OpenStreetMap, options = providerTileOptions(noWrap = TRUE), group = "Open Street Map") %>%
  setView(lng = -1.900796, lat = 52.479380, zoom = 7) %>% 
  addLayersControl(baseGroups = c("Open Street Map")))

Hoping a solution is possible - any help would be very much appreciated.


Solution

  • There is an option to create clusters (clusterOptions = TRUE) within the addCircleMarkers function.

    I am not sure if the code below generates what you want, but it might be able to help you to the next step.

    leaflet() %>%
      addProviderTiles(providers$OpenStreetMap, options = providerTileOptions(noWrap = TRUE), group = "Open Street Map") %>%
      setView(lng = -1.900796, lat = 52.479380, zoom = 7) %>% 
      addLayersControl(baseGroups = c("Open Street Map")) %>% 
      addCircleMarkers(data = x, lng = ~lon, lat = ~lat, clusterOptions = TRUE, 
                       popup = paste("<b>Site:</b>", x$site, "<br>",
                                     "<b>lon:</b>", x$lon, "<br>",
                                     "<b>lat:</b>", x$lat, "<br>",
                                     "<b>trap:</b>", x$trap, "<br>",
                                     "<b>animal:</b>", x$animal))
    

    I added the popup to keep track of which marker was which, but you can do something with colors or shapes if that is more visually attractive.

    An additional note: As you can see I have created the popup with some html script for the formatting (<b></b>) and the linebreaks (<br>). You can use other html tricks in these popups if you want, it usually works and it's highly customizable. However, the leafpop package might be a faster way to add tables, images and graphs in popups.