Search code examples
rshinyr-leaflet

How to correctly clearShapes in Leaflet in a Shiny app


Note that this question has been posted at the R Shiny Google Group:

Following the Leaflet for R/ Shiny Integration documentation, I'm getting unwanted/ unexpected behavior with the leafletProxy function.

In the app below, I'd expect the circle markers to appear/ disappear as the input$choices changes.

The reactive df 'filteredData' seems to be working correctly.

Am I incorrectly using leafletProxy() or clearShapes()?

library(shiny)
library(dplyr)
library(leaflet)


my_df <- data.frame(lat = 34.72 + rnorm(1000, sd = .18), 
                    lng = -92.5 + rnorm(1000, sd = .33), 
                    category = c(rep("A", 300), rep("B", 300), rep("C", 400)))

ui <- bootstrapPage(
  tags$style(type = "text/css", "html, body {width:100%;height:100%}"),
  leafletOutput("map", height = '100%', width = '100%'),
  absolutePanel(top = 10, right = 10, 
                checkboxGroupInput("choices", "Choices", choices =     list("A","B","C"), selected = c("A","B","C")),
                verbatimTextOutput("my_rows")


  )
)


server <- function(input, output) {

  filteredData <- reactive( my_df %>% filter(category %in% input$choices) )

    output$map <- renderLeaflet({ leaflet() %>% addTiles() %>% setView(lat =     34.72, lng = -92.5, zoom = 9) })

    observe({

      leafletProxy("map", data = filteredData()) %>% clearShapes() %>% addCircleMarkers(radius = 6, weight = 1, fillColor = "red", fillOpacity = 0.3)

    })

    output$my_rows <- renderPrint({ filteredData() %>% nrow() })
}

shinyApp(ui = ui, server = server)

Solution

  • Your first issue is solved by using clearMarkers() rather than clearShapes().

    As to the other issue you pointed out, leaflet struggles with empty (and NA) data. When you deselect all the values, your data.frame obviously becomes empty. A simple check for this to stop leaflet trying to plot it will solve this issue.

    Here I'm using an if - else do do the check.

    library(shiny)
    library(dplyr)
    library(leaflet)
    
    my_df <- data.frame(lat = 34.72 + rnorm(1000, sd = .18), 
                        lng = -92.5 + rnorm(1000, sd = .33), 
                        category = c(rep("A", 300), rep("B", 300), rep("C", 400)))
    
    ui <- bootstrapPage(
        tags$style(type = "text/css", "html, body {width:100%;height:100%}"),
        leafletOutput("map", height = '100%', width = '100%'),
        absolutePanel(top = 10, right = 10, 
                     checkboxGroupInput("choices", "Choices"
                                         , choices = list("A","B","C")
                                         , selected = c("A","B","C")),
                     verbatimTextOutput("my_rows")
        )
    )
    
    server <- function(input, output) {
    
        filteredData <- reactive({ 
            my_df %>% filter(category %in% input$choices) 
            })
    
        output$map <- renderLeaflet({ 
            leaflet() %>% 
                addTiles() %>% 
                setView(lat = 34.72, lng = -92.5, zoom = 9) 
            })
    
        observe({
    
            df <- filteredData()
    
            ## check for empty dataframe
            if(nrow(df) == 0){
                leafletProxy("map", data = df) %>% 
                clearMarkers()
            }else{
                leafletProxy("map", data = df) %>% 
                    clearMarkers() %>% 
                    addCircleMarkers(radius = 6, weight = 1
                                     , fillColor = "red", fillOpacity = 0.3)
            }
    
        })
    
        output$my_rows <- renderPrint({ 
            filteredData() %>% 
                nrow() 
            })
    }
    
    shinyApp(ui = ui, server = server)