R Shiny leaflet: using observers

[This article was first published on rbloggers – SNAP Tech, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Using leaflet in R is fairly simple and there are plenty of online resources and examples available already. See the RStudio tutorial to get started if you haven’t already. This post presents a series of examples which build upon each other.

ex_leaflet

The code displays both point data and raster data on leaflet maps with Shiny app integration. The focus here is to show the utility of event observation on the server side for integrating the behavior of browser elements, namely, the leaflet map.

In the course of these examples, I’ll also use a modal from the shinyBS package and the maps will be full size in the browser window with UI widgets laid on top using absolute panels. The full post contains interactive embedded Shiny widgets. See the full post here. It includes complete source code for these and other related apps using leaflet.

The app does not do much in this version, but it provides a clear view of how to use observers in Shiny apps to ensure that various inputs and outputs remain mutually well behaved. Here I use observeEvent three distinct times to tie together the reactive behavior of instances of selectInput and leafletOutput. The entire ui.R at this point is:

ui <- bootstrapPage(
  tags$style(type="text/css", "html, body {width:100%;height:100%}"),
  leafletOutput("Map", width="450", height="100%"),
  absolutePanel(top=10, right=10,
    selectInput("location", "Community", c("", locs$loc), selected=""),
    conditionalPanel("input.location !== null && input.location !== ''",
      actionButton("button_plot_and_table", "View Plot/Table", class="btn-block"))
  )
)

In server.R note the three observers. They constitute the entire code block except for the initial, relatively simple call to renderLeaflet. Comments mark the role performed by each call to observeEvent, which:

  • Update the leafletOutput map when clicked
  • Update the selectInput when the map is clicked
  • Update the leafletOutput when the selectInput changes
server <- function(input, output, session) {
  acm_defaults <- function(map, x, y) addCircleMarkers(map, x, y, radius=6, color="black", fillColor="orange", fillOpacity=1, opacity=1, weight=2, stroke=TRUE, layerId="Selected")

  output$Map <- renderLeaflet({
    leaflet() %>% setView(lon, lat, 4) %>% addTiles() %>%
      addCircleMarkers(data=locs, radius=6, color="black", stroke=FALSE, fillOpacity=0.5, group="locations", layerId = ~loc)
  })

  observeEvent(input$Map_marker_click, { # update the map markers and view on map clicks
    p <- input$Map_marker_click
    proxy <- leafletProxy("Map")
    if(p$id=="Selected"){
      proxy %>% removeMarker(layerId="Selected")
    } else {
      proxy %>% setView(lng=p$lng, lat=p$lat, input$Map_zoom) %>% acm_defaults(p$lng, p$lat)
    }
  })

  observeEvent(input$Map_marker_click, { # update the location selectInput on map clicks
    p <- input$Map_marker_click
    if(!is.null(p$id)){
      if(is.null(input$location) || input$location!=p$id) updateSelectInput(session, "location", selected=p$id)
    }
  })

  observeEvent(input$location, { # update the map markers and view on location selectInput changes
    p <- input$Map_marker_click
    p2 <- subset(locs, loc==input$location)
    proxy <- leafletProxy("Map")
    if(nrow(p2)==0){
      proxy %>% removeMarker(layerId="Selected")
    } else if(length(p$id) && input$location!=p$id){
      proxy %>% setView(lng=p2$lon, lat=p2$lat, input$Map_zoom) %>% acm_defaults(p2$lon, p2$lat)
    } else if(!length(p$id)){
      proxy %>% setView(lng=p2$lon, lat=p2$lat, input$Map_zoom) %>% acm_defaults(p2$lon, p2$lat)
    }
  })

}

shinyApp(ui, server)

Care must be taken to ensure each observer does not update when it shouldn’t. One can easily trigger another back and forth in this context. Fortunately it is not too difficult to make the three observeEvent calls work well together. See the full post to use the app and continue with the interactive examples.

To leave a comment for the author, please follow the link and comment on their blog: rbloggers – SNAP Tech.

R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Never miss an update!
Subscribe to R-bloggers to receive
e-mails with the latest R posts.
(You will not see this message again.)

Click here to close (This popup will not appear again)