Download button to download SVG images of my ggplot in Shiny? [min reprex]

How can I get a download button to actually download a ggplot .SVG image in Shiny? This solution isn't quite working:

(modified from an old thread)

library(ggplot2)
library(shiny)

ui <- fluidPage(
  plotOutput("plot"),
  downloadButton("savePlot")
)

server <- shinyServer(function(input, output, session) {
  values <- reactiveValues(
    plot = NULL
  )
  values$plot<-  qplot(clarity, data=diamonds, fill=cut, geom="bar")
  output$plot<- renderPlot(values$plot)
  observeEvent(input$savePlot, {
    image=values$plot
    ggsave(file="test.svg", plot=image, width=10, height=8)
  })
})

shinyApp(ui, server)

I think you are treating downloadButton just as if it was an actionButton, and you are having the press of it, trigger an observe event that writes an test.sgv to the wroking directory.

However, a downloadButton should have a downloadHandler, so replace the observeEvent with one of those.
Shiny - File Downloads — downloadHandler (rstudio.com)

Thanks for the link! I read up on it and several other examples, but it seems there aren't really examples that completely solve this (that I could find).

So I modified an example from the link you mentioned, but I can only get it to work when re-generating the plot completely. This would mean pasting the code within each download handler - but this isn't feasible because my real data has many plots and they're all complex.

How can I make this work but instead reference the plot rather than re-make it just to download it?

This works:

library(shiny)
library(ggplot2)
runApp(list(
  ui = fluidPage(downloadButton("downloadPlot"),
                 plotOutput("myplot")),
  
  
  server = function(input, output) {
    
      output$myplot <- renderPlot({
        myplot <- ggplot(mtcars, aes(x=cyl, y=mpg, color=mpg)) + geom_point()
        myplot
      })

    plotInput = function() {
    
      ##################################################
      ##################################################
      #This method works - but requires re-generating the plot for every download button!
      ggplot(mtcars, aes(x=cyl, y=mpg, color=mpg)) + geom_point()
      ##################################################
      ##################################################
      
    }
    output$downloadPlot <- downloadHandler(
      filename = function() { paste("test", '.svg', sep='') },
      content = function(file) {
        ggsave(file, plot = plotInput(), device = "svg")
      }
    )
  }
))

...but this does not work by simply referencing the plot -- maybe I'm doing it wrong?

library(shiny)
library(ggplot2)
runApp(list(
  ui = fluidPage(downloadButton("downloadPlot"),
                 plotOutput("myplot")),
  
  
  server = function(input, output) {
    
      output$myplot <- renderPlot({
        myplot <- ggplot(mtcars, aes(x=cyl, y=mpg, color=mpg)) + geom_point()
        myplot
      })

    plotInput = function() {
    
      ##################################################
      ##################################################
      #DOES NOT WORK obviously - because 'myplot' is only defined inside of the 'renderPlot' from above
      myplot 
      ##################################################
      ##################################################
      
    }
    output$downloadPlot <- downloadHandler(
      filename = function() { paste("test", '.svg', sep='') },
      content = function(file) {
        ggsave(file, plot = plotInput(), device = "svg")
      }
    )
  }
))

I was able to adapt an answer from this thread into a suitable solution.

In this way, the plot only needs to be generated one time.

library(shiny)
library(ggplot2)
runApp(list(
  ui = fluidPage(downloadButton("downloadPlot"),
                 plotOutput("myplot")),
  
  
  server = function(input, output) {
    
    
    
      output$myplot <- renderPlot(.myplot())
      
      .myplot <- reactive(ggplot(mtcars, aes(x=mpg, y=cyl))+geom_point())
        

    plotInput = function() {
    
      ##################################################
      ##################################################
      .myplot()
      ##################################################
      ##################################################
      
    }
    output$downloadPlot <- downloadHandler(
      filename = function() { paste("test", '.svg', sep='') },
      content = function(file) {
        ggsave(file, plot = plotInput(), device = "svg")
      }
    )
  }
))
1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.