Solved - Error when using mapshot with Shiny Leaflet

leaflet

#1

I'm trying to save an image of my Leaflet map in my Shiny app. I'm using the mapshot function from the mapview package The map is constantly updated with markers etc via leafletProxy("map") %>% <add markers etc>

I'm using a function:

observeEvent(input$exportMap, {
    mapshot("map", file=paste0(getwd(), '/exported_map.png'))
  })

However I get the following error:

Warning: Error in : $ operator is invalid for atomic vectors
Stack trace (innermost first):
    70: resolveSizing
    69: toHTML
    68: <Anonymous>
    67: do.call
    66: mapshot
    65: observeEventHandler [testFrontend/server.R#71]
     1: runApp
ERROR: [on_request_read] connection reset by peer

I also tried:

observeEvent(input$exportMap, {
    m <- leafletProxy("map")
    mapshot(m, file=paste0(getwd(), '/exported_map.png'))
  })

But then I get:

Warning: Error in system.file: 'package' must be of length 1
Stack trace (innermost first):
    75: system.file
    74: inherits
    73: yaml::yaml.load_file
    72: getDependency
    71: widget_dependencies
    70: htmltools::attachDependencies
    69: toHTML
    68: <Anonymous>
    67: do.call
    66: mapshot
    65: observeEventHandler [testFrontend/server.R#72]
     1: runApp
ERROR: [on_request_read] connection reset by peer

Any suggestions?

Thanks.


#2

I've added a reprex here:

library(leaflet)
library(mapview)
library(shiny)

ui <- fluidPage(
  
   titlePanel("Mapshot error example"),

   sidebarLayout(
      sidebarPanel(
         actionButton("addMarkers", "Add markers"),
         actionButton("saveMapUsingID", "Screenshot map with ID"),
         actionButton("saveMapUsingProxy", "Screenshot map with Proxy")
      ),
      mainPanel(
         leafletOutput("map")
      )
   )
)

server <- function(input, output) {
  
  output$map <- renderLeaflet({
    leaflet() %>%
      addProviderTiles(providers$OpenStreetMap)
  })
  
  observeEvent(input$addMarkers, {
     # Somewhere in London
     randPoint1 <- runif(1, min=-0.34, max=0.16)
     randPoint2 <- runif(1, min=51.34, max=51.67)
     leafletProxy("map") %>%
       addMarkers(lng=randPoint1, lat=randPoint2) %>%
       setView(lng=randPoint1, lat=randPoint2, zoom=10)
   })
  
  observeEvent(input$saveMapUsingID, {
    mapshot("map", file=paste0(getwd(), '/exported_map.png'))
  })
  
  observeEvent(input$saveMapUsingProxy, {
    m <- leafletProxy("map")
    mapshot(m, file=paste0(getwd(), '/exported_map.png'))
  })
  
}

shinyApp(ui = ui, server = server)

#3

Thanks for posting the reprex!

The issue appears to be with the fact the "map" is not actually a leaflet object, but rather a shiny output.

If you create the leaflet object in its own reactive expression and then pass that into the renderLeaflet and first mapshot observer then that first save button works.

For the proxy option, I am not able to get it to work as I am getting the following error:

Warning: Error in system.file: 'package' must be of length 1

This seems to be an issue with saveWidget which is what mapshot calls. I am also not entirely sure what you are accomplishing by saving it with the proxy option that is not already being captured by the first save option. But I may be missing something.

Anyway, Here is the app with a working save button for the first option:

library(leaflet)
library(mapview)
library(shiny)

ui <- fluidPage(
  
  titlePanel("Mapshot error example"),
  
  sidebarLayout(
    sidebarPanel(
      actionButton("addMarkers", "Add markers"),
      actionButton("saveMapUsingID", "Screenshot map with ID")
      # actionButton("saveMapUsingProxy", "Screenshot map with Proxy")
    ),
    mainPanel(
      leafletOutput("map")
    )
  )
)

server <- function(input, output, session) {
  
  map_reactive <- reactive({
    leaflet() %>%
      addProviderTiles(providers$OpenStreetMap)
  })
  
  output$map <- renderLeaflet({
    map_reactive()
  })
  
  observeEvent(input$addMarkers, {
    # Somewhere in London
    randPoint1 <- runif(1, min=-0.34, max=0.16)
    randPoint2 <- runif(1, min=51.34, max=51.67)
    leafletProxy("map") %>%
      addMarkers(lng=randPoint1, lat=randPoint2) %>%
      setView(lng=randPoint1, lat=randPoint2, zoom=10)
  })
  
  observeEvent(input$saveMapUsingID, {
    mapshot(map_reactive(), file=paste0(getwd(), '/exported_map.png'))
  })
  

  
}

shinyApp(ui = ui, server = server)

As a final note, please indicate when you have cross-posted your question (here is your question also on SO). This will prevent people from spending time trying to answer your question if you have already gotten an answer. Please see the FAQ about cross-posting questions:


#4

Thanks for the reply, apologies for the cross posting!

I've given your way a go but I still don't get the markers that are added to the map on the exported map. That's the main issue, I'd like the user to be able to add their data as they go along and then export the map.


#5

I've uploaded a gif of what I'm trying to do, notice the output doesn't contain the markers, thanks again :smile:

Gif of process


#6

Marking this as solved as @tbradley helped me get the mapshot actually generating a file. I've since found https://github.com/rowanwins/leaflet-easyPrint which seems to do a better job (For my needs) at producing an export.

Many thanks @tbradley for the help!