R Shiny leaflet: using observers

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="100%", 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.

This entry was posted by Matt Leonawicz.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 521 other followers

%d bloggers like this: