Shiny 应用程序不会从 Rmd 的 chrome_print 渲染下载 pdf

问题描述 投票:0回答:1

我正在按照 https://github.com/RLesur/chrome_print_shiny 中的示例构建一个 Shiny 应用程序,该应用程序将从 .Rmd 文件生成 .pdf 输出。我可以让示例 app.R 在本地运行(对于大多数选择),但修改最终将使用

render(params())
的 .Rmd 并未成功。

报告生成器.Rmd

---
title: "Test Report"
output:
  pagedown::html_paged:
    includes:
    number_sections: false
    self_contained: true
    css:
       - default

params:
  gonna: "a"
  have: "b"
  some: "c"
  later: "d"
#knit: pagedown::chrome_print # commented out for use in Shiny
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)
```
## Summary

```{r cars}
summary(cars)
```

## Plot

```{r pressure}
plot(pressure)
```

app.R

library(pagedown)
library(promises)
library(rmarkdown)
library(shiny)
library(shinybusy)

chrome_extra_args <- function(default_args = c("--disable-gpu")) {
  args <- default_args
  # Test whether we are in a shinyapps container
  if (identical(Sys.getenv("R_CONFIG_ACTIVE"), "shinyapps")) {
    args <- c(args,
              "--no-sandbox", # required because we are in a container
              "--disable-dev-shm-usage") # in case of low available memory
  }
  args
}

# send the .Rmd to temp
tempReport <- tempfile(fileext=".Rmd")
file.copy("ReportGenerator.Rmd", tempReport, overwrite=TRUE)

ui <- fluidPage(
  actionButton( # build the report
    inputId="buildBtn",
    label="Build Report"
  ),
  uiOutput("downloadBtn") # download the report
)

server <- function(input, output) {
  observeEvent(input$buildBtn, {
    output$downloadBtn <- renderUI({
      show_modal_spinner()
      # generate PDF
      chrome_print(
        render(tempReport,
               # will have params here later
               envir = new.env(parent = globalenv())
        ),
        output=tempfile(fileext=".pdf"),
        extra_args=chrome_extra_args(),
        verbose=1,
        async=TRUE
      )$then(
        onFulfilled=function(value){
          showNotification("PDF file successfully generated", type="message")
          output$downloadBtn <- downloadHandler(
            filename="Report.pdf", 
            content=function(file){
              file.copy(value, file) # I think the problem is here?
            },
            contentType="application/pdf"
          )
          downloadButton(
            outputId="downloadBtn",
            label="Download Report"
          )
        },
        onRejected=function(error){
          showNotification(
            error$message,
            duration=NULL,
            type="error"
          )
          HTML("")
        }
      )$finally(remove_modal_spinner)
    })
    
  })
  
}

shinyApp(ui = ui, server = server)

单击“构建报告”按钮确实会生成 .pdf - 使用

tempdir()
,我可以导航到会话的临时目录,并看到 .Rmd 已被连接,并且 .pdf 就在那里,命名为通常的临时文件哈希,打开时看起来与预期一致。但是,单击“下载报告”按钮不会提供 .pdf 文件。相反,我得到一个 .html 文件的对话框,该文件不包含
downloadHandler
中指示的文件名。打开它会生成一个 .html 窗口,看起来与原始 Shiny 应用程序页面类似。

鉴于 .pdf does 已生成,我猜测问题出在

downloadHandler(content)
中的某个位置,但我不太熟悉
chrome_print(async=TRUE)
如何与
library(promises)
$then()
和临时文件一起使用将 .pdf 从 Temp 目录中拉出并将其粘贴到处理程序中。

r shiny r-markdown pagedown
1个回答
0
投票

output_file_path
设为
reactiveVal
。这将作为生成的 PDF 路径的存储点。此外,应利用
downloadHandler
中保留的路径独立定义
output_file_path

downloadHandler
然后利用此存储路径来方便下载 PDF 文件:

library(pagedown)
library(promises)
library(rmarkdown)
library(shiny)
library(shinybusy)

chrome_extra_args <- function(default_args = c("--disable-gpu")) {
  args <- default_args
  # Test whether we are in a shinyapps container
  if (identical(Sys.getenv("R_CONFIG_ACTIVE"), "shinyapps")) {
    args <- c(args,
              "--no-sandbox", # required because we are in a container
              "--disable-dev-shm-usage") # in case of low available memory
  }
  args
}

# send the .Rmd to temp
tempReport <- tempfile(fileext=".Rmd")
file.copy("ReportGenerator.Rmd", tempReport, overwrite=TRUE)

# <- changed here
ui <- fluidPage(
  titlePanel("ABR Dashboard"),
  actionButton(inputId = "buildBtn", label = "Build Report"),
  uiOutput("downloadBtn")
)

server <- function(input, output) {
    
    # new a path for the pdf
    output_file_path <- reactiveVal()
    
    observeEvent(input$buildBtn, {
      show_modal_spinner()
      # generate PDF
      promise <- chrome_print(
        input = render(tempReport,
                       # will have params here later
                       envir = new.env(parent = globalenv())
        ),
        output = tempfile(fileext = ".pdf"),
        extra_args = chrome_extra_args(),
        verbose = 1,
        async = TRUE
      )
      
      promise$then(
        onFulfilled = function(value) {
          output_file_path(value) # <- store to path to the generated pdf
          remove_modal_spinner()
          showNotification("PDF file successfully generated", type = "message")
        },
        onRejected = function(error) {
          remove_modal_spinner()
          showNotification(error$message, duration = NULL, type = "error")
        }
      )
    })
    
    output$downloadBtn <- renderUI({
      if (!is.null(output_file_path())) {
        downloadButton(outputId = "downloadPDF", label = "Download Report")
      }
    })
    
    output$downloadPDF <- downloadHandler(
      filename = "Report.pdf",
      content = function(file) {
        file.copy(output_file_path(), file, overwrite = TRUE)
      },
      contentType = "application/pdf"
    )

}

shinyApp(ui = ui, server = server)

© www.soinside.com 2019 - 2024. All rights reserved.