I'm trying to create a shiny app that both displays a png that is created by the code (i.e. reactive) and which can then be downloaded. I found a nice example on how to create and update the png (link), but have not found out how to then grab this file for download. The download button is not working as intended.
The code below shows a minimal example:
library(shiny)
ui <- pageWithSidebar(
headerPanel("renderImage example"),
sidebarPanel(
sliderInput("obs", "Number of observations:",
min = 0, max = 1000, value = 500)
),
mainPanel(
# Use imageOutput to place the image on the page
imageOutput("myImage"),
# Download button
downloadButton("download", "Download Image")
)
)
server <- function(input, output, session) {
output$myImage <- renderImage({
# A temp file to save the output.
# This file will be removed later by renderImage
outfile <- tempfile(fileext = '.png')
# Generate the PNG
png(outfile, width = 400, height = 300)
hist(rnorm(input$obs), main = "Generated in renderImage()")
dev.off()
# Return a list containing the filename
list(src = outfile,
contentType = 'image/png',
width = 400,
height = 300,
alt = "This is alternate text")
}, deleteFile = FALSE)
# Enable image download
output$download <- downloadHandler(
filename = function() {
"generated_plot.png"
},
content = function(file){
# Save the plot/image to a file
img <- system.file(output$myImage$outfile, package="png")
file.copy(img, file)
}
)
}
shinyApp(ui, server)
When you want to display your image and want to download it, then IMHO the easiest approach would be to create your image inside a reactive
which could then be used or called both in renderImage()
and in downloadHandler
. Also note that system.file(output$myImage$outfile, package="png")
does not make sense. Instead when you store the list containing the image information as a reactive image
as I do below you could use image()$src
to get the file path.
library(shiny)
ui <- pageWithSidebar(
headerPanel("renderImage example"),
sidebarPanel(
sliderInput("obs", "Number of observations:",
min = 0, max = 1000, value = 500
)
),
mainPanel(
imageOutput("myImage"),
downloadButton("download", "Download Image")
)
)
server <- function(input, output, session) {
image <- reactive({
outfile <- tempfile(fileext = ".png")
png(outfile, width = 400, height = 300)
hist(rnorm(input$obs), main = "Generated in renderImage()")
dev.off()
list(
src = outfile,
contentType = "image/png",
width = 400,
height = 300,
alt = "This is alternate text"
)
})
output$myImage <- renderImage(
{
image()
},
deleteFile = FALSE
)
output$download <- downloadHandler(
filename = function() {
"generated_plot.png"
},
content = function(file) {
img <- image()$src
file.copy(img, file)
}
)
}
shinyApp(ui, server)