Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Save plots made in a shiny app

Tags:

r

ggplot2

shiny

I'm trying to figure out how to use downloadButton to save a plot with shiny. The example in the package demonstrates downloadButton/downloadHandler to save a .csv. I'm going to make a reproducible example based on that.

For ui.R

shinyUI(pageWithSidebar(   headerPanel('Downloading Data'),   sidebarPanel( selectInput("dataset", "Choose a dataset:",              choices = c("rock", "pressure", "cars")),     downloadButton('downloadData', 'Download Data'),     downloadButton('downloadPlot', 'Download Plot')   ),   mainPanel(     plotOutput('plot')   ) )) 

For server.R

library(ggplot2) shinyServer(function(input, output) {   datasetInput <- reactive({     switch(input$dataset,            "rock" = rock,            "pressure" = pressure,            "cars" = cars)   })      plotInput <- reactive({     df <- datasetInput()     p <-ggplot(df, aes_string(x=names(df)[1], y=names(df)[2])) +       geom_point()   })      output$plot <- renderPlot({     print(plotInput())   })      output$downloadData <- downloadHandler(     filename = function() { paste(input$dataset, '.csv', sep='') },     content = function(file) {       write.csv(datatasetInput(), file)     }   )   output$downloadPlot <- downloadHandler(     filename = function() { paste(input$dataset, '.png', sep='') },     content = function(file) {       ggsave(file,plotInput())     }   ) }) 

If you're answering this question, you are probably familiar with this, but to get this working, save the above into separate scripts (ui.R and server.R into a folder (foo) within the working directory. To run the shiny app, run runApp("foo").

Using ggsave, I get an error message indicating that ggsave can't use the filename function (I think). If I use the standard graphics device (like below), the Download Plot works without an error, but it doesn't write the graphic.

Any tips to get downloadHandler working for writing plots would be appreciated.

like image 463
alexwhan Avatar asked Feb 11 '13 10:02

alexwhan


People also ask

Which function is used to create the shiny app?

shinyApp. Finally, we use the shinyApp function to create a Shiny app object from the UI/server pair that we defined above. We save all of this code, the ui object, the server function, and the call to the shinyApp function, in an R script called app. R .


2 Answers

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")     } ) 
like image 134
sebkopf Avatar answered Oct 07 '22 19:10

sebkopf


I didn't manage to make it work with ggsave, but with a standard call to png() it seems to be okay.

I only changed the output$downloadPlot part of your server.R file :

 output$downloadPlot <- downloadHandler(     filename = function() { paste(input$dataset, '.png', sep='') },     content = function(file) {       png(file)       print(plotInput())       dev.off()     }) 

Note that I had some problems with the 0.3 version of shiny, but it works with the latest from Github :

library(devtools) install_github("shiny","rstudio") 
like image 29
juba Avatar answered Oct 07 '22 18:10

juba