[GIS] Removing specific Circle Markers in Leaflet Shiny

leafletmarkersrshiny

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. In reality I have millions of id's whose subset to visualize depends on a different dataset which can change over time. So I need a dynamic way to delete specific layerId's.

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. Note that this in no way reflects my real life example: I have millions of points and deletion of points is not through a direct checkbox input, but based on a different dataset that can change over time.

 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)

Best Answer

The id column of the data.frame must be of class character or factor. I modified the id vector when creating the data.frame. Try the working code below. You will be able to add and remove markers when check/uncheck the checkboxes.

# Load libraries
library("leaflet")

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

# ID must be a character
df <- data.frame(
  id = as.character(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(layerId = df$id[1:2])
    }

    if (!input$delete1) {
      proxy %>% addCircleMarkers(
        layerId = df$id[1:2],
        df$lng[1:2],
        df$lat[1:2],
        group = 'marker',
        radius = 2,
        fill = TRUE,
        color = 'red'
      )
    }

  })

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

    if (input$delete3) {
      proxy %>% removeMarker(layerId = df$id[3])
    }

    if (!input$delete3) {
      proxy %>% addCircleMarkers(
        layerId = df$id[3],
        df$lng[3],
        df$lat[3],
        group = 'marker',
        radius = 2,
        fill = TRUE,
        color = 'red'
      )
    }

  })
})

shinyApp(ui, server)

Edit1:

Based on Cluster markers

# Load libraries
library("leaflet")

ui <- shinyUI(fluidPage(sidebarLayout(
  sidebarPanel(
    hr(),
    h4("Remove points"),
    checkboxGroupInput(
      inputId = "removeFromMap",
      label = "",
      choices = c(1:6)
    ),
    p("Cluster1 = 1,2,3"),
    p("Cluster2 = 4,5,6"),
    hr(),
    p("Checked = removed"),
    p("Unchecked = present")
  ),
  mainPanel(leafletOutput("map"))
)))

# ID must be a character
df <- data.frame(
  id = as.character(1:6),
  lng = rnorm(6, -106.1039361, 0.5),
  lat = rnorm(6, 50.543981, 0.5)
)

server <- shinyServer(function(input, output, session) {
  output$map <- renderLeaflet(
    leaflet() %>%
      setView(-106.1039361, 50.543981, zoom = 5) %>%
      addTiles() %>%

      addCircleMarkers(
        layerId = df$id[1:3],
        df$lng[1:3],
        df$lat[1:3],
        group = 'marker',
        radius = 3,
        fill = TRUE,
        color = '#EF2929',
        clusterId = "Cluster1",
        clusterOptions = markerClusterOptions()
      ) %>%

      addCircleMarkers(
        layerId = df$id[4:6],
        df$lng[4:6],
        df$lat[4:6],
        group = 'marker',
        radius = 3,
        fill = TRUE,
        color = '#729FCF',
        clusterId = "Cluster2",
        clusterOptions = markerClusterOptions()
      )
  )

# Global ID vector
ids <- df$id

# Remove points
  observeEvent(input$removeFromMap, {
    checkedPoints <- input$removeFromMap
    checkedPoints <- checkedPoints[which(checkedPoints %in% ids)]

proxy <- leafletProxy('map')

if (length(checkedPoints) != 0) {
  if (any(checkedPoints %in% as.character(1:3))) {
    pointsC1 <- checkedPoints[which(checkedPoints %in% ids)]
    proxy %>% removeMarkerFromCluster(layerId = pointsC1, clusterId = "Cluster1")
    ids <<- ids[-which(ids == pointsC1)]

  }

  if (any(checkedPoints %in% as.character(4:6))) {
    pointsC2 <- checkedPoints[which(checkedPoints %in% ids)]
    proxy %>% removeMarkerFromCluster(layerId = pointsC2, clusterId = "Cluster2")
    ids <<- ids[-which(ids == pointsC2)]

  }
}

  })

})

shinyApp(ui, server)

map

Related Question