luthe
luthe

Reputation: 23

Interactive Leaflet with shiny - clearMarkers() and set new ones

I want to create an interactive leaflet map with Shiny. The creation works fine, but despite changes at selectInput() and clicking "go!" the old markers are not deleted and no new markers are set. Can you please help me?

Operating System: Windows 10 64-Bit RStudio R Version: R version 4.0.0

geocodes <- data.frame("customer" = c("John", "Ahmet", "Zara"),
                       "longitude" = c(8.71, 8.59, 8.98),
                       "latitude" = c(51.2, 51.3, 51.1))
# UI
ui <- dashboardPage(
  dashboardHeader(title = "CustomerLocation Dashboard"),
  dashboardSidebar(
    
    selectInput("account", label = "Account",
                choices = c(unique(geocodes$customer)),
                multiple = TRUE),
    
    actionButton("go", "Go!")

  ),

  
  dashboardBody(
    tags$style(type = "text/css", "#map {height: calc(100vh - 80px) !important;}"),
    leafletOutput("mymap", height=1000)
  )
)
  

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

  reactiveDf <- reactive({
    if(is.null(input$account)){
      geocodes
    } else{
      geocodes[geocodes$customer %in% input$account,]
    }
  })
  
  
  output$mymap <- renderLeaflet({
    leaflet(geocodes) %>%
      addProviderTiles("OpenStreetMap",
                       group = "OpenStreetMap"
      ) %>%
      addAwesomeMarkers(
        lng = ~longitude,
        lat = ~latitude,
        icon = customIcon,
        clusterOptions = markerClusterOptions(),
        label = ~customer,
        popup = ~popup
      )
  })
  
  
  eventReactive(input$go,{
   leafletProxy("mymap", data = reactiveDf()) %>%
      clearShapes() %>%
      clearPopups() %>%
      clearMarkers() %>%
      addAwesomeMarkers(
        data = reactiveDf(),
        lng = ~longitude,
        lat = ~latitude,
        icon = customIcon,
        clusterOptions = markerClusterOptions(),
        label = ~customer,
        popup = ~popup
      )
  })

}

shinyApp(ui, server)

Upvotes: 2

Views: 839

Answers (1)

Michael Safarty
Michael Safarty

Reputation: 46

Three fixes that I've identified:

  1. The c(unique(geocodes$customer)) transforms this input to c(1,2,3). And when you later try subset the customer names "John", "Ahmet", and "Zara" by c(1,2,3) - this is incompatible and fails.
 selectInput("account", label = "Account",
                choices = c(unique(geocodes$customer)),
                multiple = TRUE),

Change to:

selectInput("account", label = "Account",
                choices = unique(geocodes$customer),
                multiple = TRUE),
  1. I unfortunately don't know why the clearMarkers() in leafletProxy() won't clear the markers like you expect, but changing the original map from rendering with geocodes to reactiveDf() (which still returns the geocodes data frame if input$account is null) appears to solve that issue.
output$mymap <- renderLeaflet({
    leaflet(geocodes) %>%
      addProviderTiles("OpenStreetMap",
                       group = "OpenStreetMap"
      ) %>%
      addAwesomeMarkers(
        lng = ~longitude,
        lat = ~latitude,
        icon = customIcon,
        clusterOptions = markerClusterOptions(),
        label = ~customer,
        popup = ~popup
      )
  })

Change to:

output$mymap <- renderLeaflet({
    leaflet(reactiveDf()) %>%
      addProviderTiles("OpenStreetMap",
                       group = "OpenStreetMap"
      ) %>%
      addAwesomeMarkers(
        lng = ~longitude,
        lat = ~latitude,
        icon = customIcon,
        clusterOptions = markerClusterOptions(),
        label = ~customer,
        popup = ~popup
      )
  })

If you are willing to change the architecture a little bit:

  1. Use observeEvent to redefine geocodes according to input$account and to trigger leafletProxy() along with it. I suppose we are both missing some step with regards to creating the reactive data frame for the leafletProxy, perhaps we can't completely change the data source going from the initial renderLeaflet to the leafletProxy?
observeEvent(input$go, {
    if(is.null(input$account)){
      geocodes = geocodes
    } else{
     geocodes = geocodes[geocodes$customer %in% input$account,]
    }
 leafletProxy("mymap") %>%
    clearShapes() %>%
    clearPopups() %>%
    clearMarkers() %>%
    addMarkers(
      data = geocodes,
      lng = ~longitude,
      lat = ~latitude,
      label = ~customer,
    )
  }
)

Edit: Another option would be to define a group for each marker layer, and call showGroup() and hideGroup() to manipulate which markers are visually shown.

I hope this helps

Upvotes: 3

Related Questions