1
votes

I posted a similar question here: How do I create a Leaflet Proxy in observeEvent() for checkboxGroup in R Shiny . But I'm a little desperate for answers, so I thought I'd rephrase my question and post it again. I've scoured the internet for answers and can't seem to find what I'm looking for. Apologies for the double posting.

Here's my issue. I have a dataset here: https://github.com/mallen011/Leaflet_and_Shiny/blob/master/Shiny%20Leaflet%20Map/csv/RE.csv

It's recycling centers in Kentucky. It's set up so each recyclable material is a column, and each row i.e. recycling center is listed as yes/no as to whether each center actually recycles said material. Here's an example of what the data looks like, in case you can't access the csv. Top row is the header column. Sorry for the formatting:

  • Name___________________GL______AL_____PL
  • Bath Community Recycling___Yes_____No____Yes
  • Ted & Sons Scrap Yard______No______No____Yes

Now I have the csv visualized on a R shiny dashboard app like here using Leaflet: https://github.com/mallen011/Leaflet_and_Shiny/blob/master/Shiny%20Leaflet%20Map/re_map.png But I want to add a control in which users can filter through where they can recycle their goods, namely, I want to use checkboxGroupInput() in R shiny so users can check materials and have recycling centers populate the map. For example, if a person wants to know where to recycle their glass, they can check "glass" in the checkbox group, and all recycling centers that allow glass recycling pop up.

So in R Shiny, I've read my recycling data csv (RE.csv):

RE <- read.csv("C:/Users/username/Desktop/GIS/Shiny Leaflet Map/csv/RE.csv")

RE$y <- as.numeric(RE$y)
RE$x <- as.numeric(RE$x)

RE.SP <- SpatialPointsDataFrame(RE[,c(7,8)], RE[,-c(7,8)])

Here's my UI that puts the checkboxGroupInput() in the sidebar():

ui <- dashboardPage(
  skin = "blue",
  dashboardHeader(titleWidth = 400, title = "Controls"),
  dashboardSidebar(width = 400
                  #here's the checkboxgroup, it calls the columns for glass, aluminum and plastic from the RE.csv, all of which have binary values of yes/no
                  checkboxGroupInput(inputId = "RE_check", 
                                     label = h3("Recycleables"), 
                                      choices = list("Glass" = RE$GL, "Aluminum" = RE$AL, "Plastic" = RE$PL),
                                      selected = 0)
                   ),
  dashboardBody(
    fluidRow(box(width = 12, leafletOutput(outputId = "map"))),
    tags$style(type = "text/css", "#map {height: calc(100vh - 80px) !important;}"),
    leafletOutput("map")
  )
)

And now for the trouble I'm having: What do I put into my server so it observes each of these events? This is what I have for the event in which a user checks "glass", and I have no idea how wrong or how right it is. I just know it's not working. I'm trying to use "if" statements, so only values that equal "yes" populate the map. But currently, the map in the dashboard is blank no matter what I do, although the checkbox group input seems to work.

server <- function(session, input, output) {
 observeEvent({
    RE_click <- input$map_marker_click
    if (is.null(RE_click))
      return()

    if(input$RE$GL == "Yes"){
      leafletProxy("map") %>% 
        clearMarkers() %>% 
        addMarkers(data = RE_click,
                   lat = RE$y,
                   lng = RE$x)
      return("map")
    }
  })

Here's my output leaflet map too, in case that matters:

 output$map <- renderLeaflet({
    leaflet() %>% 
      setView(lng = -83.5, lat = 37.6, zoom = 8.5)  %>% 
      addProviderTiles("Esri.WorldImagery") %>% 
      addProviderTiles(providers$Stamen.Toner, group = "Toner") %>% 
      addPolygons(data = counties,
                  color = "green",
                  weight = 1,
                  fillOpacity = .1,
                  highlight = highlightOptions(
                    weight = 3,
                    color = "green",
                    fillOpacity = .3)) %>% 
      addMarkers(data = RE,
                 lng = ~x, lat = ~y, 
                 label = lapply(RE$popup, HTML),
                 group = "recycle",
                 clusterOptions = markerClusterOptions(showCoverageOnHover = FALSE)) %>% 
    addLayersControl(baseGroups = c("Esri.WorldImagery", "Toner"),
                     overlayGroups = c("recycle"),
                     options = layersControlOptions(collapsed = FALSE))
  })
}

I'm new to R Shiny if that's not obvious. I'd really appreciate any and all help. All my code is publicly available on my GitHub for download: https://github.com/mallen011/Leaflet_and_Shiny

Thanks and stay safe!

1
It might be worth using a reactive object in this situation. I took a look at the project, but there's a lot to get my head around. Create a new object filtered_data <- reactive({...])). Inside, define all of the conditions that the data should follow, and then use the reactive object in the render leaflet function, leaflet() %>% addMarkers(data = RE_filtered()).... Make sure you use the (). - dcruvolo
@dcruvolo Thanks, I'll give that a try! - Melissa Allen
This could work, but I think it would trigger unnecessary re-rendering of the map. I think the answer below would work best as everything is pre-rendered, and then you show and hide layers accordingly: rstudio.github.io/leaflet/showhide.html - dcruvolo
A few more ideas after looking at the leaflet docs. At the end of the renderLeaflet define the layers that are shown/hidden by default using hideGroup and showGroup. Create a separate observe block that evaluates the checkbox inputs: observe({ if(input$RE_check == "Glass") leafletProxy("map") %>% showGroup("glass") else { leafletProxy("map") %>% hideGroup("glass") } }). Make sure the layer IDs and input values match. - dcruvolo
@dcruvolo thanks, I've been figuring out how to make a reactive object for the checkbox group, but the hideGroup/showGroup is more to do with the layerControl than Shiny widgets, right? I already have a layerControl that users can check/uncheck layers, I just want more UI interactivity with having a reactive checkboxGroupInput. Your advice has really helped with using a reactive object for it, I feel like I almost have it working. Thanks a lot! - Melissa Allen

1 Answers

0
votes

Maybe this would work... You can add the different recycle types as layers, then add the checkboxes on the leaflet map instead of worrying about shiny integration. Obviously, you'd have to add the rest of your recycle types on here...

library(leaflet)
library(htmlTable)
RE <- read.csv("https://raw.githubusercontent.com/mallen011/Leaflet_and_Shiny/master/Shiny%20Leaflet%20Map/csv/RE.csv")
leaflet() %>% 
  setView(lng = -83.5, lat = 37.6, zoom = 8.5)  %>% 
  addProviderTiles("Esri.WorldImagery") %>% 
  addProviderTiles(providers$Stamen.Toner, group = "Toner") %>% 
  # addPolygons(data = counties,
  #             color = "green",
  #             weight = 1,
  #             fillOpacity = .1,
  #             highlight = highlightOptions(
  #               weight = 3,
  #               color = "green",
  #               fillOpacity = .3)) %>% 
  addMarkers(data = RE[RE$AL=="Yes", ],
             lng = ~x, lat = ~y, 
             #label = lapply(RE$popup, HTML),
             group = "AL",
             clusterOptions = markerClusterOptions(showCoverageOnHover = FALSE)) %>% 
  addMarkers(data = RE[RE$FE=="Yes", ],
             lng = ~x, lat = ~y, 
             #label = lapply(RE$popup, HTML),
             group = "FE",
             clusterOptions = markerClusterOptions(showCoverageOnHover = FALSE)) %>% 
  addMarkers(data = RE[RE$NONFE=="Yes", ],
             lng = ~x, lat = ~y, 
             #label = lapply(RE$popup, HTML),
             group = "NONFE",
             clusterOptions = markerClusterOptions(showCoverageOnHover = FALSE)) %>% 
  addLayersControl(baseGroups = c("Esri.WorldImagery", "Toner"),
                   overlayGroups = c("AL", "FE", "NONFE"),
                   options = layersControlOptions(collapsed = FALSE))