I'm trying to knit a word document from a shiny app using a template.docx file. I get the following error message:
pandoc.exe: template.docx: openBinaryFile: does not exist (No such file or directory)
The following 3 files were all currently located in the same directory.
app.R:
library(shiny)
library(rmarkdown)
ui <- fluidPage(
titlePanel("Word template"),
sidebarLayout(
sidebarPanel(),
mainPanel(
downloadButton("download", "Download Report")
)
)
)
server <- function(input, output) {
output$download <- downloadHandler(
filename = function() {
"report.docx"
},
content = function(file) {
src <- normalizePath('report.Rmd')
owd <- setwd(tempdir())
on.exit(setwd(owd))
file.copy(src, 'report.Rmd', overwrite = TRUE)
out <- render('report.Rmd',
envir = new.env(parent = globalenv()))
file.rename(out, file)
}
)
}
shinyApp(ui = ui, server = server)
report.Rmd:
---
title: "Test"
output:
word_document:
reference_docx: template.docx
---
`r getwd()`
```{r}
mtcars
```
template.docx is an empty "new" Word 2016 document
In the downloadHandler() function you need to copy both .Rmd and .docx files to the temporary directory
content = function(file) {
src <- normalizePath(c('report.Rmd', 'template.docx')) # SEE HERE
owd <- setwd(tempdir())
on.exit(setwd(owd))
file.copy(src, c('report.Rmd', 'template.docx'), overwrite = TRUE) # SEE HERE
out <- render('report.Rmd',
envir = new.env(parent = globalenv()))
file.rename(out, file)
}
Thoughts
I wouldn't have worked this out without preparing a reproducible example and thinking about how to describe the problem. It's worth thinking about how to ask your question!
Related
This is a followup or more a simplification of this question Error: File header.tex not found in resource path in a rmarkdown generated pdf report from a shiny app
With this Rmarkdown code I can achieve what I want:
logo.png
report.Rmd
---
geometry: margin=20truemm
fontfamily: mathpazo
fontsize: 11pt
documentclass: article
classoption: a4paper
urlcolor: blue
output:
pdf_document:
header-includes:
- \usepackage{fancyhdr}
- \pagestyle{fancy}
- \rhead{\includegraphics[width = .05\textwidth]{logo.png}}
params:
scores: NA
---
<!-- ```{r, echo=FALSE} -->
<!-- hist(params$scores) -->
<!-- ``` -->
```{r}
hist(runif(100))
```
Getting desired output: The R logo is in the header:
Now I would like to do the same from a shiny app
For this I pass the plot as a parameter and uncomment the relevant part in the report.Rmd file
relevant part in report.Rmd file:
```{r, echo=FALSE}
hist(params$scores)
```
app.R
# Global variables can go here
n <- 200
# Define the UI
ui <- bootstrapPage(
numericInput('n', 'Number of obs', n),
plotOutput('plot'),
downloadButton('report', 'Generate Report')
)
# Define the server code
server <- function(input, output) {
output$plot <- renderPlot({
hist(runif(input$n))
})
# create markdown report ----------------------------------
output$report <- downloadHandler(
filename = "report.pdf",
content = function(file) {
tempReport <- file.path(tempdir(), "report.Rmd")
file.copy("report.Rmd", tempReport, overwrite = TRUE)
params <- list(scores = input$n)
rmarkdown::render(tempReport, output_file = file,
params = params,
envir = new.env(parent = globalenv())
)
}
)
}
# Return a Shiny app object
shinyApp(ui = ui, server = server)
Error:
! Package pdftex.def Error: File `logo.png' not found: using draft setting.
I suspect because it works locally logo.png is not found in the temporary file where shiny saves tempReport
But I don't know why this works when knitting from markdown and not when calling it from the shiny app.
I think I have been through of the relevant sites on the internet!
Many thanks!
Basically you already figured out what's the issue. Hence one approach to fix your issue would be to do copy both the report template and the logo to the same temporary directory.
# Define the server code
server <- function(input, output) {
output$plot <- renderPlot({
hist(runif(input$n))
})
# create markdown report ----------------------------------
output$report <- downloadHandler(
filename = "report.pdf",
content = function(file) {
td <- tempdir()
tempReport <- file.path(td, "report.Rmd")
tempLogo <- file.path(td, "logo.png")
file.copy("report.Rmd", tempReport, overwrite = TRUE)
file.copy("logo.png", tempLogo, overwrite = TRUE)
params <- list(scores = input$n)
rmarkdown::render(tempReport,
output_file = file,
params = params,
envir = new.env(parent = globalenv())
)
}
)
}
I am trying to reproduce an example form the shiny website and running into the following error. There seems to be an issue with .Rmd file. The code seems to save the report.Rmd file in temp directory but somehow it is not reading it when I try to download the plot.
Code
# load required packages
library(shiny)
library(shinydashboard)
library(tidyverse)
ui <- fluidPage(
title = 'Download a PDF report',
sidebarLayout(
sidebarPanel(
helpText(),
selectInput('x', 'Build a regression model of mpg against:',
choices = names(mtcars)[-1]),
radioButtons('format', 'Document format', c('PDF', 'HTML', 'Word'),
inline = TRUE),
downloadButton('downloadReport')
),
mainPanel(
plotOutput('regPlot')
)
)
)
server <- function(input, output) {
regFormula <- reactive({
as.formula(paste('mpg ~', input$x))
})
output$regPlot <- renderPlot({
par(mar = c(4, 4, .1, .1))
plot(regFormula(), data = mtcars, pch = 19)
})
output$downloadReport <- downloadHandler(
filename = function() {
paste('my-report', sep = '.', switch(
input$format, PDF = 'pdf', HTML = 'html', Word = 'docx'
))
},
content = function(file) {
src <- normalizePath('report.Rmd')
# temporarily switch to the temp dir, in case you do not have write
# permission to the current working directory
owd <- setwd(tempdir())
on.exit(setwd(owd))
file.copy(src, 'report.Rmd', overwrite = TRUE)
library(rmarkdown)
out <- render('report.Rmd', switch(
input$format,
PDF = pdf_document(), HTML = html_document(), Word = word_document()
))
file.rename(out, file)
}
)
}
shinyApp(ui, server)
Error
Listening on http://127.0.0.1:5552
Warning in normalizePath("report.Rmd") :
path[1]="report.Rmd": No such file or directory
Warning: Error in file.copy: file can not be copied both 'from' and 'to'
[No stack trace available]
Your code confused me a fair bit to be honest with you. I changed some things to get the report to download in my tempdir() successfully so hopefully this answers your question.
content = function(file) {
library(rmarkdown)
tempReport <- file.path(tempdir(), "report.Rmd")
file.copy("report.Rmd", tempReport, overwrite = TRUE)
render(tempReport, switch(
input$format,
PDF = pdf_document(), HTML = html_document(), Word = word_document()
))
}
I had to create report.Rmd file before running the above code. That works like a charm.
I made an R script that allows to get an R Markdown report with a certain type of dataset. Now I would like other people to be able to use this script in order to get an automated report with their data but without using this script (especially for people who don't master R).
I try to go through Shiny hoping to make an interface that loads a dataset and would make my script automatically but I can't make the link between Shiny and my Rmd.
How can I tell my Rmd that the dataset to be processed is not the one that my Rmd script was going to look for in a directory but the one that was loaded on the Shiny interface?
Thanks
Here is the Shiny script with my Rmd called "traitemant_bis.Rmd" :
library(shiny)
library(rmarkdown)
ui <- fluidPage(
titlePanel("Uploading Files"),
sidebarLayout(
sidebarPanel(
fileInput(
inputId = "file1", label = "Choose CSV File",
multiple = FALSE,
accept = c("text/csv", "text/comma-separated-values,text/plain", ".csv")
),
radioButtons("format", "Document format", c("PDF", "HTML", "Word"), inline = TRUE)
),
mainPanel(
tableOutput("contents"),
downloadButton("downloadReport")
)
)
)
server <- function(input, output) {
dataset <- reactive({
req(input$file1)
read.csv(file = input$file1$datapath,
na.strings = ".",
sep = ";",
header = TRUE,
nrows=10)
})
output$contents <- renderTable({
req(dataset())
head(dataset())
})
output$downloadReport <- downloadHandler(
filename = function() {
paste("my-report", sep = ".", switch(
input$format, PDF = "pdf", HTML = "html", Word = "docx"
))
},
content = function(file) {
src <- normalizePath("traitemant_bis.Rmd")
owd <- setwd(tempdir())
on.exit(setwd(owd))
file.copy(src, "traitemant_bis.Rmd", overwrite = TRUE)
out <- render("traitemant_bis.Rmd", switch(
input$format,
PDF = pdf_document(), HTML = html_document(), Word = word_document()
))
file.rename(out, file)
}
)
}
shinyApp(ui, server) ```
I'm giving a simple example showing how you can achieve this. Basically, you can pass any of your data from shiny to Rmd as params.
If you have multiple data frames or any data convert them to a single list and pass as params, you can extract individual data later in the RMarkdown
app.R
library(shiny)
ui <- fluidPage(
# Application title
titlePanel("RMD example"),
downloadButton("btn", "Generate Report")
)
# Define server logic required to draw a histogram
server <- function(input, output) {
data <- reactive({
mtcars
})
output$btn <- downloadHandler(
filename = function(){"myreport.docx"},
content = function(file) {
tempReport <- file.path(tempdir(),"markdown.Rmd")
file.copy("markdown.Rmd", tempReport, overwrite = TRUE)
rmarkdown::render("markdown.Rmd", output_format = "word_document", output_file = file,
params = list(table = data()), # here I'm passing data in params
envir = new.env(parent = globalenv()),clean=F,encoding="utf-8"
)
}
)
}
# Run the application
shinyApp(ui = ui, server = server)
Rmd file
---
title: "Untitled"
author: "Mohan"
date: "2/17/2021"
params:
table: [some object]
output: word_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
## 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}
params$table -> data
data
summary(data)
```
I need to print a report from a shiny application using r markdown. I have been trying to follow the examples, but after many hours, I need some help.
There are 4 files: app.R, report.Rmd, calculations.R and datos.xlsx
datos.xlsx is an excel file with information to be used by a function defined in calculations.R and used by app.R
app.R is expected to provide the result on the screen and a downloadable report. I do not get the latter and I have been strugling the last two days with this.
Thank you very much!
app.R:
ui <- fluidPage(
titlePanel("Calculations"),
sidebarLayout(
sidebarPanel(
fileInput("file1","Select excel file with data", accept=c("excel",".xlsx",".xls")),
"When are available on the screen, you can download the report",
radioButtons('format', 'Document format', c('PDF', 'HTML', 'Word'),
inline = TRUE),
downloadButton('downloadReport')
),
mainPanel(
tableOutput(outputId = "tabla")
)
))
server <- function(input, output) {
source("./calculations.R")
output$tabla<-renderTable({
infile<-input$file1
if(is.null(infile))return(NULL)
calculo(infile$datapath)})
output$downloadReport <- downloadHandler(
filename = function() {
paste('my-report', sep = '.', switch(
input$format, PDF = 'pdf', HTML = 'html', Word = 'docx'
))
},
content = function(file) {
src <- normalizePath('report.Rmd')
# temporarily switch to the temp dir, in case you do not have write
# permission to the current working directory
owd <- setwd(tempdir())
on.exit(setwd(owd))
file.copy(src, 'report.Rmd', overwrite = TRUE)
library(rmarkdown)
out <- render('report.Rmd', switch(
input$format,
PDF = pdf_document(), HTML = html_document(), Word = word_document()
))
file.rename(out, file)
}
)
}
# Run the application
shinyApp(ui = ui, server = server)
report.Rmd:
title: "Dynamic report"
output: word_document
knitr::opts_chunk$set(echo = FALSE,warning=FALSE,message = FALSE)
Results
print(output$tabla)
calculations.R
library(xlsx)
calculo<-function(archivo){
incrementos_descuentos<-read.xlsx(archivo,sheetName="incrementos - descuentos", check.names = FALSE)
incrementos_descuentos$`Desde / mm`<-as.numeric(as.character(incrementos_descuentos$`Desde / mm`))
incrementos_descuentos$`A / mm`<-as.numeric(as.character(incrementos_descuentos$`A / mm`))
incrementos_descuentos$`Volumen / L`<-as.numeric(as.character(incrementos_descuentos$`Volumen / L`))
incrementos_descuentos$`Resultado L/m`<-as.numeric(as.character(incrementos_descuentos$`Resultado L/m`))
incrementos_descuentos$`Resultado L/m`<-incrementos_descuentos$`Volumen / L`/(incrementos_descuentos$`A / mm`-incrementos_descuentos$`Desde / mm`)
Resutado<-incrementos_descuentos
Resutado
}
It seems that I found the solution, after many days.
I added in app.R a reactive object:
informe <- reactive({
infile<-input$file1
if(is.null(infile))return(NULL)
calculo(infile$datapath)
})
and the I called it from report.Rmd as informe()
I'm basing my code below on this page on R Studio on creating apps with downloadable reports. I've created the following app and .Rmd documents, which are both saved in the same directory:
app.R:
library(rmarkdown)
library(shiny)
shinyApp(
ui = fluidPage(
sliderInput("slider", "Slider", 1, 100, 50),
downloadButton("report", "Generate report")
),
server = function(input, output) {
output$report <- downloadHandler(
filename = "report.pdf",
content = function(file) {
tempReport <- file.path(tempdir(), "report.Rmd")
file.copy("report.Rmd", tempReport, overwrite = TRUE)
params <- list(n = input$slider)
render(tempReport, output_file = file,
params = params,
envir = new.env(parent = globalenv())
)
}
)
}
)
report.Rmd:
---
title: "Dynamic report"
output: pdf_document
params:
n: NA
---
```{r}
# The `params` object is available in the document.
params$n
```
A plot of `r params$n` random points.
```{r}
plot(rnorm(params$n), rnorm(params$n))
```
When I click on the "Generate report" button, the file that gets saved is called "report", when in fact I named it "report.pdf". I end up having to add ".pdf" manually into the filename in order for my computer to recognize it as a PDF document.
Is there a reason why the filename doesn't match exactly what I specified? What else am I supposed to do?
Try to set the the contentType argument of downloadHandler to the correct MIME type, i.e. to "application/pdf".