首页 > 解决方案 > 在闪亮的应用程序中,downloadHandler() 是否有理由无法从 rmarkdown::render() 渲染 pdf?

问题描述

我有一个复杂的闪亮应用程序,它运行良好,除了一个下载按钮,用于从 rmarkdown 呈现 pdf 以生成可下载的报告。

简而言之,downloadHandler() 没有成功地从 rmarkdown::render() 渲染 pdf,但是 Rstudio 从 .Rmd 文件中很好地编织了 pdf,并且 Rstudio 可以在临时文件中从 .tex 文件中编译 pdf 没有问题。

简化代码:

我的闪亮应用程序使用多文件布局,这个最小的代码重现了我机器上的问题,比我实际的闪亮应用程序复杂得多。

重现错误的简单代码

用户界面

#
# This is the user-interface definition of a Shiny web application. You can
# run the application by clicking 'Run App' above.
#
# Find out more about building applications with Shiny here:
#
#    http://shiny.rstudio.com/
#

library(shiny)

# Define UI for application that draws a histogram
shinyUI(fluidPage(

    # Application title
    titlePanel("Old Faithful Geyser Data"),

    # Sidebar with a slider input for number of bins
    sidebarLayout(
        sidebarPanel(
            sliderInput("bins",
                        "Number of bins:",
                        min = 1,
                        max = 50,
                        value = 30),
            downloadButton("Markdown", "Generate report")
        ),

        # Show a plot of the generated distribution
        mainPanel(
            plotOutput("distPlot")
        )
    )
))

服务器.R

#
# This is the server logic of a Shiny web application. You can run the
# application by clicking 'Run App' above.
#
# Find out more about building applications with Shiny here:
#
#    http://shiny.rstudio.com/
#

library(shiny)

# Define server logic required to draw a histogram
shinyServer(function(input, output) {

    output$distPlot <- renderPlot({

        # generate bins based on input$bins from ui.R
        x    <- faithful[, 2]
        bins <- seq(min(x), max(x), length.out = input$bins + 1)

        # draw the histogram with the specified number of bins
        hist(x, breaks = bins, col = 'darkgray', border = 'white')

    })

    #options(tinytex.verbose = TRUE)
    ##---- Markdown ----
    source('06_Save_pdf_report.R', local = TRUE)
    
})

06_Save_pdf_report.R

output$Markdown <- downloadHandler(
    # For PDF output, change this to "report.pdf"
  filename = "report.pdf",
  content = function(file) {
    # Copy the report file to a temporary directory before processing it, in
    # case we don't have write permissions to the current working dir (which
    # can happen when deployed).

    
    tempReport <- file.path(tempdir(), "07_tester.Rmd")
    file.copy("07_tester.Rmd", tempReport, overwrite = TRUE)
    
    # Knit the document, passing in the `params` list, and eval it in a
    # child of the global environment (this isolates the code in the document
    # from the code in this app).
    rmarkdown::render(tempReport, 
                      output_format = "pdf_document",
                      output_file = file
                      )
    }
)

07_tester.Rmd

---
title: "07_tester.Rmd"
author: "CB"
date: "2/10/2021"
output: pdf_document
---

```{r setup, include=FALSE}
options(tinytex.verbose = TRUE)
knitr::opts_chunk$set(echo = FALSE)
```

## R Markdown

This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see <http://rmarkdown.rstudio.com>.

When you click the **Knit** button a document will be generated that includes both content as well as the output of any embedded R code chunks within the document. You can embed an R code chunk like this:

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

## Including Plots

You can also testingwithout plots, for example:

```{r pressure, echo=FALSE}
summary(cars)
```

Note that the `echo = FALSE` parameter was added to the code chunk to prevent printing of the R code that generated the plot.

好的问题和错误

如果我编织 07_tester.Rmd 文件,我会得到一个 pdf 没有问题。当我运行闪亮的应用程序并单击生成报告按钮时,我会在控制台中看到正常的 rmarkdown 活动,最后会弹出一个窗口来显示文件的保存位置,注意它不包含 06_Save_pdf_report.R 代码中的文件名. 单击保存按钮后,控制台中会出现以下错误:

Warning: Error in : LaTeX failed to compile C:\Users\USER\AppData\Local\Temp\RtmpQD0jkj\file49b85d6276e8.tex. See https://yihui.org/tinytex/r/#debugging for debugging tips.
  [No stack trace available]

在此之前没有警告或错误,之后应用程序继续运行而没有问题。没有文件实际上被保存或下载到任何地方。

如果我转到 C:\Users\USER\AppData\Local\Temp\RtmpQD0jkj\ 并在 Rstudio 中打开 file49b85d6276e8.tex 文件,我可以将其编译为 pdf 而不会出错。从闪亮的应用程序尝试中,临时文件夹还包含一个 texput.log 文件,它显示:

This is pdfTeX, Version 3.14159265-2.6-1.40.21 (TeX Live 2020/W32TeX) (preloaded format=pdflatex 2021.2.10)  10 FEB 2021 18:04
entering extended mode
 restricted \write18 enabled.
 %&-line parsing enabled.
**C:/Users/USER/AppData/Local/Temp/RtmpQD0jkj/file49b85d6276e8.tex
! Emergency stop.
<to be read again> 
                   \protect 
<*> C:/Users/USER
                  /AppData/Local/Temp/RtmpQD0jkj/file49b85d6276e8.tex 
Here is how much of TeX's memory you used:
 4 strings out of 481250
 115 string characters out of 5913850
 266128 words of memory out of 5000000
 17047 multiletter control sequences out of 15000+600000
 403430 words of font info for 27 fonts, out of 8000000 for 9000
 14 hyphenation exceptions out of 8191
 3i,0n,0p,1b,6s stack positions out of 5000i,500n,10000p,200000b,80000s

!  ==> Fatal error occurred, no output PDF file produced!

我在网上搜索了高低,没有发现任何有用的东西。我一定是在做一些简单的错误,任何指向正确方向的人都将不胜感激。

标签: rpdfshinyr-markdownrstudio

解决方案


正如@RemkoDuursma 的评论以及@PatrickBucher的回复中所指出的:

output_file 不应该以这种方式使用。它只是中间的 LaTeX 文件。从渲染返回 PDF 文件的位置。这个文件只需要移动到文件参数指向的地方:

library(rmarkdown)
library(tinytex)
library(shiny)

shinyApp(
    #
    # This is the user-interface definition of a Shiny web application. You can
    # run the application by clicking 'Run App' above.
    #
    # Find out more about building applications with Shiny here:
    #
    #    http://shiny.rstudio.com/
    #
    
    
    
    # Define UI for application that draws a histogram
    ui = shinyUI(fluidPage(
    
        # Application title
        titlePanel("Old Faithful Geyser Data"),
    
        # Sidebar with a slider input for number of bins
        sidebarLayout(
            sidebarPanel(
                sliderInput("bins",
                            "Number of bins:",
                            min = 1,
                            max = 50,
                            value = 30),
                downloadButton("Markdown", "Generate report")
            ),
    
            # Show a plot of the generated distribution
            mainPanel(
                plotOutput("distPlot")
            )
        )
    )),
  server = function(input, output) {
      
    #
    # This is the server logic of a Shiny web application. You can run the
    # application by clicking 'Run App' above.
    #
    # Find out more about building applications with Shiny here:
    #
    #    http://shiny.rstudio.com/
    #
    
    
    # Define server logic required to draw a histogram

    output$distPlot <- renderPlot({

        # generate bins based on input$bins from ui.R
        x    <- faithful[, 2]
        bins <- seq(min(x), max(x), length.out = input$bins + 1)

        # draw the histogram with the specified number of bins
        hist(x, breaks = bins, col = 'darkgray', border = 'white')

    })

    #options(tinytex.verbose = TRUE)
    ##---- Markdown ----
    output$Markdown <- downloadHandler(
        # For PDF output, change this to "report.pdf"
      filename = "report.pdf",
      content = function(file) {
        # Copy the report file to a temporary directory before processing it, in
        # case we don't have write permissions to the current working dir (which
        # can happen when deployed).
    
        
        tempReport <- file.path(tempdir(), "07_tester.Rmd")
        file.copy("07_tester.Rmd", tempReport, overwrite = TRUE)
        
        # Knit the document, passing in the `params` list, and eval it in a
        # child of the global environment (this isolates the code in the document
        # from the code in this app).
        output <- rmarkdown::render(
            input = tempReport
        )
        file.copy(output, file) 
    })
    
  }
)

注意 我也在这里回答了,因为我遇到了同样的问题,先到这里,并错过了一段时间的欺骗评论。希望这可以节省一些时间。


推荐阅读