rshinytmap

Saving a Tmap plot in shiny


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)
    }
  )

Solution

  • 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!