Sweave, Shiny : can't generate a PDF on the server - r

I'm working on R Sweave to generate a report in PDF in a shiny application on a server. Everything works perfectly in my computer, locally, I can generate my PDF in the application. It also works in the server. But, when I wanted to add an image in a background, a rectangular header, in the R Sweave , it didn't work anymore on the server, it can't be generated.
Here's the code I added in my R Sweave, so my report :
\usepackage{background}
\usepackage{graphicx}
\backgroundsetup{
scale=0.5,
angle=0,
opacity=1,
color=black,
contents={\begin{tikzpicture}[remember picture, overlay]
\node at ([yshift=-.6in] current page.north)
{\includegraphics[width = \paperwidth]{myheader}};
\end{tikzpicture}}
}
Did I forget something ?
Thank you
EDIT : After some researches, I think I probably have a problem with these functions in the script server.R :
output$report <- downloadHandler(
filename = function(){name()},
content = function(file) {
out = knitr::knit2pdf(input="my_report.Rnw",encoding = "UTF-8",clean=TRUE)
file.rename(out, file)
file.copy(file,paste0("export/",Sys.Date(),"_",name()))
},
contentType = 'application/pdf'
)
It seems that I probably forgot an argument in my function out = knitr::knit2pdf(input="my_report.Rnw",encoding = "UTF-8",clean=TRUE). It seems that it can only manage a text on UTF-8 and geometric forms, not an image.

Problem solved! In my R Sweave, I just added \usepackage{tikz} and it works!
Thanks to Dirk Eddelbuettel for his help.

Related

Generate and render rmd from within shinyapp

I wrote a shiny app that includes generating an rmd file and then rendering it into html report.
As shown in the simple example below, there is a variable created inside the server function of shinyapp, then the created rmd file should have access to this variable while rendering into html.
according to other posts and articles, it seems that we have to copy the rmd file into a temporary folder to work and that's what I tried to do below.
the app is not working.
when I try locally, I get this error:
Quitting from lines 8-9 (x3.Rmd)
Warning: Error in print: object 'xz' not found
so it seems that shiny was able to find the generated rmd, started rendering it but did not have access to the xz variable generated in shiny. I did some reading, and it seems to be related to the render environment (ie it renders in a new session) but I do not know how to fix that. (in the real app I am working on, the render process should have access to a dataframe not just a string variable, but I believe the concept is the same for illustration purpose).
when I tested on shinyapps.io, it says Failed-server problem when I click on the download button. Surprisingly, there is nothing in the application log, it says currently no logs.
when I test the original app I am writing (not this simple example), I get this error in shinyapp.io logs:
2022-04-10T18:01:45.357461+00:00 shinyapps[6055802]: Warning in normalizePath(path, winslash = winslash, mustWork = mustWork) :
2022-04-10T18:01:45.357710+00:00 shinyapps[6055802]: [No stack trace available]
2022-04-10T18:01:45.357627+00:00 shinyapps[6055802]: Warning: Error in abs_path: The file '/tmp/Rtmp27RVU8/x3.Rmd' does not exist.
2022-04-10T18:01:45.357543+00:00 shinyapps[6055802]: path[1]="/tmp/Rtmp27RVU8/x3.Rmd": No such file or directory
My goal is to make this work from shinyapp.io. Any suggestions on where to go from there, I believe there are two issues:
1- make sure the rmd render will have access to the variables generated in shiny
2- save the rmd file in a place that is "convenient" for shiny to find and render.
library(shiny)
ui <- fluidPage(
downloadButton("report", "Download sample report.")
)
server <- function(input, output, session) {
#create content and export it into rmd
observe({
xz= "hello there"
x3 = '---
title: sample
output: html_document
---
``` {r}
print(xz)
```
';write(x3, file="x3.rmd", append = FALSE)
})
#Render the report and pass it to download handler
output$report <- downloadHandler(
filename = "sample.html",
content = function(file) {
tempReport <- file.path(tempdir(), "x3.Rmd")
file.copy("x3.Rmd", tempReport, overwrite = TRUE)
output <- rmarkdown::render(
input = tempReport
)
file.copy(output, file)
})
}
shinyApp(ui, server)
These are the resources I used (but still unable to make it work). All deal with parameterized reports of a user uploaded .rmd, which won't work in my case:
https://shiny.rstudio.com/articles/generating-reports.html
https://community.rstudio.com/t/where-do-i-save-the-rmd-file-i-am-generating-with-a-shiny-r-app/65987/3
https://community.rstudio.com/t/generating-downloadable-reports/39701
https://mastering-shiny.org/action-transfer.html#downloading-reports
I have done this with Shiny App but on a shiny server (in my work place) and can share only the approach here. Currently the access to exact code will take time but this shall give you idea. No idea how it works with shinyapps.io but will try that sometime.
Within UI of shiny provide for a "Generate Report" Button.
In server, with
observeEvent(input$btn_Id,{
#Code to render the html in rmarkdown and then also `downloadHandler()`
})
Please check this also :
Use the downloandHanlder() referring this documentation.
This one gives idea to download data
Solution to passing variables is not special. Just ensure data is already present when you are calling render()
like this:
rmarkdown::render(input = "D:/YourWorkingDirectly/Letters.rmd")
If this doesn't help you , please let me know and will delete the answer.

R Shiny downloadHandler does not work inside flexdashboard

I am working in a R Shiny Flexdashboard, and including a download button. To distribute the items on the screen I would like to use splitLayout. But the issue is, if I use downloadButton inside the SplitLayout, the downloadHandler throws a very strange behaviour... in RStudio, it tries to save an (apparently) empty .Rmd file. In the browser, it tries to save an (apparently) empty .htm file...
The code with a minimal example is the following:
splitLayout(cellWidths = c("30%", "70%"),
wellPanel(
downloadButton("downloadData")
),
dataTableOutput("OrigData")
)
output$downloadData<-downloadHandler(
filename = "OriginalData.csv" ,
content = function(file) {
write.csv(mtcars, file=file)
},
contentType="text/csv"
)
output$OrigData<-DT::renderDataTable(mtcars)
I would like to understand what is going on...
From the link apparently downloadHandler works just if one put it just after the download button code (also just if the last one wrapped inside a wellPanel)... But the code works well if isolated just this part.
Other parts of app are still just text/Markdown, and column and tab headers because it is in the draft state...
What is happening when the downloadHandler tries to save a .Rmd and/or html file?
This worked for me:
---
title: "app"
output:
flexdashboard::flex_dashboard:
orientation: columns
vertical_layout: fill
runtime: shiny
---
```{r}
library(flexdashboard)
library(shiny)
library(DT)
splitLayout(cellWidths = c("30%", "70%"),
wellPanel(
downloadButton("downloadData")
),
dataTableOutput("OrigData")
)
output$downloadData<-downloadHandler(
filename = "OriginalData.csv" ,
content = function(file) {
write.csv(mtcars, file=file)
},
contentType="text/csv"
)
output$OrigData <- renderDataTable(mtcars)
```
I am including an answer because I tried to answer the comments and it disappeared...I believe I figured out the answer but it would be an intriguing flexdashboard+downloadHandler behaviour...
As mentioned by #Phil, the isolated code I posted here indeed works, I tried now (sorry for not doing it before)...
I went back to my original code and isolated the corresponding code (with my data). It also works (it downloads correctly the .csv)
The remaining codes were theoretically irrelevant for the problem... including just the remaining code keep the downloadhandler working fine...
The problem appears to be the titles (column, tabs titles - .data-navmenu, .storyboard)... It makes little sense, are them just titles… But I modified the original titles (there were some similar titles) and it also solved the issue… the app stopped trying to save .Rmd or .htm, and started to enable to download .csv…
I believe the downloadHandler() does not work when there are similar column/tab titles in the flexdashboard... Does it make sense? It sounds a bit strange to be the answer for this but worked...

Uploading picture to the knitr document via Shiny

I am using combination of Shiny and knitr to create PDF documents.
Currently I want to add feature that will allow user to upload picture that will be placed within the created document. However, I am really stuck because I am unable to get the path of the input picture. Could anyone help me with that?
Simple example:
Application:
library(knitr)
library(shiny)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
fileInput("picture", label = 'Picture'),
downloadButton('report', label = 'Download PDF')
),
mainPanel()
)
)
server <- function(input,output){
picture <- reactive({
input$picture[,4]
})
output$report = downloadHandler(
filename = "test.pdf",
content = function(file){
picture = picture()
out = knit2pdf(input = 'test.Rnw', compiler = 'xelatex', clean = TRUE)
file.rename(out, file)
},
contentType = 'application/pdf'
)
}
shinyApp(ui = ui, server = server)
and the .Rnw document:
\documentclass{article}
\begin{document}
Put picture here:
<<echo = FALSE , message = F, results='asis'>>=
cat(paste('\\includegraphics[height=3in]{', picture,'}'))
#
\end{document}
Part '\includegraphics[height=3in]{', picture,'} is obviously causing the problem, because I do not know the picture path only temporary one.
You said you were working with Shiny Server, then you should be okay with the full path of the picture, even if it is in a temporary directory (because currently Shiny Server only works on Linux, and LaTeX should be okay with Linux file paths like /tmp/...../yourfile.png). The problem is perhaps the datapath (i.e. input$picture[, 4]) does not have the file extension, so LaTeX could not recognize it. You may try to retrieve the filename extension of the original file, and copy the uploaded picture to a temp file with the same extension, e.g.
picture <- reactive({
path1 <- input$picture$datapath
path2 <- tempfile(fileext = gsub('^(.*)([.].+)$', '\\2', input$picture$name))
file.copy(path1, path2, overwrite = TRUE)
path2
})
i see a solution in two ways:
1) copy the temporary file to a folder of your choice and use that image:
observe({
if (is.null(input$picture)) return()
picture<-"your/final/path/to/disk/uploadImage.jpg" # OR do a PASTE with the PATH and the upload file name
file.copy(input$picture$datapath, picture)
if(file.exists(picture)){
# PROCESS THE IMAGE IF NEEDED
}
picture<<-picture # sometimes needed to R to see the variable outside the observe scope
})
2) if you (in this case the R session) are not allowed to write to disk you can turn the image into a base64 variable and include that into your Knitr document (or save it to a database as a string). This takes the Knitr/HTML route if you are willing to take that detour. (R studio running from a server almost always has a lot of restrictions in reading/writing that you can only handle as an ADMIN. And the server runs the shiny session as RStudio and not you so Rstudio must have the read/write permissions needed if you run the Shiny app as an automatic Rstudio Shiny session and not run it directly form RStudio using RUN)
Make sure the base64 is readable by R ouside the 'observe' or 'if' scope again by using '<<-' together with '<-'. Scoping is quite something special with R so be sure to test it properly.
You should dive into this (base64) with sites like:
https://github.com/yihui/knitr/issues/944
https://github.com/yihui/knitr/blob/master/R/utils-base64.R

Print/save interactive report created using Rmarkdown and Shiny

I have an interactive Rmarkdown document which embeds a few shiny apps that generates graphs based on user inputs.
After I am happy with the graphs generated, I would like to save the report (so that it becomes static).
I have opened the report in my browser (Chrome), and tried printing to pdf. It sort of works, however some figures are cut into two by the page break.
Does anyone know what is the best way to print/save such reports?
I think it's a bit tricky but this is what i use on my app to save html plot on pdf or png format.
Instal wkhtmltopdf
wkhtmltopdf and wkhtmltoimage are open source (LGPLv3) command
line tools to render HTML into PDF and various image formats using the
Qt WebKit rendering engine. These run entirely "headless" and do not
require a display or display service.
Use it in R
This allow you to convert a htmlfile into pdfor img.
In my ShinyApp i use inside a downloadHandler() function somthing like this :
system("wkhtmltopdf --enable-javascript --javascript-delay 2000 plot.html plot.pdf")
I think for your example you could simply convert your html by using :
system("wkhtmltopdf yourFile.html yourFile.pdf")
You can give a download button on the ui.R as:
downloadButton('report', 'Download PDF')
And the corresponding server.R code:
library(knitr)
output$report = downloadHandler(
filename = function() {
paste("Report_", <date/identifier>, ".pdf", sep="")
},
content = function(file) {
rnw <- normalizePath('input.rnw') # assuming you wrote the code to display the graphs etc in this file
owd <- setwd(tempdir())
on.exit(setwd(owd))
file.copy(rnw, 'input.rnw')
out = knit2pdf(rnw, clean=TRUE)
file.rename(out, file)
}
)

rmarkdown shiny user input in chunk?

I have a shiny app that allows the user to download an HTML file (knitted from a .Rmd file) that includes the code used to run the analysis based on all the user inputs. I am trying to write the base .Rmd file that gets altered when user inputs vary. I am having trouble including user input variables (e.g. input$button1) into R code chunks. Say the user input for input$button1 = "text1".
```{r}
results <- someFun(input$button1)
```
And I'd like to have it knitted like this:
```{r}
results <- someFun('text1')
```
Every time I download the knitted HTML though, I get input$button1 getting written to file. I would also like to be able to produce an .Rmd file that is formatted with this substitution. It seems like knit_expand() might be the key, but I can't seem to relate available examples to my specific problem. Is the proper way to knit_expand() the whole .Rmd file and specify explicitly all the parameters you want subbed in, or is there a more elegant way within the .Rmd file itself? I would prefer a method similar to this, except that instead of using the asis engine, I could use the r one. Any help would be greatly appreciated. Thanks!
Got it. Solution below. Thanks to Yihui for the guidance. The trick was to knit_expand() the whole .Rmd file, then writeLines() to a new one, then render. With hindsight, the whole process makes sense. With hindsight.
For the example, p1 is a character param 'ice cream' and p2 is an integer param 10. There is a user-defined param in ui.R called input$mdType that is used to decide on the format provided for download.
Rmd file:
Some other text.
```{r}
results <- someFun("{{p1}}", {{p2}})
```
in the downloadHandler() within server.R:
content = function(file) {
src <- normalizePath('userReport.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, 'userReport.Rmd')
exp <- knit_expand('userReport.Rmd', p1=input$p1, p2=input$p2)
writeLines(exp, 'userReport2.Rmd')
out <- rmarkdown::render('userReport2.Rmd', switch(input$mdType,
PDF = pdf_document(), HTML = html_document(), Word = word_document()))
}
file.rename(out, file)
}
Resulting userReport2.Rmd before rendering:
```{r}
results <- someFun("ice cream", 10)
```

Resources