Problem with dynamic map in Shiny app
I get the error
Error in .getReactiveEnvironment()$currentContext() :
Operation not allowed without an active reactive context. (You tried to do something that can only be done from inside a reactive expression or observer.)
when using mapview in a Shiny app where the map is based on reactive data. Here is an example:
library(shiny)
library(sf)
library(mapview)
ui <- fluidPage(
sidebarLayout(sidebarPanel(
selectInput( "county", "County Name",
choices = c("All", levels(franconia$NAME_ASCI)),
selected = "All"
)
),
mainPanel(mapviewOutput("mapPlot")))
)
server <- function(input, output) {
fran <- reactive({
f <- franconia
if (input$county != "All")
f <- franconia %>% filter(NAME_ASCI == input$county)
f
})
mapPlot <- reactive({ mapview(fran(), zcol = "NAME_ASCI") })
output$mapPlot <- renderMapview(mapPlot())
}
# Run the application
shinyApp(ui = ui, server = server)
My guess is that the problem is the mapview2leaflet(expr) call in renderMapview, because the same example works if converted to use leaflet instead of mapview.
One fix is to enclose the output$mapPlot in observe({ }). However according to this discussion that is not recommended.
Here is the (working) leaflet version:
library(shiny)
library(sf)
library(leaflet)
ui <- fluidPage(
sidebarLayout(sidebarPanel(
selectInput("county", "County Name",
choices = c("All", levels(franconia$NAME_ASCI)),
selected = "All"
)
),
mainPanel(leafletOutput("mapPlot")))
)
server <- function(input, output) {
fran <- reactive({
f <- franconia
if (input$county != "All")
f <- franconia %>% filter(NAME_ASCI == input$county)
f
})
mapPlot <- reactive({ addPolygons(leaflet(fran())) })
output$mapPlot <- renderLeaflet(mapPlot())
}
# Run the application
shinyApp(ui = ui, server = server)
From here: https://stackoverflow.com/questions/59585109/filtering-data-reactively-to-generate-maps/59585256
Replacing renderMapview with the below function makes this example work. I don't really understand what substitute is doing here so I don't know if there might be other implications to this change...
myRenderMapview = function (expr, env = parent.frame(), quoted = FALSE)
{
if (!quoted)
expr = substitute(mapview:::mapview2leaflet(expr))
htmlwidgets::shinyRenderWidget(expr, leafletOutput, env,
quoted = TRUE)
}
See my reply on stackoverflow: In shiny applications, use of renderLeaflet over the @map slot of the mapview object is preferable and should solve your issue (See https://github.com/r-spatial/mapview/issues/58).
ISTM that renderMapview should either be fixed or removed (or deprecated with a note to use renderLeaflet(map@map) instead.
Trying to use myRenderMapview() results in Error: addResourcePath called with invalid prefix; please see documentation.
The renderLeaflet() @map workaround works for me.
@kent37 thanks! the myRenderMapview() worked for me!
Thank you @kent37, the problem with rendering in shiny was exactly what you mentioned there. I was printing the map successfully but it was not rendered by shiny because it should be map@map not just map.
I had something like:
leaflet::renderLeaflet({mapview(SomeMap,legend=FALSE) })
when it is changed to
leaflet::renderLeaflet({mapview(SomeMap,legend=FALSE)@map }) it worked...
By the way, the legend false or true is just an additional option in the mapview.