Edit
Caching of images created using renderPlot()/plotOutput() has been supported since version 1.2.0.
The solution below behaves similarly to the following use of renderCachedPlot() .
output$plot <- renderCachedPlot( expr = { histfaithful(bins = input$bins, col = input$col) }, cache = diskCache() )
renderCachedPlot() allows you to cache in memory and on disk with reasonable default values. Rules for generating hash keys can be configured and, by default, digest::digest() used for all reactive expressions that appear in expr .
The solution below demonstrates how a subset of these features (disk caching) can be implemented using a brilliant module. The main strategy is to use
digest::digest() to create cache keys based on arguments sent to the build functiondo.call() to pass arguments to the plot function if the key created from digest() does not mean that the image is already cachedgrDevices::png() to capture the image from the call to do.call() and add it to the cacheshiny::renderImage() to serve cache images
Original answer
Although both answers to this question are very good, I would like to add another one using brilliant modules . The next module accepts a graphical function and a reactive version of the arguments as input. In the end, do.call(plotfun, args()) used to create the plot.
library(shiny) cachePlot <- function(input, output, session, plotfun, args, width = 480, height = 480, dir = tempdir(), prefix = "cachedPlot", deleteonexit = TRUE){ hash <- function(args) digest::digest(args) output$plot <- renderImage({ args <- args() if (!is.list(args)) args <- list(args) imgpath <- file.path(dir, paste0(prefix, "-", hash(args), ".png")) if(!file.exists(imgpath)){ png(imgpath, width = width, height = height) do.call(plotfun, args) dev.off() } list(src = imgpath) }, deleteFile = FALSE) if (deleteonexit) session$onSessionEnded(function(){ imgfiles <- list.files(dir, pattern = prefix, full.names = TRUE) file.remove(imgfiles) }) } cachePlotUI <- function(id){ ns <- NS(id) imageOutput(ns("plot")) }
As we can see, the module deletes the created image files, if necessary, and makes it possible to use the user directory for caching if constant caching is necessary (as in my real use case).
As an example of use, I will use the hist(faithful[, 2]) example, just like Stedy.
histfaithful <- function(bins, col){ message("calling histfaithful with args ", bins, " and ", col) x <- faithful[, 2] bins <- seq(min(x), max(x), length.out = bins + 1) hist(x, breaks = bins, col = col, border = 'white') } shinyApp( ui = fluidPage( inputPanel( sliderInput("bins", "bins", 5, 30, 10, 1), selectInput("col", "color", c("blue", "red")) ), cachePlotUI("cachedPlot") ), server = function(input, output, session){ callModule( cachePlot, "cachedPlot", histfaithful, args = reactive(list(bins = input$bins, col = input$col)) ) } )