I have a shiny application where I return two chart in a reactive element. Then I pass the two charts as params to my rmarkdown file. I can't resize them nor print them side by side with download button.
Here is my rmarkdown code
---
# always_allow_html: true
output:
html_document
params:
plot_1: 'NULL'
plot_2: 'NULL'
---
{r setup, include=FALSE}
options(tinytex.verbose = TRUE)
knitr::opts_chunk$set(echo = FALSE, fig.retina = 1)
library(webshot)
{r, figures-side, fig.show="hold", out.width="50%", echo=FALSE}
# plot_1()
params$plot_1
params$plot_2
this is my download script:
output$download <- downloadHandler(
filename = "new_report.pdf",
content = function(file) {
tempReport <- normalizePath('report.Rmd')
file.copy("myRmarkdown.Rmd", tempReport, overwrite = TRUE)
params <- list(plot_1=plot_1()
,plot_2=plot_2()
)
html_fn <- rmarkdown::render(tempReport, params = params,
envir = new.env(parent = globalenv()))
pagedown::chrome_print(html_fn, file)
}
)
Is there any way to arrange plots in params side by side?
Here is the actual output:
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 have a bunch of pre-saved plots inside a folder.
I have a Rmarkdown(Flexdashboard) looping this folder and showing a picture per tab this way (an example taking just one)
```{r ,results="asis"}
list_plots <- list.files(plots_folder,pattern = ".png", full.names = TRUE)
cat(" \n###", "Tab Name \n")
knitr::include_graphics(list_plots[1])
cat(" \n")
```
this worked flawlessly. My issue is when using a loop. The tabs are rendered but no plot inside. This way:
```{r ,results="asis"}
list_plots <- list.files(plots_folder,pattern = ".png", full.names = TRUE)
for(i in plots) {
cat(" \n###", "tab name \n")
knitr::include_graphics(i)
cat(" \n")
}
```
Similarly to this, I'll drop here a fully reproducible code for flexdashboard:
---
title: "Test"
output:
flexdashboard::flex_dashboard:
orientation: columns
vertical_layout: fill
---
```{r setup, include=FALSE}
library(flexdashboard)
```
```{r create plots}
# reproducible example
tmp <- tempdir()
x <- lapply(5:10, function(x){
png(file.path(tmp, paste0(x,".png")))
plot(seq(x))
dev.off()
})
```
```{r, results='asis'}
list_plots <- list.files(tmp, pattern = ".png", full.names = TRUE)
for(i in list_plots) {
cat(sprintf("\n### tab name\n![](%s)\n", i))
}
```
I've created ShinyApp where everything works fine. I'd like to add downloadHandler to generate Markdown report that contains the chosen plot. Firstly, I upload a file into ShinyApp. Nextly, I select variables to be plotted using checkBoxInput. Next step is using dropdown list to select between Lattice/ggplot2 plot and finally I'd like to click download it and get it.
Unfortunately, every time I do try to download it I receive a blank Markdown page. It doesn't really matter what format of report will be generated. I'd like to get an appropiate logic for this task. I tried both solutions I found in a network:
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')
owd <- setwd(getwd())
on.exit(setwd(owd))
file.copy(src, 'report.Rmd', overwrite = TRUE)
out <- render('report.Rmd', switch(
input$format,
PDF = pdf_document(), HTML = html_document(), Word = word_document()
))
file.rename(out, file)
})
and
output$report <- downloadHandler(
filename = "report.html",
content = function(file) {
tempReport <- file.path(getwd(), "report.Rmd")
file.copy("report.Rmd", tempReport, overwrite = TRUE)
params <- list(graph = input$graph, colsel = input$colsel)
rmarkdown::render(tempReport, output_file = file,
params = params,
envir = new.env(parent = globalenv())
So respectively I created report.rmd templates for my app to fullfill it. I tried to put a lot of things inside but none of these works. Do I miss the logic for the template?
---
title: "Untitled"
author: "user"
date: "date"
output: html_document
runtime: shiny
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
```{r plot, echo=TRUE}
plotdata <- reactive({
d <- dataIn()[, c(req(input$colsel))]
d <- melt(d, id.vars="Numer")
})
plot1 <- reactive({
dotplot(value~Numer, data=plotdata(), auto.key = list(space="right", title="Types"), groups=variable)
})
plot2 <- reactive({
ggplot(plotdata(), aes(x=Numer, y=value, color=variable)) +
geom_point()
})
graphInput <- reactive({
switch(input$graph,
"Lattice" = plot1(),
"ggplot2" = plot2())
})
renderPlot({
graphInput()
})
})
```
Alright, I got it finally! Firstly, we need to run shinyApp using function "Run External". Secondly we don't need that mess I made in the template. Simple:
---
title: "Untitled"
author: "user"
date: "date"
output: html_document
runtime: shiny
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
library(shiny)
library(ggplot2)
library(lattice)
library(markdown)
```
```{r plot}
plot1()
plot2()
graphInput()
```
Where plot1(), plot2() and graphinput() represent my:
plot1 <- reactive({
dotplot(value~Numer,data=plotdata(), auto.key = list(space="right", title="WWW"), groups=variable)
})
plot2 <- reactive({
ggplot(plotdata(), aes(x=Numer, y=value, color=variable)) +
geom_point()
})
graphInput <- reactive({
switch(input$graph,
"Lattice" = plot1(),
"ggplot2" = plot2()
)
})
I have a shiny markdown app in which I have several figures, say for different days of the week. Above these figures is a text area where I write some comments.
I want to be able to export this report to a static markdown format.
I'm presenting a (mainly) reproducible example below, the first part is the code that I would like to have edited so that it creates the code from the second part in a separate file.
---
title: "WEEKLY REPORT"
runtime: shiny
output: html_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = F)
```
```{r header, echo=FALSE}
selectInput("x", label = "x",choices = 1:10,width="100%")
actionButton("button", "Export report")
```
## Monday
```{r monday}
textAreaInput("mon", label = NULL)
renderPlot({
plot(log(1:input$x))
})
```
## Tuesday
```{r tuesday}
textAreaInput("tue", label = NULL)
renderPlot({
plot(sin(1:input$x))
})
```
How can I edit it so the action button creates a new a Rmd file containing the code below (or an Rmd file that would create a similar output)? (change png urls to any existing file to make it reproducible).
---
# title: "WEEKLY REPORT"
output: html_document
---
## Monday
The text I would have put on the first box
![](plot_monday.png)
## Tuesday
The text I would have put on the second box
![](plot_tuesday.png)
So basically the input selectors have to go, the text areas need to be changed to standard text (possibly containing markdown), and the plots have to be exported as picture files for the relevant inputs and then inserted back as pictures in the report.
Ideally I would also like to be able to export monday and tuesday into different Rmd files.
I think the easiest is to use a report template and pass in the inputs as parameters.
So, you create a new report with the filename "sampleRmdReport.Rmd" in the same directory as your Shiny report with the following contents:
---
title: "Weekly Report"
author: "Moody_Mudskipper"
date: '`r format(Sys.Date(),"%Y-%B-%d")`'
output: html_document
params:
mondayText: "holder"
tuesdayText: "holder"
x: "holder"
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE, results = "asis")
```
# Monday
```{r}
cat(params$mondayText)
```
```{r}
plot(log(1:params$x))
```
# Tuesday
```{r}
cat(params$tuesdayText)
```
```{r}
plot(sin(1:params$x))
```
Then, add the following to your Shiny report:
Download the weekly report:
```{r}
downloadHandler(
filename = function(){
paste0("weeklyReport_generated_"
, format(Sys.Date(), "%Y%b%d")
, ".html")
}
, content = function(file){
rmarkdown::render(input = "sampleRmdReport.Rmd"
, output_file = file
, params = list(mondayText = input$mon
, tuesdayText = input$tue
, x = input$x
))
}
, contentType = "text/html"
)
```
making the full file:
---
title: "WEEKLY REPORT"
runtime: shiny
output: html_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = F)
```
```{r header}
selectInput("x", label = "x",choices = 1:10,width="100%")
```
Download the weekly report:
```{r}
downloadHandler(
filename = function(){
paste0("weeklyReport_generated_"
, format(Sys.Date(), "%Y%b%d")
, ".html")
}
, content = function(file){
rmarkdown::render(input = "sampleRmdReport.Rmd"
, output_file = file
, params = list(mondayText = input$mon
, tuesdayText = input$tue
, x = input$x
))
}
, contentType = "text/html"
)
```
## Monday
```{r monday}
textAreaInput("mon", label = NULL)
renderPlot({
plot(log(1:input$x))
})
```
## Tuesday
```{r tuesday}
textAreaInput("tue", label = NULL)
renderPlot({
plot(sin(1:input$x))
})
```
Then, clicking on the "Download" button will generate the report and prompt the user to download it. Note that if you test in RStudio, the file name won't work. I suggest opening it in the browser to test that.
Then, if you want to be able to generate separate daily reports, just add a template for the report you want and a download button for each. Or, you can make your downloadHandler generate a report for each day (from templates) and put them in a zipped directory to download together.
(Note: I tend to find this is more flexible in a Shiny App than in a markdown document, particularly as that allows more control of the download button. Depending on your use case, it may be worth considering that as an approach.)
Based on the comments, here is a version that would upload to Imgur and insert the images that way. Replace the other template with this or add a second button. Note that I did not make the imgur upload function work because I do not have an API key (I assume you do, since you are planning to do it this way).
---
title: "Weekly Report"
author: "Moody_Mudskipper"
date: '`r format(Sys.Date(),"%Y-%B-%d")`'
output:
html_document:
self_contained: false
params:
mondayText: "holder"
tuesdayText: "holder"
x: 1
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE, results = "asis")
library(ggplot2)
tempDir <- tempdir()
uploadImgur <- function(fileName){
# This function would need to upload with the Imgur API
# I don't have a key, and don't want to set one up
# for this example.
# It would return the url that imgur assigns the image
# here, I am using a placeholder
outUrl <- "https://i.imgur.com/WsUV4DK.gif"
return(outUrl)
}
```
# Monday
```{r}
cat(params$mondayText)
```
```{r}
tempPlot <-
ggplot(mapping = aes(x = 1:params$x
, y = log(1:params$x))) +
geom_point() +
xlab("X") +
ylab("Y")
tempFile <- tempfile("plot_", tempDir, ".png")
ggsave(tempFile, tempPlot, width = 4, height = 4)
imgurURL <- uploadImgur(tempFile)
cat("![](", imgurURL,")", sep = "")
```
# Tuesday
```{r}
cat(params$tuesdayText)
```
```{r}
tempPlot <-
ggplot(mapping = aes(x = sin(1:params$x)
, y = log(1:params$x))) +
geom_point() +
xlab("X") +
ylab("Y")
tempFile <- tempfile("plot_", tempDir, ".png")
ggsave(tempFile, tempPlot, width = 4, height = 4)
imgurURL <- uploadImgur(tempFile)
cat("![](", imgurURL,")", sep = "")
```
If you are ok with using ggplot you can use ggsave to save the plots locally as png.
You could try this for your main file:
---
title: "WEEKLY REPORT"
runtime: shiny
output: html_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = F)
library(ggplot2)
```
```{r header, echo=FALSE}
selectInput("x", label = "x",choices = 1:10,width="100%")
actionButton("button", "Export report")
observeEvent(input$button,{
params <- list(text = input$mon)
render('report.Rmd',params = params)
})
```
## Monday
```{r monday}
textAreaInput("mon", label = NULL)
renderPlot({
p <- ggplot(data.frame(x=1:input$x,y=log(1:input$x)),aes(x=x,y=y))+
geom_point()
ggsave("plot.png",plot=p)
p
})
```
And for your static report (needs to be in the same folder as the other .Rmd):
---
# title: "WEEKLY REPORT"
output: html_document
---
## Monday
```{r}
params$text
```
![plot](plot.png)
I'm not sure how to make a proper download button with a download handler in a shiny Rmd so this only works when run from RStudio and not in a browser.
I have a big shiny app and I'm making a downloadable pdf with rmarkdownfrom the content in it. The problem I'm having is that all the plots are in plotlyand I haven't found how to plot 2 plots in the same row of the pdf file, in R it would be a simple subplot but it doesn't work.
This is a toy example of what I have:
shinyApp(
ui = fluidPage(
downloadButton("reporte", "Generate report"),
plotlyOutput("plotTest"),
plotlyOutput("plotHist")
),
server = function(input, output) {
library(webshot)
data = as.data.frame(rnorm(1000))
plotTest = plot_ly(y = ~rnorm(1000),type = "scatter",mode = "lines")
plotHist = plot_ly(x = ~rnorm(1000),type = "histogram")
output$plotTest = renderPlotly({plotTest})
output$plotHist = renderPlotly({plotHist})
output$reporte <- downloadHandler(
filename = "reporte.pdf",
content = function(file) {
tempReport <- file.path("C:/Users/Alejandro/Documents/test", "report.Rmd")
file.copy("report.Rmd", tempReport, overwrite = TRUE)
params <- list(n=plotTest,k=plotHist)
rmarkdown::render(tempReport, output_file = file,
params = params,
envir = new.env(parent = globalenv())
)
}
)
}
)
report.Rmd:
---
title: "Ensayo Reporte"
output: pdf_document
always_allow_html: yes
params:
n: NA
k: NA
---
```{r,echo=FALSE}
library(plotly)
tmpFile <- tempfile(fileext = ".png")
export(params$n, file = tmpFile)
export(params$k, file = tmpFile)
```
Adding the ususal fig.align='center',fig.show='hold' doesn't work i'll just get: Warning: Error in : pandoc document conversion failed with error 43