0

I have an R Shiny document where a user defines their chosen data and parameters, colours, etc. for a ggplot plot that is displayed in a "PlotOutput" area.

I want to add a button that will save the image that is currently in a plotting area as a PNG to a folder that I have already defined and with a naming format that I have chosen.

Namely, I would like the file to have name like "IMG_YYMMDD_HHMMSS" where date and time information comes from a Sys.time() call.

The only thing similar that I'm seeing documentation for is a downloadButton widget. But I can't get this to work, and even if I could, this lets the user define the name and destination of the output image file, which is not what I want.*

If I could just have the ggplot object passed to a ggsave function like one would do if one was writing code to produce such an image, then the file name and file path could be defined in this way. Is there any way to just do this?

Cheers

EDIT: so it looks like there is a way of using the download handler to save with a default name of my choosing. For my purposes, it looks to be easily changed from the below example:

output$downloadData <- downloadHandler(
  filename = function() { 
    paste(input$downloadData, " ",Sys.Date(),".csv",sep="") 
  },
  content = function(file) {
    write.csv(myout()$dataframe1,file,row.names=F)
  }
)

But I'm still not clear about how to use it and if there is a way of setting a folder of my choosing as the default as well. That would be perfect if it could be done.

*the reason I don't want it this way is that it should be very quick. It should take 10 seconds to produce the image that the user desires. If they then need to spend 15 seconds saving the image to some random destination with a random name, then this defeats the point. The idea is that it should just be the last name alphabetically, and the date and time works for this.

Limey
  • 10,234
  • 2
  • 12
  • 32
Leonhard Euler
  • 231
  • 1
  • 7
  • Allowing web apps to have access to arbitrary folders on a user's computer would be a *serious* security risk. You can allow them to chose the name of downloaded file, not its location. – Limey Mar 16 '23 at 18:27
  • I should say, the intention is to always access to the shiny app locally. Users will just open the app from the folder the R code is saved in and I would like any saved outputs to go to a nearby folder. Is this not possible? – Leonhard Euler Mar 16 '23 at 18:42

2 Answers2

1

With the app below, the user chooses a folder after clicking the button, and the graphic is saved in this folder with the name you specified in the app. It uses the good old package rChoiceDialogs. You could also use the shinyFiles package.

library(shiny)
library(rChoiceDialogs)
library(ggplot2)

ui <- fluidPage(
  br(), br(),
  actionButton("save", "Save plot"),
  br(),
  plotOutput("ggplot")
)

server <- function(input, output, session) {
  
  gg <- reactive({
    ggplot(iris) + geom_point(aes(Sepal.Length, Sepal.Width))
  })
  
  output[["ggplot"]] <- renderPlot(gg())
  
  observeEvent(input[["save"]], {
    folder <- jchoose.dir()
    if(length(folder) != 0) { # if not cancelled
      path <- file.path(folder, "TheNameYouWant.png")
      ggsave(path, plot = gg())
    }
  })
  
}

shinyApp(ui, server)

enter image description here

Stéphane Laurent
  • 75,186
  • 15
  • 119
  • 225
  • Yep, looks similar to what I put with the ggplot in the reactive dataset. It would have been cool to have a default folder that it saves to for every user, or to just hit "save" and it automatically saves the a preset folder but seems like that's not possible for security reasons. – Leonhard Euler Mar 18 '23 at 15:28
  • @LeonhardEuler you can set a default folder with `jchoose.dir`. – Stéphane Laurent Mar 18 '23 at 15:29
0

I wasn't able to do everything that I wanted, but this answer had enough to get me close enough.

The trick was to create the ggplot object as a reactive dataset that is

  1. passed to the renderer in

    output$dotPlot <- renderPlot({
        p()
    })
    

and 2. passed into the download handler in

output$save <- downloadHandler(
  filename =  function() {
    "WhatIWantToCallMyFile.png"
  },
  # content is a function with argument file. content writes the plot to the device
  content = function(file) {
    ggsave(file, p())
  } 
)

Saving ggplot from Shiny gives blank png file

This saves a nicely high res image as it's default anyway, but you can tinker around with width and height within ggsave.

Leonhard Euler
  • 231
  • 1
  • 7