Search code examples
rshinydashboard

Shiny Download Handler not working for plots


I am trying to save the plots created on my shiny app and it works perfectly fine for the CSV files. However, I am unable to save the plots for ggplot2. What can go wrong in this case?

I get the following error

Saving 7 x 7 in image Warning: Error in Plotnca1: could not find function "Plotnca1"

  output$Plotnca1<-renderPlot({plot(Plot1<-modnca() %>% 
                                      ggplot()+
                                   geom_line(aes_string(y=input$ycol,x=input$xcol,group=(input$subid)))+
                                   theme_bw())})
  
  output$downloadplot <- downloadHandler(
    filename = function() {
      paste("pk_plot", ".png", sep = "")
    },
    content = function(file) {
      ggsave(file, plot = Plotnca1(), dpi = 300,device="png")
    }
  )

Solution

  • I think the primary issue is that output$Plotncal <- renderPlot({...}) doesn't work as we may think. The strategy, I think, is to have your plot as a reactive, call that reactive in the renderPlot call, and in the download handler - at least that's what I've used in the past.

      # Create a reactive object which returns a plot
      plot_ncal_reactive <- shiny::reactive({
        plot <- modnca() %>% 
          ggplot()+
          geom_line(aes_string(y=input$ycol,x=input$xcol,group=(input$subid)))+
          theme_bw())
      
      return(plot)
      })
    
      # Render the reactive plotting object
      output$Plotnca1 <- shiny::renderPlot(plot_ncal_reactive())
    
      # Download the reactive object in place of the renderPlot
      output$downloadplot <- downloadHandler(
        filename = function() {
          paste("pk_plot", ".png", sep = "")
        },
        content = function(file) {
          ggsave(file, plot = plot_ncal_reactive(), dpi = 300,device="png")
        }
      )
    

    If the syntax is slightly off, the idea should be correct. If not, a reprex would be really helpful :)

    As an aside, it may be worth looking at refactoring from aes_string to aes() and using .data[[input$xcol]], .data[[input$ycol]]

    Including an example here that you should be able to copy and paste and run the app to see it works

      library(shiny)
      library(tidyverse)
      ui <- fluidPage(
        shiny::downloadButton(
          outputId = "plotDownload"
        ),
        shiny::plotOutput(
          outputId = "plotOutput"
        )
      )
      
      server <- function(input, output, session) {
    
        plot_reactive <- shiny::reactive({
          plot <- mtcars %>%
            ggplot(aes(x= mpg)) +
            geom_histogram()
          
          return(plot)
        })
        
        output$plotOutput <- shiny::renderPlot({plot_reactive()})
        
        output$plotDownload <- output$plotDownload <- downloadHandler(
          filename = function() {
            paste("pk_plot", ".png", sep = "")
          },
          content = function(file) {
            ggsave(file, plot = plot_reactive(), dpi = 300,device="png")
          }
        )
      }
      
      shinyApp(ui, server)