I am trying to create a R markdown file that works with the downloadHandler in my shiny app. In the r markdown I just need a simple uiOutput. Below is how I attempted to pass it into the markdown file.
In server:
output$myOutput <- renderUI({
... # the output that needs to be printed
})
output$downloadChart <- downloadHandler(
filename = "report.pdf",
content = function(file) {
tempReport <- file.path(tempdir(), "report.Rmd")
file.copy("report.Rmd", tempReport, overwrite = TRUE)
params <- list(report = output$myOutput)
rmarkdown::render(tempReport, output_file = file, params = params, envir = new.env(parent = globalenv()))
}
)
report.Rmd
---
title: "report"
output: pdf_document
params:
report: NA
---
```{r}
params$report```
When the code above is used, a HTML file is downloaded. I don't really understand why is this so since I already specified PDF. Is this not the right way to produce a downloadable file? I'm very new to R shiny. Any help would be appreciated!
Related
Dear all shiny developers!
I have a question about a shiny app with a Rmarkdown report downloadable.
The app is based on this https://shiny.rstudio.com/articles/generating-reports.html, taken here as an exemple.
shinyApp(
ui = fluidPage(
sliderInput("slider", "Slider", 1, 100, 50),
downloadButton("report", "Generate report")
),
server = function(input, output) {
output$report <- downloadHandler(
# For PDF output, change this to "report.pdf"
filename = "report.pdf",
content = function(filename) {
# 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(), "Template.Rmd")
print(tempReport)
file.copy("Template.Rmd", tempReport, overwrite = TRUE)
# Set up parameters to pass to Rmd document
params <- list(n = input$slider)
# 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_file = filename,
params = params,
envir = new.env(parent = globalenv())
)
}
)
}
)
with my .Rmd document
---
title: ''
output: pdf_document
geometry: "left=2cm,right=2cm,top=1cm,bottom=2cm"
params:
n: NA
---
```{r}
# The `params` object is available in the document.
params$n
```
A plot of `r params$n` random points.
The code is running ok, the document is created but when I open it, I can see that the code within the chunk is ok but not in the inline code, see below:
However, in this exemple https://shiny.rstudio.com/gallery/download-knitr-reports.html we see that the inline code is good (I don't have the code of the Rmarkdown unfortunatelly).
I saw this subject (https://community.rstudio.com/t/embedding-shiny-with-inline-not-rendering-with-html-output/41175) that could be similar but it is html and the answer does not seem to fit.
Do you have an idea why it does not function ? Or any track to explore ?
Many thanks !!
Be careful to the file.copy function !
Thanks to the remark of Limey, I notice that the Rmarkdown that had a typo few moments ago was not updated! Careful that the file.copy is correct!
Here is the script working:
shinyApp(
ui = fluidPage(
sliderInput("slider", "Slider", 1, 100, 50),
downloadButton("report", "Generate report")
),
server = function(input, output) {
output$report <- downloadHandler(
# For PDF output, change this to "report.pdf"
filename = "report.pdf",
content = function(filename) {
# 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(), "rules.Rmd")
print(tempReport)
file.copy("Data/rules.Rmd", tempReport, overwrite = TRUE)
# Set up parameters to pass to Rmd document
params <- list(n = input$slider)
# 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_file = filename,
params = params,
envir = new.env(parent = globalenv())
)
}
)
}
)
and the Rmarkown
---
title: ''
output: pdf_document
geometry: "left=2cm,right=2cm,top=1cm,bottom=2cm"
params:
n: NA
---
```{r}
# The `params` object is available in the document.
params$n
```
A plot of `r params$n` random points.
Thanks to all of you that gave time to this subject!
I'm trying to make a "downloadable html report" from my shiny app, however when I deploy the app to shinyapps.io and try to download the report, it fails because I can't render the image in the R markdown file. It works fine locally, which means I think the issue is to do with the relative file path.
Short example made for ease:
app.R
library(shiny)
library(dplyr)
library(tidyverse)
library(knitr)
library(here)
#load pca plots from working directory
pca <- list.files(pattern="*pca_check.png")
#move file to www folder for it to render correctly
dir.create("www")
file.copy(pca[[1]], "www")
#pca[[1]] is "sept_2021.pca_check.png"
##################
# Make Shiny App #
##################
ui <- fluidPage(titlePanel("QC output"),
navbarPage("Menu",
tabPanel("Report",
sidebarLayout(
sidebarPanel(downloadButton("report", "Generate report"), width=0
),
mainPanel(tags$h2("Ancestry prediction Peddy"),
a(img(src=pca[[1]], height = 500, width = 300, slign="center",
target="_blank"),
href=pca[[1]])
)))))
server <- function(input, output) {
output$report <- downloadHandler(
# For PDF output, change this to "report.pdf"
filename = "report.html",
content = function(file) {
tempReport <- file.path(tempdir(), "report.Rmd")
file.copy("report.Rmd", tempReport, overwrite = TRUE)
# Set up parameters to pass to Rmd document
params <- list(pca = pca[[1]])
rmarkdown::render(tempReport, output_file = file,
params = params,
envir = new.env(parent = globalenv())
)
}
)
}
shinyApp(ui = ui, server = server)
NB: the image displays fine in the app when using this code:
a(img(src=pca[[1]], height = 500, width = 300, slign="center",
target="_blank"),
href=pca[[1]])
However, when generating the report, it fails...
report.Rmd
---
title: "Dynamic report"
output: html_document
params:
pca: NULL
---
PCA plot
```{r out.width="70%"}
knitr::include_graphics(here::here(pca))```
If it don't use here::here(pca) the code fails locally. However it's clearly giving the wrong path when deployed. So, instead I tried just:
knitr::include_graphics(pca)
That still fails when deployed. The full app is here: https://lecb.shinyapps.io/QC_sept_21/ and the image in question was successfully uploaded to https://lecb.shinyapps.io/QC_sept_21/sept_2021.pca_check.png, which implies I am referring to the correct directory... perhaps the markdown doesn't know what the "working directory" is?
Anyone have any idea how to get the image to render in the downloadable report please?
Many thanks!
knitr::rendr treats the folder where the .Rmd file sits as root. You are copying your report.Rmd to a temp folder. Thus, copying your png to the same temp folder and referencing it without here should do the trick remotely and locally:
Untested code snippet:
output$report <- downloadHandler(
# For PDF output, change this to "report.pdf"
filename = "report.html",
content = function(file) {
tmp_dir <- tempdir()
tempReport <- file.path(tmp_dir, "report.Rmd")
tmp_pic <- file.path(tmp_dir, pca[[1]])
file.copy("report.Rmd", tempReport, overwrite = TRUE)
file.copy(pca[[1]], tmp_pic, overwrite = TRUE)
# Set up parameters to pass to Rmd document
params <- list(pca = pca[[1]])
rmarkdown::render(tempReport, output_file = file,
params = params,
envir = new.env(parent = globalenv())
)
}
)
and
---
title: "Dynamic report"
output: html_document
params:
pca: NULL
---
PCA plot
```{r out.width="70%"}
knitr::include_graphics(params$pca)
```
I have a rmarkdown file which is built around the {pagedreport} package (an add-on to pagedown). This creates a html and them uses pagedown::chrome_print to convert the html to pdf.
The rmarkdown file i have works as planned when I have the parameters manually entered on the rmarkdown file, but I want to be able to pick my parameters from a shiny app.
I currently have tried this approach
output$report <- downloadHandler(
# For PDF output, change this to "report.pdf"
filename = "new_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("../temp/", "myRmarkdown.Rmd")
file.copy("myRmarkdown.Rmd", tempReport, overwrite = TRUE)
# Set up parameters to pass to Rmd document
params <- list(A = input$A, B = input$B)
# 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).
library(rmarkdown)
render(tempReport, params = params,
envir = new.env(parent = globalenv()))
}
and I get the result:
Output created: MyRmarkdown.html
but there is no pdf created. Pagedown uses chrome_print to convert - and this is in the yaml of the Rmarkdown.
This is the YAML of my Rmarkdown file
output:
pagedreport::paged_windmill:
img_to_dark: TRUE
logo_to_white: TRUE
knit: pagedown::chrome_print
#toc: TRUE
toc-title: "Table of Contents"
#toc_depth: 1
main-color: "#264653"
secondary-color: "#2a9d8f"
google-font: TRUE
main-font: "Raleway"
header-font: "Roboto"
params:
A: NA
B: NA
editor_options:
markdown:
wrap: 72
I know there is an issue between shiny and chrome_print() where you need to add chrome_print(..., async = TRUE), but I don't know where to put this argument in my shiny app?
I am pretty sure you have to make sure that your render function creates a file at the location given by the argument file. In your current appraoch render uses defaults, which won't work. Thus, it should be as simple as adding the output_file argument to render. The following code snippets works for me:
test.Rmd
---
title: "Untitled"
output: html_document
params:
title: "Test"
heading: "Header"
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)
```
```{r results="asis"}
cat("## ", params$title)
```
You passed in argument `r cat(params$heading)`
app.R
library(shiny)
library(rmarkdown)
ui <- fluidPage(textInput("heading", "Heading"),
textInput("title", "Title"),
downloadButton("download_ok", "Works"),
downloadButton("download_nok", "Does not Work"))
server <- function(input, output) {
output$download_ok <- downloadHandler(
filename = function() {
paste("data-", Sys.Date(), ".html", sep="")
},
content = function(file) {
p <- list(title = input$title,
heading = input$heading)
render("test.Rmd", output_file = file, params = p)
}
)
output$download_nok <- downloadHandler(
filename = function() {
paste("data-", Sys.Date(), ".html", sep="")
},
content = function(file) {
p <- list(title = input$title,
heading = input$heading)
render("test.Rmd", params = p)
}
)
}
shinyApp(ui, server)
This snippet shows how this works now in principle, I do not know pagedreport. If there is an option in the YAML to produce pdfs right away (without the manual call to whatever function) this should work in the same way.
If you absolutely need to call the function, you can do that in the downloadHandler after the render assuming that the function can deal with input file names and create output files at the given location (again you need to create the file at the given location [as per argument file])
After reading the docs of pagedown::chrome_print you can adapt your downloadHandler as follows:
output$report <- downloadHandler(
filename = "new_report.pdf",
content = function(file) {
tempReport <- file.path("../temp/", "myRmarkdown.Rmd")
file.copy("myRmarkdown.Rmd", tempReport, overwrite = TRUE)
params <- list(A = input$A, B = input$B)
html_fn <- rmarkdown::render(tempReport, params = params,
envir = new.env(parent = globalenv()))
pagedown::chrome_print(html_fn, file)
}
I created a shiny app in which I have multiple outputs (tables, graphs and text) based on user selected parameters. I would like to download the outputs in a HTML document. I am able to do this using the small example on https://shiny.rstudio.com/articles/generating-reports.html but I cannot seem to figure out how to use multiple outputs in the markdown file.
I looked around quite a bit and although there are some examples out there I still cannot seem to figure it out. Probably it's just me being inexperienced. The code I modified (poorly) bellow gives outputs test.text, test.text2 then test.text again.
I would like to be able to add multiple output values that will subsequently be used in the markdown. I am using all my outputs in reactive functions as I noticed that I cannot use output$ in downloadHandler
This is the code I am trying to use in downloadHandler
test.text <- reactive({input$gendertext}) #input text written in boxes
test.text2 <- reactive({input$agetext})
output$report <- downloadHandler(
filename = "report.html",
content = function(file) {
tempReport <- file.path(tempdir(), "report.Rmd")
file.copy("report.Rmd", tempReport, overwrite = TRUE)
params <- list(n = test.text())
params2 <- list(n = test.text2())
rmarkdown::render(tempReport, output_file = file,
params = c(params,params2),
envir = new.env(parent = globalenv()))
}
)
As I have multiple outputs (ggplots, tables and text) I would like to be able to use test.text, test.text2, plot1...plotn etc. in markdonw. separately.
e.g.
---
title: "Dynamic report"
output: html_document
params:
n: NA
---
```{r}
test.text
plot1
``
```{r}
test.text2
plot2
``
If there is an easier way to download an Html/pdf file from a shinyUI that would be amazing!
Thank you!
I figured it out! Thanks #Ruben Kazumov for the help.
In order to be able to add plots to a markdown, or any other thing that you might have inside an output$ you first need to wrap your plot in a reactive function.
e.g.
plot <- reactive({your plot(can be ggplot2 or whatever)}
You can render this in your application by using
output$plottorender <- renderPlot({plot()})
And lastly you can use the plot() you just created in a markdown!
output$report <- downloadHandler(
filename = "report.html",
content = function(file) {
tempReport <- file.path(tempdir(), "report.Rmd")
file.copy("report.Rmd", tempReport, overwrite = TRUE)`
# one list() container object for all the parameters
# all the objects have unique names (keys)
`params <- list(text1 = input$test.text1,
text2 = input$test.text2,
plot1 = plot(),
plot2 = plot())) # ... whatever you have to send to the report
rmarkdown::render(tempReport, output_file = file,
params = params,
envir = new.env(parent = globalenv()))
})
output$report <- downloadHandler(
filename = "report.html",
content = function(file) {
tempReport <- file.path(tempdir(), "report.Rmd")
file.copy("report.Rmd", tempReport, overwrite = TRUE)
# one list() container object for all the parameters
# all the objects have unique names (keys)
params <- list(text1 = input$test.text1,
text2 = input$test.text2,
plot1 = output$plot1,
plot2 = output$plot2)) # ... whatever you have to send to the report
rmarkdown::render(tempReport, output_file = file,
params = params,
envir = new.env(parent = globalenv()))
}
)
Then in report:
```{r}
params$text1 # inside the report, you should call the object by its key
params$plot1
``
```{r}
params$text2
params$plot2
``
I have written a shiny application that allows users to produce and download html rmarkdown reports. This works.
However, when the report is generated, the user is prompted for a save location. I can certainly include a location in the filename, but the user is still prompted.
Ideally, I would like the user to click the download button and have the file automatically sent to a specific location.
Here is a sample app that works:
library(shiny)
shinyApp(
ui = fluidPage(
sliderInput("slider", "Slider", 1, 100, 50),
downloadButton("report", "Generate report"),
),
server = function(input, output) {
output$report <- downloadHandler(
# For PDF output, change this to "report.pdf"
filename = paste("My name", ".html", sep=""),
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
tempReport <- file.path(tempdir(), "report.Rmd")
file.copy("report.Rmd", tempReport, overwrite = TRUE)
# Set up parameters to pass to Rmd document
params <- list(n = input$slider)
# 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_file = file,
params = params,
envir = new.env(parent = globalenv())
)
}
)
}
)
and an rmarkdown script:
---
title: "Dynamic report"
output: html_document
params:
n: NA
---
```{r}
# The `params` object is available in the document.
params$n
```
A plot of `params$n` random points.
```{r}
plot(rnorm(params$n), rnorm(params$n))
```