Saving a Tmap plot in shiny

Viewed 326

I want to add a feature for users to export a map, produced by Tmap, in Shiny. I understand that tmap converts the map to leaflet but it doesn't work with mapview::mapshot as many answers give for saving Leaflet maps in Shiny.

None of the following work:

map_expr <- reactive({
    tm_shape(water1) +
      tm_fill(col = "darkblue") +
    tm_shape(county_outlines) +
      tm_borders(col = "black") +
    tm_shape(herd_summary) +
      tm_symbols(col = "green", size = "REACTORS", scale = 0.15, alpha = 0.7) +
    tm_shape(water1) +
      tm_fill(col = "darkblue")
  })
  
  observe({
    output$map <- renderTmap({
      map_expr()
    })
  })

output$downloadData <- downloadHandler(
    filename = "test.png",
    content = function(file) {
      # mapshot(map_expr(), file = file, cliprect = "viewport")
      # tmap_save(map_expr(), file = file)
      tmapProxy("map", session, {}) %>%
        mapview::mapshot(file = file)
    }
  )
3 Answers

After some trial and error, I eventually got it to work, and have included a reproducible example here as follows:

library(shiny)
library(tmap)
library(mapview)

data("World")
pal <- leaflet::colorBin(palette = grDevices::heat.colors(20), domain = World$HPI)

ui <- fluidPage(

    titlePanel("Tmap Example"),

    sidebarLayout(
        sidebarPanel(
            downloadButton("downloadData")
        ),
        mainPanel(
            tmapOutput("map")
        )
    )
)

server <- function(input, output) {
    map_expr <- reactive({
        tm_shape(World) +
            tm_polygons("HPI")
    })
    
    output$map <- renderTmap({
        map_expr()
    })
    
    output$downloadData <- downloadHandler(
        filename = "test.png",
        content = function(file) {
            mapview::mapshot(tmap_leaflet(map_expr()), file = file)
        }
    )
}

shinyApp(ui = ui, server = server)

So the tmap expression must be saved to an object (I am saving it to a reactive object called map_expr, so you must include the brackets when calling this object elsewhere within the code).

Using the function mapshot from the package mapview, you can save a leaflet object, and there is a function called tamp_leaflet within tmap that will convert the tmap object to a leaflet object.

Make sure that mapshot is working by first testing it outside of the application. To get it to work, I had to install the package webshot and had to install phantomJS which can be done via the following function: webshot::install_phantomjs()

Hope this helps!

library(tmap)
data("World")

# pal accepts a character vector of colours
tm_shape(World) +
  tm_polygons("HPI", pal = c("#DC0032","#FFF5AC","#00B0F0"))

# You can also store the palette in pal, 
# and then call pal(3) to return three colours
pal = grDevices::colorRampPalette(c("#DC0032","#FFF5AC","#00B0F0"))
tm_shape(World) +
  tm_polygons("HPI", pal = pal(3))

use the tmap_save function

output$downloadData <- downloadHandler(
filename = "example.png",
content = function(file) {
tmap_save(map_expr(), file)
}
Related