7
votes

I'm working on creating a Shiny/Leaflet app similar to this one that's done in tableau. It shows world-level views of poverty for different years, allowing the user to filter the map by variable, region, and year.

The problem is that the global country-level shapefile (from NaturalEarthData) renders quite slowly. I'm working on different ways to simplify those polygons to decrease load time, but in the meantime, I'm working on other potential solutions.

Ideally, I would use Shiny controls to toggle the different map layers and use leafletProxy to update the map. But because each layer change draws the entire map again, this is also quite slow.

When I include the different layers inside Leaflet, the layers are rendered much, much faster. (I assume that this is because the addLayersControl option in Leaflet only changes the fillColor of the polygons rather than redrawing the entire global shapefile, as is done with leafletProxy). But is there any way to access these layers outside of Leaflet?

To illustrate, here's some dummy code:

#load required libraries 
library(shiny)
library(leaflet)
library(raster)

#begin shiny app
shinyApp(

  ui <- fluidPage(
    leafletOutput("map", width = "100%", height = 600) 
  ), #END UI

  server <- function(input, output, session){

    #load shapefile
    rwa <- getData("GADM", country = "RWA", level = 0)

    #render map
    output$map <- renderLeaflet({
      leaflet() %>% 
        addTiles() %>% 
        addPolygons(data = rwa, 
                    fillColor = "blue", 
                    group = "blue") %>% 
        addPolygons(data = rwa, 
                    fillColor = "red", 
                    group = "red") %>% 
        addLayersControl(baseGroups = c("blue", "red"), 
                         options = layersControlOptions(collapsed = F))
    }) #END RENDER LEAFLET 
  } #END SERVER
) #END SHINY APP

Which has the following output: enter image description here

You can easily toggle between the blue and red layers within the leaflet map object. But let's say that I want a Shiny table to update with the attributes from the red polygon layer when I toggle the map layers from blue to red. I want to be able to pull this object outside of leaflet and utilize it in a Shiny observeEvent. Is this possible/how can I do this?

1
I've not seen a method that allows you to observe the 'layersControl' being clicked, but you can observe polygons being clicked, as in this answerSymbolixAU
maybe this stackoverflow.com/questions/28938642/… could also helpMLavoie
Maybe this helps: stackoverflow.com/a/41668048/3502164. Let me know if you need further specification for your challenge.Tonio Liebrand
@TonioLiebrand I was able to get your minimal example to work, but haven't had any luck integrating it into a larger app. In my actual code, there are several different inputs (including the Leaflet layer controls), and this seems to be the issue. I tried the console.log statement that you suggested in your other response to no avail. Any additional tips to troubleshoot?Lauren
Hi @Lauren, well I tried it out. Its possible to change the to toggle, but that wont change the color :D The color of the map is within <svg class="leaflet-zoom-animated" ..> so you would set the color there. My first attempt to access that with "document.getElementsByClassName("leaflet-zoom-animated")" failed, so I would look there, the problem with the multiple inputs I can show you later on.Tonio Liebrand

1 Answers

2
votes

You can define an observer for the {MAP_ID}_groups input in your Shiny server.

Example:

server <- function(input, output, session) {
    # ...

    output$my_map <- renderLeaflet({
        # ...
    })

    observe({
        selected_groups <- req(input$my_map_groups)
        # do whatever ... 
    })
}

This input gets updated when the user selects a group in the layers control.