[GIS] Changing the style of a polygon with a click event in a Shiny/Leaflet app

leafletrshiny

I'm attempting to create my first Shiny app using Leaflet. I'm currently trying to figure out how observers work together to update the map when something is clicked. Here is the example that I've been working from. In this example (code included in link), each marker changes styles and becomes yellow when clicked on, shown below:

enter image description here

Similarly, in my app, I want my polygons to change styles when they are clicked. While the example is very useful, I'm having problems translating the code from marker clicks to shape clicks.

Here is some example code with my shapefiles available for download here.

library(shiny)
library(rgdal)
library(leaflet)

ctry <- readOGR("D:/", layer = "ctry", stringsAsFactors = F)


shinyApp(

  ui = fluidPage(leafletOutput("map")),

  server = function(input, output, session) {

    output$map <- renderLeaflet({
      leaflet(ctry) %>% 
        addTiles() %>% 
        addPolygons(fillColor = "gray", 
                    fillOpacity = 1, 
                    weight = 2, 
                    stroke = T, 
                    color = "blue", 
                    opacity = 1)
    })


    observeEvent(input$map_shape_click, {
      click <- input$map_shape_click
      proxy <- leafletProxy("map")
      if(click$id == "Selected"){
        proxy %>% removeShape(layerId = "Selected")
      } else {
        proxy %>% addPolygons(fillColor = "black", layerId = "Selected")
      }
    })


  })

This code pretty closely follows the linked example with an attempt to work with shapes instead of markers. When I run the code, however, I get the following error:

Warning: Error in if: argument is of length zero Stack trace
(innermost first):
68: observeEventHandler [#22]
4:
3: do.call
2: print.shiny.appobj
1: ERROR: [on_request_read] connection reset by peer

I'm not sure where to go from here. Again, I want to change the style of my polygons whenever they are clicked (in the example, I made the fill black). What am I doing wrong?


I've continued to play around with my code a bit more and I think I have narrowed the problem down to the if(click$id == "Selected")... statement. It was my understanding that the click event is what triggered click$id to be populated by the string "Selected." However, when I print click$id from the example markers, I get the location name. I am really unsure of how this "Selected" id works.

Best Answer

I'm not sure that this is the solution, but I found a solution that works for my purpose! It appears that the problem was with my click event. When I clicked on a polygon, the result was still only a point rather than a polygon. I subset my ctry object by the click point and set that object as my data in the final addPolygons() function. I also added some groups and layerIds.

library(shiny)
library(rgdal)
library(leaflet)

ctry <- readOGR("D:/", layer = "ctry")
proj4string(ctry) <- CRS("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs")

shinyApp(

  ui = fluidPage(leafletOutput("map")),

  server = function(input, output, session) {

    output$map <- renderLeaflet({
      leaflet() %>% 
        addTiles() %>% 
        addPolygons(data = ctry, 
                    fillColor = "gray", 
                    fillOpacity = 1, 
                    weight = 2, 
                    stroke = T, 
                    color = "blue", 
                    opacity = 1,
                    group = "Countries", 
                    layerId = ~admin)
    })

    observeEvent(input$map_shape_click, {
      click <- input$map_shape_click

      if(is.null(click))
        return()   

      #pulls lat and lon from shiny click event
      lat <- click$lat
      lon <- click$lng

      #puts lat and lon for click point into its own data frame
      coords <- as.data.frame(cbind(lon, lat))

      #converts click point coordinate data frame into SP object, sets CRS
      point <- SpatialPoints(coords)
      proj4string(point) <- CRS("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs")

      #retrieves country in which the click point resides, set CRS for country
      selected <- ctry[point,]
      proj4string(selected) <- CRS("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs")

      proxy <- leafletProxy("map")
      if(click$id == "Selected"){
        proxy %>% removeShape(layerId = "Selected")
      } else {
        proxy %>% addPolygons(data = selected, 
                              fillColor = "black",
                              fillOpacity = 1, 
                              color = "red",
                              weight = 3, 
                              stroke = T,
                              layerId = "Selected")
      } 
    })
  })