Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remove specific leaflet Markers in R shiny.

I have a layer of CircleMarkers and I am trying to remove only the markers that have a certain layerId. The id's for these circle markers are in a dataframe.

Below is a simple example: Suppose I have a dataframe with 3 rows with id's 1, 2 and 3. I tried to make a checkboxInput with the options to delete id's 1 and 2 or 3.

Below the inputs will trigger an ObserveEvent that use the removeMarker function. However, nothing happens. I have tried a million ways to enter the id's into the removeMarker and I have also tried several of the other ways to deletion. Either nothing happens or all disappear. I need a way to delete specific markers.

 ui <- shinyUI(fluidPage(
sidebarLayout(
    sidebarPanel(
        checkboxInput("delete1", "Delete ID=1 and 2",value=FALSE),
    checkboxInput("delete3", "Delete ID=3",value=FALSE)
    ),
    mainPanel(
        leafletOutput("map")
    )
)
))

df <- data.frame(id=c(1,2,3),lng = rnorm(3, -106.1039361, 0.5) ,
              lat = rnorm(3, 50.543981, 0.5))

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

output$map <- renderLeaflet(
    leaflet() %>% 
addTiles() %>% addCircleMarkers(layerId=df$id,df$lng,df$lat, group='marker', radius=2, fill = TRUE,color='red') 


    )

observeEvent(input$delete1, {
    proxy <- leafletProxy('map')
    if (input$delete1){ proxy %>% removeMarker(df[1:2,1])
 }
 })

observeEvent(input$delete3, {
    proxy <- leafletProxy('map')
    if (input$delete3){ proxy %>% removeMarker(3)}
   })
})

 shinyApp(ui, server)
like image 639
DS501 Avatar asked Oct 29 '22 08:10

DS501


2 Answers

For some reason this works if the layerId in the addCirleMarkers and in the removeMarker are characters, you could try, for the server part:

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

  output$map <- renderLeaflet(
    leaflet() %>% 
      addTiles() %>% addCircleMarkers(layerId=as.character(df$id),df$lng,df$lat, group='marker', radius=2, fill = TRUE,color='red') 


  )

  observeEvent(input$delete1, {
    proxy <- leafletProxy('map')
    if (input$delete1){ proxy %>% removeMarker(c("1","2"))
    }
  })

  observeEvent(input$delete3, {
    proxy <- leafletProxy('map')
    if (input$delete3){ proxy %>% removeMarker("3")}
  })

})
like image 107
NicE Avatar answered Nov 15 '22 05:11

NicE


I think grouping the IDs is still the way to go. That grouping variable can then be added to your data frame and you can use that to toggle showing/hiding the points as I illustrate below. It's really not any different than what you were trying originally because you still had to specifically identify which IDs you wanted to remove. You still have to do that, but now you have to put them in defined groups.

require(shiny)
require(leaflet)
require(dplyr)

ui <- shinyUI(fluidPage(
  sidebarLayout(
    sidebarPanel(
      #Set value = TRUE so points are shown by default
      checkboxInput("delete1", "Toggle ID 1 and 2", value = TRUE),
      checkboxInput("delete3", "Toggle ID 3", value = TRUE)
    ),
    mainPanel(
      leafletOutput("map")
    )
  )
))


df <- data.frame(
        id = c(1,2,3),
        #Add grouping variable
        group = c("one", "one", "two"),
        lng = rnorm(3, -106.1039361, 0.5) ,
        lat = rnorm(3, 50.543981, 0.5)
)


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

  output$map <- renderLeaflet(
    leaflet() %>% 
    addTiles() %>%

    #Add markers with group
    addCircleMarkers(group = df$group, df$lng, df$lat, radius=2, fill = TRUE, color = 'red') 
  )

  observeEvent(input$delete1, {
    proxy <- leafletProxy('map')

    #Always clear the group first on the observed event 
    proxy %>% clearGroup(group = "one")

    #If checked
    if (input$delete1){

      #Filter for the specific group
      df <- filter(df, group == "one")

      #Add the specific group's markers
      proxy %>% addCircleMarkers(group = df$group, df$lng, df$lat, radius=2, fill = TRUE, color = 'red')
    }
  })

  #Repeat for the other groups
  observeEvent(input$delete3, {
    proxy <- leafletProxy('map')
    proxy %>% clearGroup(group = "two")
    if (input$delete3){
      df <- filter(df, group == "two")
      proxy %>% addCircleMarkers(group = df$group, df$lng, df$lat, radius=2, fill = TRUE, color = 'red')
    }
  })
})

shinyApp(ui, server)

Another idea that you could use is instead of a checkboxInput is a selectInput where you can select multiples at one. That will save having to observeEvents for each group. That's shown below. I set it up so it defaults to all points being shown, and if you select a group it removes it from the plot.

require(shiny)
require(leaflet)
require(dplyr)

df <- data.frame(
        id = c(1,2,3),
        #Add grouping variable
        group = c("one", "one", "two"),
        lng = rnorm(3, -106.1039361, 0.5) ,
        lat = rnorm(3, 50.543981, 0.5)
)

ui <- shinyUI(fluidPage(
  sidebarLayout(
    sidebarPanel(
      #Set value = TRUE so points are shown by default
      selectInput("toggle", "Toggle Groups", choices = unique(df$group), multiple = TRUE)
    ),
    mainPanel(
      leafletOutput("map")
    )
  )
))

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

  output$map <- renderLeaflet(
    leaflet() %>% 
    addTiles() %>%
    addCircleMarkers(df$lng, df$lat, radius=2, fill = TRUE, color = 'red') 
  )

  observe({

    proxy <- leafletProxy('map')

    if(is.null(input$toggle)){
      proxy %>% clearMarkers() %>%
       addCircleMarkers(df$lng, df$lat, radius=2, fill = TRUE, color = 'red') 
    } else {

      #Always clear the shapes on the observed event 
      proxy %>% clearMarkers()

      #Filter for the specific group
      df <- filter(df, !(group %in% input$toggle))

      #Add the specific group's markers
      proxy %>% addCircleMarkers(group = df$group, df$lng, df$lat, radius=2, fill = TRUE, color = 'red')
    }
  })

})

shinyApp(ui, server)
like image 42
Jake Avatar answered Nov 15 '22 07:11

Jake