如何将 Shiny 应用程序中的表格和绘图作为参数传递给 R Markdown?
Posted
技术标签:
【中文标题】如何将 Shiny 应用程序中的表格和绘图作为参数传递给 R Markdown?【英文标题】:How to pass table and plot in Shiny app as parameters to R Markdown? 【发布时间】:2020-01-08 03:55:55 【问题描述】:在这款 Shiny 应用中,用户可以上传 .csv 文件,以表格形式获取结果并进行绘图。我希望能够将结果下载为 PDF 文档。
输入文件
#I created the input .csv file to be used in the app from diamonds data.frame
library(ggplot2)
df <- diamonds[1:5000, ]
head(df)
write.csv(df, "df.csv")
应用程序
library(tidyverse)
library(shiny)
library(rmarkdown)
library(knitr)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(fileInput("file","Upload your file"),
width =2),
mainPanel(
width = 10,
downloadButton("report", "Download report"),
tableOutput("table"),
tags$br(),
tags$hr(),
plotOutput("plot1"),
tags$br(),
tags$hr(),
plotOutput("plot2")
)
)
)
server <- function(input,output)
data <- reactive(
file1 <- input$file
if(is.null(file1))return()
read.csv(file1$datapath, header=TRUE, sep=',')
)
output$table <- renderTable(
if (is.null(data())) return()
df <- data() %>%
dplyr::select(cut, color, price) %>%
dplyr::group_by(cut, color) %>%
dplyr::summarise_all(funs(min(.), mean(.), median(.),max(.),sd(.), n() ))
)
table_rmd <- reactive(
df <- data() %>%
dplyr::select(cut, color, price) %>%
dplyr::group_by(cut, color) %>%
dplyr::summarise_all(funs(min(.), mean(.), median(.),max(.),sd(.), n() ))
)
output$plot1 <- renderPlot(
if (is.null(data())) return()
ggplot(data(), aes (x =carat, y = price, col = color))+
geom_point()+
facet_wrap(~cut)
)
plot_rmd <- reactive(
chart <- ggplot(data(), aes (x =carat, y = price, col = color))+
geom_point()+
facet_wrap(~cut)
chart
)
#https://shiny.rstudio.com/articles/generating-reports.html
output$report <- downloadHandler(
filename = "report.pdf",
content = function(file)
tempReport <- file.path(tempdir(), "report.Rmd")
file.copy("report.Rmd", tempReport, overwrite = TRUE)
params <- list(table1 = table_rmd(),
plot1 = plot_rmd())
rmarkdown::render(tempReport, output_file = file,
params = params,
envir = new.env(parent = globalenv())
)
)
shinyApp(ui=ui, server = server)
report.Rmd
---
title: "Dynamic report"
output: pdf_document
params:
table1: NA
plot1: NA
---
This is the firs plot
```r
params$plot1
```
This is the first table
```r
kable(params$table1)
```
我尝试了不同的方法将表格和绘图从 Shiny 作为参数传递给 R Markdown,但没有一个奏效。
非常感谢您提出解决此问题的建议。
更新
我已经尝试过@BigDataScientist 的回答,但我得到了这个错误
"C:/Program Files/RStudio/bin/pandoc/pandoc" +RTS -K512m -RTS report.utf8.md --to latex --from markdown+autolink_bare_uris+ascii_identifiers+tex_math_single_backslash --output pandoc20e043232760.tex - -template "C:\PROGRA~1\R\R-35~1.2\library\RMARKD~1\rmd\latex\DEFAUL~3.TEX" --highlight-style tango --pdf-engine pdflatex --可变图形=是--变量“几何:边距= 1in”--变量“紧凑标题:是” 警告:错误:无法编译 C:\Users\user\AppData\Local\Temp\RtmpYvWn8M\file20e042326267.tex。有关调试提示,请参阅https://yihui.name/tinytex/r/#debugging。 [没有可用的堆栈跟踪]
这里是sessionInfo()
> sessionInfo()
R version 3.5.2 (2018-12-20)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 7 x64 (build 7601) Service Pack 1
Matrix products: default
locale:
[1] LC_COLLATE=English_New Zealand.1252 LC_CTYPE=English_New Zealand.1252 LC_MONETARY=English_New Zealand.1252 LC_NUMERIC=C
[5] LC_TIME=English_New Zealand.1252
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] bindrcpp_0.2.2 forcats_0.3.0 stringr_1.4.0 dplyr_0.7.8 purrr_0.2.5 readr_1.3.1 tidyr_0.8.2 tibble_2.0.1 tidyverse_1.2.1 ggplot2_3.1.0
[11] shiny_1.2.0
loaded via a namespace (and not attached):
[1] tinytex_0.15.2 tidyselect_0.2.5 xfun_0.9 haven_2.0.0 lattice_0.20-38 colorspace_1.4-0 generics_0.0.2 htmltools_0.3.6 yaml_2.2.0
[10] utf8_1.1.4 rlang_0.4.0 later_0.8.0 pillar_1.3.1 glue_1.3.0 withr_2.1.2 readxl_1.2.0 modelr_0.1.2 bindr_0.1.1
[19] plyr_1.8.4 cellranger_1.1.0 munsell_0.5.0 gtable_0.2.0 rvest_0.3.2 evaluate_0.12 labeling_0.3 knitr_1.21 httpuv_1.4.5.1
[28] fansi_0.4.0 broom_0.5.1 Rcpp_1.0.0 xtable_1.8-3 promises_1.0.1 scales_1.0.0 backports_1.1.3 jsonlite_1.6 mime_0.6
[37] hms_0.4.2 digest_0.6.18 stringi_1.2.4 grid_3.5.2 cli_1.0.1 tools_3.5.2 magrittr_1.5 lazyeval_0.2.1 crayon_1.3.4
[46] pkgconfig_2.0.2 xml2_1.2.0 rsconnect_0.8.13 lubridate_1.7.4 assertthat_0.2.0 rmarkdown_1.11 httr_1.4.0 rstudioapi_0.9.0 R6_2.3.0
[55] nlme_3.1-137 compiler_3.5.2
【问题讨论】:
【参考方案1】:您可以将 R 对象作为params
列表的一部分传递给参数化的Rmd
。这是常规交互式会话中的示例(无闪亮)。 report.Rmd
与问题中的相同。 df
和 pl
由一些 R
脚本生成,可在您的环境中使用。然后您可以将它们包装在list
中并将它们作为params
传递给render
。
library(rmarkdown)
library(ggplot2)
df <- head(iris)
pl <- ggplot(iris, aes(x = Sepal.Width)) + geom_histogram(color = "white")
render(
input = "report.Rmd",
params = list("table1" = df, "plot1" = pl),
output_file = "rendered-from-session.pdf"
)
rendered-from-session.pdf
的截图
这是否是一个好的策略是另一个问题。如果制作表格和绘图的代码对于app
和Rmd
是相同的,那么最好将其放在一个由app
和Rmd
提供的单独脚本中。这样,当您想要更改表格/绘图代码时,您只需要编辑一个文档。在这种情况下,您会将参数传递给绘图函数,而不是绘图本身。这样做的缺点是,如果您有许多不同的图,需要许多不同的参数来跟踪。或者如果计算/绘图需要很长时间,所以你不想做两次。
回到您的 Shiny 应用。事实上,您的应用程序代码适用,就像通过 Shiny 一样。我可以制作 pdf(即使 table_rmd()
反应式没有明确返回 df
)。所以很可能是 pandoc 或 latex 没有弄清楚临时文件/文件夹在哪里的问题。由于您仍在测试,我会尝试保存到已知位置而不是 tempdir,以查看这是否不是某种权限问题。
您可以像这样修改您的处理程序。删除对tempdir
的调用,并将report.Rmd
的完整路径提供给render
。您也可以尝试为output_file
提供完整路径。第一种情况应该可以正常工作。在第二种情况下("PATH/TO/OUTPUT"
而不是 file
传递给 output_file
),浏览器可能会给您一个 download
错误,但 pdf 仍应使用您提供的文件名在后台呈现。
output$report <- downloadHandler(
filename = "report.pdf",
content = function(file)
# tempReport <- file.path(tempdir(), "report.Rmd")
# file.copy("report.Rmd", tempReport, overwrite = TRUE)
params <- list(table1 = table_rmd(),
plot1 = plot_rmd())
rmarkdown::render(input = "PATH/TO/report.Rmd",
output_file = file,
params = params,
envir = new.env(parent = globalenv())
)
)
这至少可以确认您的代码正在运行,tempdir()
除外。如果您有选择,请在 linux 机器或 mac 上试用您的应用程序。
【讨论】:
非常感谢您的时间和帮助。我尝试渲染pdf(没有Shiny)并且效果很好。但是,将临时目录更改为完整路径仍会导致与问题更新中所示相同的错误。 该应用在另一台 Linux 机器上运行。我没有Windows机器来测试它。我看到您使用的是pdflatex
。你可以试试其他引擎,也许是xelatex
或lualatex
?但这似乎不太可能是原因,因为您可以从交互式会话中进行渲染。那tempdir
的内容呢?它有正确扩展名的文件吗?最后,正如这里所讨论的:yihui.name/tinytex/r/#debugging,您可以将此options(tinytex.verbose = TRUE)
添加到您的report.Rmd
中的代码块中,以查看完整日志中的乳胶错误。
谢谢。我只是简单地卸载了TinyTex
并安装了MiKTex
,现在一切正常。【参考方案2】:
不确定是否可以将表格和绘图作为参数传入/传给 rmarkdown。 (也请在此处考虑 teofil 的回答)。
所有可以被 yaml::yaml.load() 解析的标准 R 类型都可以 包含为参数,包括字符、数字、整数和 逻辑类型。
来源:https://bookdown.org/yihui/rmarkdown/params-declare.html
所以你有两个选择。
将相关数据作为参数传递,并将生成绘图/表格的代码包含在降价模板中(此处为:report.Rmd
)。
如果出于某种原因,有人坚持在闪亮的一面定义绘图/表格的代码,您可以将此代码作为字符发送并使用 eval(parse(text = params$...))
在 rmarkdown 一面对其进行评估。
我可以想象你不想在闪亮 + rmarkdown 中两次指定绘图/表格的代码,但我想你必须在这两个选项之间进行选择,第一个可能更干净。 (但如果其他人有其他想法,请随时将问题留空)。
可重复的示例:(包括两个选项的示例 - 基于您的代码)
report.Rmd
---
title: "Dynamic report"
output: pdf_document
params:
plotData: NA
tableData: NA
plotCode: NA
---
```r
params$tableData
```
```r
eval(parse(text = params$plotCode))
```
```r
library(ggplot2)
ggplot(params$plotData, aes (x = carat, y = price, col = color)) +
geom_point() +
facet_wrap(~cut)
```
app.R
library(shiny)
library(ggplot2)
df <- diamonds[1:5000, ]
head(df)
write.csv(df, "df.csv")
#setwd("....") #be sure to be in same directory
shinyApp(
ui = fluidPage(
sliderInput(inputId = "slider", label = "Slider", min = 1, max = 100, value = 50),
fileInput(inputId = "file", label = "Upload your file"),
downloadButton(outputId = "report", label = "Generate report")
),
server = function(input, output)
data <- reactive(
file1 <- input$file
if(is.null(file1))return()
read.csv(file1$datapath, header = TRUE, sep = ',')
)
table_rmd <- reactive(
data() %>%
dplyr::select(cut, color, price) %>%
dplyr::group_by(cut, color) %>%
dplyr::summarise_all(funs(min(.), mean(.), median(.),max(.),sd(.), n() ))
)
output$report <- downloadHandler(
filename = "report.pdf",
content = function(file)
tempReport <- file.path(tempdir(), "report.Rmd")
file.copy("report.Rmd", tempReport, overwrite = TRUE)
params <- list(plotData = data(), tableData = table_rmd(), plotCode = "plot(1)")
rmarkdown::render(tempReport, output_file = file,
params = params,
envir = new.env(parent = globalenv())
)
)
)
【讨论】:
感谢您的时间和帮助。我收到一条错误消息。我将添加为更新,因为评论太长了 hmm 再次测试并在 ubuntu 上为我工作。无法发现某事。从错误消息中。我假设您可以将“正常” .Rmd 渲染为 pdf 文档? 我通常将 .Rmd 渲染为 pdf 没有问题。我不明白是什么导致了这个错误。 好的,我会看看我是否可以在一台带有 pandoc 的 Windows 机器上进行测试。以上是关于如何将 Shiny 应用程序中的表格和绘图作为参数传递给 R Markdown?的主要内容,如果未能解决你的问题,请参考以下文章
如何将更新的列名从 HandsOnTable 传递到 Shiny 中的绘图?
在 R 中的 Shiny 中部署 dataTableOutput 和绘图; “整理” dataTableOutput