r - 在闪亮的应用程序中,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!
我在网上搜索了高低,没有发现任何有用的东西。我一定是在做一些简单的错误,任何指向正确方向的人都将不胜感激。
解决方案
正如@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)
})
}
)
注意 我也在这里回答了,因为我遇到了同样的问题,先到这里,并错过了一段时间的欺骗评论。希望这可以节省一些时间。