17

I have created a leaflet map in a Shiny application. Now I need a download button, so that the user can download the currently shown map including all markers, polygons etc. as a pdf file.

I have found this solution how to save a leaflet map in R: How to save Leaflet in R map as png or jpg file?

But how does it work in Shiny? I kept the example code simple, but think of it, as if there were a lot of changes to the map via leafletProxy() before the user wants to save the map as a pdf.

This is my try, but it's not working.

server.R

library(shiny)
library(leaflet)
library(devtools)
install_github("wch/webshot") # first install phantomjs.exe in your directory

library(htmlwidgets)
library(webshot)

server <- function(input, output){

  output$map <- renderLeaflet({
    leaflet() %>% addTiles()
  })

 observe({
    if(input$returnpdf == TRUE){
      m <- leafletProxy("map")
      saveWidget(m, "temp.html", selfcontained = FALSE)
      webshot("temp.html", file = "plot.pdf", cliprect = "viewport")
    }
  })

  output$pdflink <- downloadHandler(
    filename <- "map.pdf",
    content <- function(file) {
      file.copy("plot.pdf", file)
    }
  )
}

ui.R

ui <- fluidPage(
     sidebarPanel(
     checkboxInput('returnpdf', 'output pdf?', FALSE), 
     conditionalPanel(
       condition = "input.returnpdf == true",
       downloadLink('pdflink')
      ) 
     ), 
     mainPanel(leafletOutput("map"))
)
Community
  • 1
  • 1
needRhelp
  • 2,948
  • 2
  • 24
  • 48

1 Answers1

10

I have updated my previous answer to make it more clear and illustrate how to use mapshot from package mapview. Moreover, following Jake's question below, I noticed that it might be necessary to specify a link to a tile (within addTiles), or the map might be downloaded with a grey background.

Server

server = function(input, output){

    mymap <- reactive({
      # here I have specified a tile from openstreetmap
      leaflet() %>% addTiles('http://{s}.tile.openstreetmap.de/tiles/osmde/{z}/{x}/{y}.png')
    })

    output$map <- renderLeaflet({
      mymap()
    })

    # function with all the features that we want to add to the map
    myfun <- function(map){
      addCircles(map,12.5,42,radius=500) %>% addMarkers(12,42,popup="Rome")
    }

    observe({
      leafletProxy("map") %>% myfun()
    })

    # map that will be downloaded
    mapdown <- reactive({
      # we need to specify coordinates (and zoom level) that we are currently viewing
      bounds <- input$map_bounds
      latRng <- range(bounds$north, bounds$south)
      lngRng <- range(bounds$east, bounds$west)
      mymap() %>% myfun() %>% setView(lng = (lngRng[1]+lngRng[2])/2, lat = (latRng[1]+latRng[2])/2, zoom = input$map_zoom)
    })

    output$map_down <- downloadHandler(
      filename = 'mymap.pdf',

      content = function(file) {
        # temporarily switch to the temp dir, in case you do not have write
        # permission to the current working directory
        owd <- setwd(tempdir())
        on.exit(setwd(owd))

        # using saveWidget and webshot (old)
        saveWidget(mapdown(), "temp.html", selfcontained = FALSE)
        webshot("temp.html", file = file, cliprect = "viewport")

        # using mapshot we can substitute the above two lines of code
        # mapshot(mapdown(), file = file, cliprect = "viewport")
      }
    )
  }

UI

ui <- fluidPage(
     sidebarPanel(
     checkboxInput('returnpdf', 'output pdf?', FALSE), 
     conditionalPanel(
       condition = "input.returnpdf == true",
       downloadButton('map_down')
      ) 
     ), 
     mainPanel(leafletOutput("map"))

)

Davide
  • 111
  • 1
  • 7
  • Any ideas why the plot would be downloading with a grey background, rather than the map background (specifically using your approach in the second code block)? – Jake Sep 12 '17 at 13:51
  • One reason could be that it is not loading the tile of the map. By the way now the downloading can be simplified massively using **mapshot** instead of **webshot**. Basically you should not need anymore to use Rmarkdown or saveWidget. I will post an updated solution. – Davide Sep 19 '17 at 14:40
  • Hi Jake, it downloads with grey background because you need to specify a link within _addTiles_ (see my edited example above). My guess is that the default tile does not support download, but you can try specifying the link to the default one and see if it works. Hope it helps. – Davide Sep 20 '17 at 14:34
  • Thanks for the reply. I did get that to work following your example above, but I really want to be able to use this with offline map tiles. I have some tiles downloaded locally to a computer (I won't be connected to the internet), and I'm serving those tiles. When I follow your example with those local tiles I get the grey background in my download still. – Jake Sep 25 '17 at 03:29
  • This works beautifully... locally, on my home computer. On shinyapps.io, I receive the 404 Not found error. – RTS May 08 '18 at 18:22
  • What if the lines and markers are drawn with addDrawToolbar in the leaflet.extras package? I could not get around to saving the map with them and then I asked a question on it: https://stackoverflow.com/questions/53650039/how-to-save-a-leaflet-map-with-drawn-shapes-points-on-it-in-shiny – BRCN Dec 06 '18 at 11:27
  • Here to say that mapview::mapshot isn't working for me (related to this issue: https://github.com/r-spatial/mapview/issues/61) so very grateful to see the webshot solution as well! – Jaccar Aug 01 '19 at 09:15