How to save plots that are made in a shiny app
Not sure if this question is still active but it's the first one that came up when searching for "saving plots in shiny app" so I wanted to quickly add how to get ggsave to work with downloadHandler along the lines of the original question.
The alternative strategies suggested by juba using direct output instead of ggsave and alternative strategy suggested by alexwhan himself both work great, this is just for those who absolutely want to use ggsave in the downloadHandler).
The problem reported by alexwhan is caused by ggsave trying to match the file extension to the correct graphics device. The temporary file, however, doesn't have an extension so the matching fails. This can be remedied by specifically setting the device in the ggsave
function call, like so in the original code example (for a png):
output$downloadPlot <- downloadHandler(
filename = function() { paste(input$dataset, '.png', sep='') },
content = function(file) {
device <- function(..., width, height) grDevices::png(..., width = width, height = height, res = 300, units = "in")
ggsave(file, plot = plotInput(), device = device)
}
)
This call basically takes the device
function for a png
that ggsave
assigns internally (you can look at the ggsave
function code to see the syntax for jpg
, pdf
, etc). Perhaps, ideally, one could specify the file extension (if different from the file name - as is the case here for the temporary file) as a ggsave
parameter but this option is currently not available in ggsave
.
A minimal self-contained working example:
library(shiny)
library(ggplot2)
runApp(list(
ui = fluidPage(downloadButton('foo')),
server = function(input, output) {
plotInput = function() {
qplot(speed, dist, data = cars)
}
output$foo = downloadHandler(
filename = 'test.png',
content = function(file) {
device <- function(..., width, height) {
grDevices::png(..., width = width, height = height,
res = 300, units = "in")
}
ggsave(file, plot = plotInput(), device = device)
})
}
))
sessionInfo()
# R version 3.1.1 (2014-07-10)
# Platform: x86_64-pc-linux-gnu (64-bit)
#
# locale:
# [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
# [3] LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8
# [5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
# [7] LC_PAPER=en_US.UTF-8 LC_NAME=C
# [9] LC_ADDRESS=C LC_TELEPHONE=C
# [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
#
# attached base packages:
# [1] stats graphics grDevices utils datasets methods base
#
# other attached packages:
# [1] ggplot2_1.0.0 shiny_0.10.1
#
# loaded via a namespace (and not attached):
# [1] bitops_1.0-6 caTools_1.17 colorspace_1.2-4 digest_0.6.4
# [5] formatR_1.0 grid_3.1.1 gtable_0.1.2 htmltools_0.2.6
# [9] httpuv_1.3.0 labeling_0.2 MASS_7.3-34 munsell_0.4.2
# [13] plyr_1.8.1 proto_0.3-10 Rcpp_0.11.2 reshape2_1.4
# [17] RJSONIO_1.3-0 scales_0.2.4 stringr_0.6.2 tools_3.1.1
# [21] xtable_1.7-3
Update
As of ggplot2 version 2.0.0, the ggsave
function supports character input for the device
parameter, that means the temporary file created by the downloadHandler can now be saved with a direct call to ggsave
by specifying that the extension to be used should be e.g. "pdf"
(rather than passing in a device function). This simplifies the above example to the following
output$downloadPlot <- downloadHandler(
filename = function() { paste(input$dataset, '.png', sep='') },
content = function(file) {
ggsave(file, plot = plotInput(), device = "png")
}
)
Downloadhander (save plot) for basic plot in shiny
You can write it on a png
object using device graphics. Check the code.
library(shiny)
library(ggplot2)
# ui
ui <- fluidPage(
downloadButton("save", "save")
)
# server
server <- function(input, output){
p <- reactive({ggplot(iris, aes(Sepal.Length, Sepal.Width)) + geom_point()})
p2 <- reactive({dotchart(iris$Sepal.Length, iris$Species, iris$Species)})
output$save <- downloadHandler(
file = "save.png" , # variable with filename
content = function(file) {
#ggsave(p(), filename = file)
png(file = file)
p2()
dev.off()
})
}
# run
shinyApp(ui, server)
Save reactive plot to temp directory as png from shiny app
There is no need to save a temporary png file. We can use recordPlot
instead:
library(shiny)
library(datasets)
writeLines(con = "report.Rmd", text = "---
title: 'Plot report'
output: html_document
params:
plot_object: NA
---
```{r plotout, echo=FALSE, message=FALSE, out.width='100%'}
params$plot_object
```")
ui = fluidPage(
plotOutput("plot1"),
downloadButton("report_button", "Generate report")
)
server = function(input, output, session) {
reactivePlot1 <- reactive({
plot(mtcars$wt, mtcars$mpg)
recordPlot()
})
output$plot1 <- renderPlot({
reactivePlot1()
})
output$report_button <- downloadHandler(
filename = "report.html",
content = function(file) {
tempReport <- tempfile(fileext = ".Rmd") # make sure to avoid conflicts with other shiny sessions if more params are used
file.copy("report.Rmd", tempReport, overwrite = TRUE)
rmarkdown::render(tempReport, output_format = "html_document", output_file = file, output_options = list(self_contained = TRUE),
params = list(plot_object = reactivePlot1())
)
}
)
}
shinyApp(ui, server)
Please see my related answer here.
After OPs update - using dummy data:
app.R:
library(shiny)
library(radarchart)
scores <- data.frame("Label"=c("Communicator", "Data Wangler", "Programmer",
"Technologist", "Modeller", "Visualizer"),
"Rich" = c(9, 7, 4, 5, 3, 7),
"Andy" = c(7, 6, 6, 2, 6, 9),
"Aimee" = c(6, 5, 8, 4, 7, 6))
ui = fluidPage(
chartJSRadarOutput("radar", width = "450", height = "300"),
downloadButton("report", "Generate report")
)
server = function(input, output, session) {
reactiveRadar <- reactive({
chartJSRadar(scores, maxScale = 10, showToolTipLabel=TRUE)
})
# plot: Radarplot ------
output$radar <- renderChartJSRadar({
reactiveRadar()
})
# create markdown report with radar plot ----------------------------------
output$report <- downloadHandler(
filename = "report.html",
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 = "Test", plot_object = reactiveRadar()) # scores = PSA_13()[,c(1,2,6)]
rmarkdown::render(tempReport, output_file = file,
params = params,
envir = new.env(parent = globalenv())
)
}
)
}
shinyApp(ui, server)
report.Rmd:
---
geometry: margin=20truemm
fontfamily: mathpazo
fontsize: 11pt
documentclass: article
classoption: a4paper
urlcolor: blue
output:
html_document
header-includes:
- \usepackage{fancyhdr}
- \pagestyle{fancy}
# - \rhead{\includegraphics[width = .05\textwidth]{logo.png}}
params:
scores: NA
plot_object: NA
---
\pagenumbering{gobble}
```{r setup, include=FALSE}
knitr::opts_chunk$set()
library(draw)
```
```{r rectangle, echo=FALSE}
drawBox(x =1.3, y = 3.7, width = 2.5, height = 1)
```
\vspace{-80truemm}
```{r plotout, echo=FALSE, message=FALSE, out.width='100%'}
params$plot_object
```
download a plot without replotting in R shiny
Use the ggplot2::last_plot
function:
library(shiny)
library(ggplot2)
k <- 0
runApp(list(
ui = fluidPage(
plotOutput("fooplot"),
textOutput("fook"),
downloadButton('foo')
),
server = function(input, output) {
plotInput = function() {
k <<- k + 1
qplot(speed, dist, data = cars)
}
output$fooplot <- renderPlot({
plotInput()
})
output$fook <- renderPrint({
k
})
output$foo = downloadHandler(
filename = 'test.png',
content = function(file) {
device <- function(..., width, height) {
grDevices::png(..., width = width, height = height,
res = 300, units = "in")
}
ggsave("myplot.png", plot = last_plot(), device = device)
})
}
))
Forgive the use of the global assignment, just including to show that the plotInput
is not called twice.
How to download plots made in a shiny app(in a jpeg /png format )
I would suggest you to use Highcharter package. This way you don't need to create a download button, because the chart has options to download in several extensions. Here I give you an example of an histogram, choosing to export in PNG, SVG, JPEG or PDF.
## Export charts with Highcharter in Shiny
# Load package
library('highcharter')
# UI side
highchartOutput('plot')
# Server side
output$plot <- renderHighchart({
# Define your data, here I am using Iris dataset as example
DT <- iris$Sepal.Length
# Define export options
export <- list(
list(
text = "PNG",
onclick = JS("function () {
this.exportChart({ type: 'image/png' }); }")
),
list(
text = "JPEG",
onclick = JS("function () {
this.exportChart({ type: 'image/jpeg' }); }")
),
list(
text = "SVG",
onclick = JS("function () {
this.exportChart({ type: 'image/svg+xml' }); }")
),
list(
text = "PDF",
onclick = JS("function () {
this.exportChart({ type: 'application/pdf' }); }")
)
)
# Plot histogram
hchart(DT,
type = "area",
name = colnames(iris[1])
) %>%
hc_exporting(
enabled = TRUE,
formAttributes = list(target = "_blank"),
buttons = list(contextButton = list(
text = "Export",
theme = list(fill = "transparent"),
menuItems = export
))
)
})
The output should be something like this:
Hope this helps.
Wlademir.
Save a ggplot generated scatterplot in Shiny as a PDF file without saving extra files
I finally came out with an obvious answer. I wasn't doing the straightforward thing that was call the ggsave in the downloadHandler call because I was using the Yihui answer directly. So, finally I just don't create the file inside the renderPlot() function, but in the downloadHandler where it rightfully should be.
# Create the scatterplot object the plotOutput function is expecting
output$scatterplot <- renderPlot({
makeScatPlot()
})
# Create the button to download the scatterplot as PDF
output$dlScatPlot <- downloadHandler(
filename = function() {
paste('scatterPlot_', Sys.Date(), '.pdf', sep='')
},
content = function(file) {
ggsave(file, makeScatPlot(), width = 11, height = 4, dpi = 300, units = "in")
}
)
Using the above code, everything (including the nearPoints call) works now :)
How to have shiny app save gt ouput as an .RFT file on the users browser?
downloadHandler()
was the solution
library(data.table)
library(shiny)
library(gt)
library(shinyscreenshot)
data <- datasets::mtcars
setDT(data, keep.rownames = TRUE)[]
ui <- navbarPage("Save this to RTF",
tabPanel("Table", icon = icon("table"),
sidebarLayout(
sidebarPanel(
selectInput("input",
label = "Choose # of cyl",
choices = c("All", data$cyl)),
screenshotButton(selector="#table", label = 'Download Png', filename = 'screenshot'),
downloadButton('downloadData', 'Download RTF')
),
mainPanel(
gt_output("table")
)
)
)
)
server <- function(input, output, session) {
reactive_tab <- reactive({
d <- data
if(input$input != "All")
d <- subset(d, cyl == input$input)
d
})
output$table <- render_gt(
reactive_tab() %>% gt()
)
output$downloadData <- downloadHandler(
filename = paste0("gttable-",Sys.Date(),".rtf"),
content = function(file){
gtsave(reactive_tab() %>% gt(),
file)
}
)
# observeEvent(input$downloadData,{
# gtsave(reactive_tab() %>% gt(),
# paste0(Sys.Date(),".rtf"))
# })
#
}
shinyApp(ui, server)
Related Topics
Calculate Cumulative Sum (Cumsum) by Group
How to Merge 2 Vectors Alternating Indexes
Split Date-Time Column into Date and Time Variables
How to Extract Plot Axes' Ranges For a Ggplot2 Object
Geom_Rect and Alpha - Does This Work With Hard Coded Values
How to Get Week Numbers from Dates
R - Concatenate Two Dataframes
Don't Drop Zero Count: Dodged Barplot
How to Load Packages in R Automatically
Special Variables in Ggplot (..Count.., ..Density.., etc.)
Concatenate Strings by Group With Dplyr
Ggplot2 Two-Line Label With Expression
Replace Missing Values With Column Mean
Merge Two Data Frames While Keeping the Original Row Order