downloading zipped files in Shiny?

Well I've looked all over, but cannot figure this one out!

Here is a minimal reprex for making 2 plots. A download button will allow either plot to be downloaded.

How can I download both plots in a zipped file?

library(shiny)
library(ggplot2)


runApp(list(
  ui = fluidPage(downloadButton("downloadPlot"),
                 plotOutput("myplot1"),
                 plotOutput("myplot2")),
  
  
  server = function(input, output) {
    
    #A reactive that generates desired plots
    #(based on user-input in real data, but simplified for this reprex)
    first_reactive <- reactive({
      p1 <- ggplot(mtcars, aes(x=mpg, y=wt))+geom_point(color="red",size=3)
      p2 <- ggplot(mtcars, aes(x=mpg, y=wt))+geom_point(color="blue",size=3)
      
      return(list(
        p1=p1,
        p2=p2
      ))
    })
    
    
    output$myplot1 <- renderPlot(first_reactive()$p1)
    output$myplot2 <- renderPlot(first_reactive()$p2)
    
    
    #Adapting examples found online to have these plots downloadable
    .download_reactive <- reactive({
      return(list(
        p1=first_reactive()$p1,
        p2=first_reactive()$p2
      ))
    })
    
    plotInput = function(){return(list(
      p1=.download_reactive()$p1,
      p2=.download_reactive()$p2
    ))}
    
    #Download p1. This also would work to download p2. 
    #Looking for a way to download them both in a zipped file
    output$downloadPlot <- downloadHandler(
      filename="myplot1.svg", 
      content = function(file){
        ggsave(file, plot=plotInput()$p1)
      }
    )
  }
))

Below is a way to do it using the zip package.

library(shiny)
library(ggplot2)

ui = fluidPage(downloadButton("downloadPlot"),
               plotOutput("myplot1"),
               plotOutput("myplot2")
               )

server = function(input, output, session) {
    
    #A reactive that generates desired plots
    #(based on user-input in real data, but simplified for this reprex)
    first_reactive <- reactive({
      p1 <- ggplot(mtcars, aes(x=mpg, y=wt))+geom_point(color="red",size=3)
      p2 <- ggplot(mtcars, aes(x=mpg, y=wt))+geom_point(color="blue",size=3)
      
      return(list(
        p1=p1,
        p2=p2
      ))
    })
    
    output$myplot1 <- renderPlot(first_reactive()$p1)
    output$myplot2 <- renderPlot(first_reactive()$p2)
    
    # download plots as .zip
    output$downloadPlot <- downloadHandler(
      
      filename="myplots.zip", 
      
      content = function(file){
        
        ggsave('plot1.svg', plot=first_reactive()$p1, device = 'svg')
        ggsave('plot2.svg', plot=first_reactive()$p2, device = 'svg')
        
        zip::zip(file, files = c('plot1.svg', 'plot2.svg') )
      }
    )
  }

shinyApp(ui = ui, server = server)

This seems to write the plots to the working directory as well as compile them into a zip for downloading. Is there a way to accomplish this without writing to the working directory?

its no different from writing any file in any program. the working directory is assumed if you dont provide an alternative file path.
you can use combination of tempdir() and tempfile() constructions to use those features; or decide your own server path, and point to it ; file.path() can be very useful.

in short; instead of telling ggsave just to make you a file called plot1.svg; give it the full path to use.

 # not
ggsave('plot1.svg',  ...
# rather 
ggsave(file.path(tempdir(),'plot1.svg'), ...

# dont forget what you did 
 zip::zip(file, files = c(file.path(tempdir(),'plot1.svg'), ...

This seems to write properly, but causes an issue for the zip portion of the code where it Cannot add file C:\Users\...plot1.svg to archive C:\Users\...file360c648d6718.zip in file zip.c:348. [No stack trace available]

library(shiny)
library(ggplot2)

ui = fluidPage(downloadButton("downloadPlot"),
plotOutput("myplot1"),
plotOutput("myplot2")
)

server = function(input, output, session) {

#A reactive that generates desired plots
#(based on user-input in real data, but simplified for this reprex)
first_reactive <- reactive({
p1 <- ggplot(mtcars, aes(x=mpg, y=wt))+geom_point(color="red",size=3)
p2 <- ggplot(mtcars, aes(x=mpg, y=wt))+geom_point(color="blue",size=3)

return(list(
  p1=p1,
  p2=p2
))

})

output$myplot1 <- renderPlot(first_reactive()$p1)
output$myplot2 <- renderPlot(first_reactive()$p2)

#download plots as .zip
output$downloadPlot <- downloadHandler(

filename="myplots.zip", 

content = function(file){
  
  ggsave(file.path(tempdir(),'plot1.svg'), plot=first_reactive()$p1, device = 'svg')
  ggsave(file.path(tempdir(),'plot2.svg'), plot=first_reactive()$p2, device = 'svg')
  
  zip::zip(file, files = c(file.path(tempdir(),'plot1.svg'), file.path(tempdir(),'plot2.svg')) )
}

)
}

shinyApp(ui = ui, server = server)

ok, the secret sauce here is the zip option cherry-pick:

      zip::zip(file, files = c(file.path(tempdir(),'plot1.svg'),
                               file.path(tempdir(),'plot2.svg')),
               mode = "cherry-pick")