You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Shiny模块中地图PDF下载功能失效问题求助

解决Shiny模块中Leaflet地图导出为PDF并合并多图表的问题

你遇到的核心问题是Leaflet地图是交互式HTML组件,无法像传统R绘图对象(如ggplot2)那样直接在pdf()设备中渲染。直接调用v1$map1不会将地图输出到PDF文件里,需要先把地图转换成静态图片,再插入到PDF中。下面是完整的解决方案:

步骤1:安装必要的包

首先需要安装mapshot和webshot2,这两个包可以将Leaflet地图转换成图片或PDF:

install.packages(c("mapshot", "webshot2"))
# 首次运行需要初始化webshot2依赖的引擎
webshot2::install_phantomjs()

步骤2:修改代码实现下载功能

下面是修改后的完整代码,我会标注关键改动点:

修改后的完整代码

library(shiny)
library(leaflet)
library(mapshot)
library(webshot2)
library(grid)

# The map UI
trade_agreement_ui <- function(id) {
  ns <- NS(id)
  tagList(
    fluidRow(column(
      8, offset = 2,
      box(
        solidHeader = TRUE,
        column(12, align = 'left', h4(strong("Trade Agreement"))),
        br(),
        column(
          12, align = 'left',
          br(),
          leafletOutput(outputId = ns("map1"),height = "650px", width = "100%")
        ),
        width = 16
      )
    )))
}

# The map server
trade_agreement_server <- function(id) {
  moduleServer(id, function(input, output, session) {
    val <- reactiveValues(map1=NULL)
    output$map1 <- renderLeaflet({
      val$map1 <- leaflet() %>%
        addTiles(urlTemplate = "https://api.mapbox.com/styles/v1/bholee/cl75rvfqs002q14o0rwzd6oe5/tiles/{z}/{x}/{y}@2x?access_token=pk.eyJ1IjoiYmhvbGVlIiwiYSI6ImNrN2tibG9pNzAwajMzbWw4ZnlpcDNqY2wifQ.o-qJAmRdkh-McoubI4E2DA")
      val$map1
    })
    # 返回reactiveValues供主server调用
    return(val)
  })
}

# Main UI
ui <- tagList(
  tags$style(HTML(
    paste(
      "html,",
      ".container{ width: 100%; margin: 0 auto; padding: 0; }
@media screen and (min-width: 700px){
 .container{ min-width: 1850px; max-width: 1920px; }
 } ",
      sep = " "
    )
  )),
  tags$div(
    class = "container",
    dashboardPage(
      dashboardHeader(disable = TRUE),
      dashboardSidebar(disable = TRUE),
      dashboardBody(
        #UI for download
        fluidRow(column(
          8, offset = 2,
          box(
            solidHeader = TRUE,
            column(6, align = 'right', class = 'download_padding',
                   downloadButton(
                     outputId = "download",
                     label = "Download Report",
                     class = 'download_button',
                     width = 150,
                   )
            ),
            width = 16,
          )
        )),
        #End of UI for download
        #UI for Trade Agreements
        trade_agreement_ui(id = "agreement")
        #End of UI Trade Agreements
      )
    )
  )
)

# Main Server
server <- shinyServer(function(input, output, session) {
  # 调用地图模块,获取地图对象
  v1 <- trade_agreement_server(id = "agreement")
  
  output$download <- downloadHandler(
    filename = function() {
      paste0("Trade_Report_", Sys.Date(), ".pdf")
    },
    content = function(file) {
      # 创建临时PDF设备,设置合适的页面尺寸
      pdf(file, width = 11, height = 8.5)
      
      # --------------------------
      # 1. 处理Leaflet地图:先转成图片再插入PDF
      # --------------------------
      # 临时保存地图为PNG图片,调整vwidth/vheight控制分辨率
      temp_map <- tempfile(fileext = ".png")
      mapshot(v1$map1, file = temp_map, vwidth = 1800, vheight = 1200)
      
      # 将图片插入PDF页面,充满整个页面
      grid.raster(png::readPNG(temp_map), width = unit(1, "npc"), height = unit(1, "npc"))
      dev.new() # 新建页面用于下一个图表(如果有)
      
      # --------------------------
      # 2. 添加其他图表(示例:这里添加一个ggplot2图表)
      # --------------------------
      # 如果你有其他图表模块,只需获取对应的绘图对象后打印即可
      # library(ggplot2)
      # p <- ggplot(mtcars, aes(mpg, wt)) + geom_point()
      # print(p)
      # dev.new() # 继续添加更多页面
      
      # 关闭PDF设备
      dev.off()
      
      # 删除临时图片文件
      file.remove(temp_map)
    }
  )
})

# Run application
shinyApp(ui, server)

关键改动说明

  1. 引入必要包:添加mapshot、webshot2和grid包,分别用于地图截图、依赖引擎支持和图片渲染。
  2. 地图转图片:在downloadHandler中,用mapshot()将Leaflet地图保存为临时PNG图片,通过vwidth和vheight参数调整地图清晰度。
  3. 插入PDF:用grid.raster()将图片插入到PDF页面中,unit(1, "npc")确保图片充满整个页面。
  4. 多图表合并:如果需要添加其他图表(如ggplot、base plot),只需在dev.new()后打印对应的绘图对象即可,每个dev.new()会创建一个新的PDF页面,实现纵向合并。

注意事项

  • 首次运行webshot2必须执行webshot2::install_phantomjs()安装依赖的PhantomJS引擎,否则地图截图会失败。
  • 可以根据需求调整PDF的width和height参数,以及地图截图的vwidth、vheight参数,优化输出效果。
  • 如果你的其他图表也是模块中的对象,只需在主server中获取对应的reactive值,然后按同样的方式(直接打印或转图片)添加到PDF中即可。

内容的提问来源于stack exchange,提问作者akshay bholee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 19:02:37