I'd like to add a plotly plot to a pdf file. This should be done locally (without plotly_IMAGE). Unfortunately I do not have access to webshot (since I do not have the rights to install PhantomJS). Therefore I tried a workaround described here: https://github.com/ropensci/plotly/issues/311 using shiny gadgets. But I wanted to adapt it such that the copying is doen without clicking done in the gadget.
All my attempts (see below) failed because I was not able to delay the downloadHandler until the copying was done.
Any suggestions how the dresired result (copy plotly-Image as png first and use it in pdf-Export afterwards) all done sequentially after click on Download Button?
ui:
library(shiny)
library(plotly)
library(rsvg)
shinyUI(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'),
tags$script('
document.getElementById("downloadReport").onclick = function() {
var plotly_svg = Plotly.Snapshot.toSVG(
document.querySelectorAll(".plotly")[0]
);
Shiny.onInputChange("plotly_svg", plotly_svg);
};
')
),
mainPanel(
plotlyOutput('regPlot')
)
)
))
server:
library(shiny)
library(plotly)
library(rsvg)
shinyServer(function(input, output, session) {
output$regPlot <- renderPlotly({
library(plotly)
set.seed(100)
d <- diamonds[sample(nrow(diamonds), 1000), ]
print("render")
p <- plot_ly(d, x = carat, y = price, text = paste("Clarity: ", clarity),
mode = "markers", color = carat, size = carat)
p
})
observeEvent(input$plotly_svg, priority = 10, {
png_gadget <- tempfile(fileext = ".png")
png_gadget <- "out.png"
print(png_gadget)
rsvg_png(charToRaw(input$plotly_svg), png_gadget)
})
output$downloadReport <- downloadHandler(
filename = function() {
paste('my-report', sep = '.', switch(
input$format, PDF = 'pdf', HTML = 'html', Word = 'docx'
))
},
content = function(file) {
src <- normalizePath('testreport.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, 'testreport.Rmd')
library(rmarkdown)
out <- render('testreport.Rmd', params = list(region = "Test"), switch(
input$format,
PDF = pdf_document(), HTML = html_document(), Word = word_document()
))
file.rename(out, file)
}
)
})
Related
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'm trying to convert a part of my Rshiny in Rmarkdown, but when i try to run this example i get an error, how can i handle it?
this code is part of an example of Rshiny app, but when i try to run something is wrong
or could you help me to find some script to print some tables and graphs from Rshiny into Rmarkdown?
Aserver <-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)
}
)
}
Aui <- 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')
)
)
)
shinyApp(Aui, Aserver)
this is the error
Warning: Error in abs_path: The file 'report.Rmd' does not exist.
[No stack trace available]
Thanks
You should distinghish two paths:
the path where the application is installed/running
the path where you are going to download the result of knitting the Markdown doc
You can get the path where the application is running with getwd().
If you don't explicitly specify a path, the report.Rmd should be located on the same directory as the application so that the application can use it.
Make sure Report.Rmd is in getwd() directory, or specify the path of Report.Rmd :
render(file.path('/custom/directory','report.Rmd'), ...
The shiny app below is taken out of gallery. It allow user to choose a variable, build a linear regression and download report.
What if I do not know in advance how many plots and models user wants to build and include into report. Is it possible to create a report with dynamically added plots?
Server.R
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)
}
)
}
ui.R
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')
)
)
)
report.Rmd
Here is my regression model:
```{r model, collapse=TRUE}
options(digits = 4)
fit <- lm(regFormula(), data = mtcars)
b <- coef(fit)
summary(fit)
```
The fitting result is $mpg = `r b[1]` + `r b[2]``r input$x`$.
Below is a scatter plot with the regression line.
```{r plot, fig.height=5}
par(mar = c(4, 4, 1, 1))
plot(regFormula(), data = mtcars, pch = 19, col = 'gray')
abline(fit, col = 'red', lwd = 2)
```
Well, it looks like I have found the answer. The problem was in local/global variables. I had to put list initialisation outside server function. Also I had to use <<- instead of <- to assign new element to the plot rather than create new plot every time.
Many thanks to Peter Ellis to support!
So, the solution is (I have slightly changed initial code to focus on the important part):
server.R
library(ggplot2); library(shiny); library(grid); library(gridExtra)
plist <- list() # IMPORTANT - outside server function
shinyServer(function(input, output) {
output$regPlot <- renderPlot({
p <- do.call("grid.arrange", c(plotList(),
ncol=floor(sqrt(length(plotList())+1)),
top = "test"))
})
plotList <- eventReactive(input$plt2rprt, {
p <- ggplot(data = mtcars, aes_string(x = input$x, y = "mpg")) +
geom_point()
# isolate(
plist[[length(plist)+1]] <<- p #IMPORTATNT <<- instead of <-
# )
return(plist)
})
output$lengthOfList <- renderText({length(plotList())})
output$lll <- renderText({length(plist)})
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(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)
}
)
}) #ShinyServer
ui.R
fluidPage(
title = 'Download a PDF report',
sidebarLayout(
sidebarPanel(
helpText(),
selectInput('x', 'Build a regression model of mpg against:',
choices = names(mtcars)[-1]),
actionButton("plt2rprt", label = "Include into report"),
hr(),
radioButtons('format', 'Document format', c('PDF', 'HTML', 'Word'),
inline = TRUE),
downloadButton('downloadReport')
),
mainPanel(
plotOutput('regPlot'),
#verbatimTextOutput("count"),
hr(),
textOutput("lengthOfList"),
textOutput("lll"),
helpText("test-test-test")
)
)
)
report.Rmd
Length of list of plots `r length(plotList())`
```{r plot, fig.height=5}
do.call("grid.arrange", c(plotList(),
ncol=floor(sqrt(length(plotList())+1)),
top = "test"))
```
I would like to download Report within Shiny App, which includes Plotly graph.
So far i have not found any answer on stackoverflow.
Till this moment im able to download the screenshot of Plotly but it appears only in my working directory and it is not sent to Rmarkdown.
Example code:
library(shiny)
library(plotly)
library(rsvg)
library(ggplot2)
d <- data.frame(X1=rnorm(50,mean=50,sd=10),X2=rnorm(50,mean=5,sd=1.5),Y=rnorm(50,mean=200,sd=25))
ui <-fluidPage(
title = 'Download report',
sidebarLayout(
sidebarPanel(
helpText(),
radioButtons('format', 'Document format', c('PDF', 'HTML', 'Word'),
inline = TRUE),
downloadButton('downloadReport'),
tags$script('
document.getElementById("downloadReport").onclick = function() {
var plotly_svg = Plotly.Snapshot.toSVG(
document.querySelectorAll(".plotly")[0]
);
Shiny.onInputChange("plotly_svg", plotly_svg);
};
')
),
mainPanel(
plotlyOutput('regPlot')
)
)
)
server <- function(input, output, session) {
output$regPlot <- renderPlotly({
p <- plot_ly(d, x = d$X1, y = d$X2,mode = "markers")
p
})
observeEvent(input$plotly_svg, priority = 10, {
png_gadget <- tempfile(fileext = ".png")
png_gadget <- "out.png"
print(png_gadget)
rsvg_png(charToRaw(input$plotly_svg), png_gadget)
})
output$downloadReport <- downloadHandler(
filename = function() {
paste('my-report', sep = '.', switch(
input$format, PDF = 'pdf', HTML = 'html', Word = 'docx'
))
},
content = function(file) {
src <- normalizePath('testreport.Rmd')
owd <- setwd(tempdir())
on.exit(setwd(owd))
file.copy(src, 'testreport.Rmd')
library(rmarkdown)
out <- render('testreport.Rmd', params = list(region = "Test"), switch(
input$format,
PDF = pdf_document(), HTML = html_document(), Word = word_document()
))
file.rename(out, file)
}
)
}
shinyApp(ui = ui, server = server)
and testreport.Rmd file:
---
title: "test"
output: pdf_document
params:
name: "Test"
region: 'NULL'
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
Any help would be appreciated, because there is not many sources and documentations about R Plotly.
Cheers
If out.png is downloaded to your working directory, you can modify the content function of your downloadHandler to move it to the temporary directory and add it to the report:
content = function(file) {
temp_dir <- tempdir()
tempReport <- file.path(temp_dir, 'testreport.Rmd')
tempImage <- file.path(temp_dir, 'out.png')
file.copy('testreport.Rmd', tempReport, overwrite = TRUE)
file.copy('out.png', tempImage, overwrite = TRUE)
library(rmarkdown)
out <- render(tempReport, params = list(region = "Test"), switch(
input$format,
PDF = pdf_document(), HTML = html_document(), Word = word_document()
))
file.rename(out, file)
}
Your testreport.Rmd could look like (more info here):
---
title: "test"
---
Here's the plot image.
![Plot image](out.png)
You could also pass the arguments of your plotly function in the render of your content function as explained here and use a parametrized Rmarkdown file but this only works for Html reports.
Depending on how deep you want to dive into this, I would suggest creating a .brew file with your shiny code and than you can have your user send the information to the brew file and create the plot. This would give you a static code file which is updated dynamically with new data, each time. The only draw back is that when you make changes to shiny you have to make the same changes to your brew file. The other option is to create a flex dashboard with rmarkdown using the new RStudio 1.0 which becomes a html file.
See (Create parametric R markdown documentation?) for brew example.
I created a R shiny application for stats analyses. I'd like that app allowed users to download a word report. I use the code on the shiny website gallery - http://shiny.rstudio.com/gallery/download-knitr-reports.html.
Server
shinyServer(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')
library(rmarkdown)
out <- render('report.Rmd', switch(
input$format,
PDF = pdf_document(), HTML = html_document(), Word = word_document()
))
file.rename(out, file)
}
)
})
UI
library(shiny)
shinyUI(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')
)
)
))
It works fine and I can download the report on the web app. I use the proposed code in R studio on a OS X computer and it works fine too. I try to do the same with R studio on a win 7 computer but it doesn't works, the report (html, pdf or docx) is not created whereas the apps works fine.
Can someone help me ?
Ari