编辑
自闪亮 1.2.0 起支持缓存使用 renderPlot()/plotOutput() 创建的图像。
以下解决方案的行为类似于renderCachedPlot() 的以下用法。
output$plot <- renderCachedPlot(
expr = {
histfaithful(bins = input$bins, col = input$col)
},
cache = diskCache()
)
renderCachedPlot() 允许在内存和磁盘上以合理的默认值进行缓存。可以自定义生成哈希键的规则,默认情况下digest::digest() 用于出现在expr 中的所有反应式表达式。
下面的解决方案演示了如何使用闪亮的模块来实现这些功能的一个子集(磁盘上的缓存)。基本策略是使用
-
digest::digest() 根据发送到绘图函数的参数创建缓存键
-
do.call() 将参数传递给绘图函数,除非从 digest() 创建的键表示图像已被缓存
-
grDevices::png() 从对do.call() 的调用中捕获图像并将其添加到缓存中
-
shiny::renderImage() 从缓存中提供图片
原答案
虽然这个问题的两个答案都很好,但我还是想使用shiny modules 添加另一个答案。以下模块将 plotfunction 和它的参数的反应版本作为输入。最后do.call(plotfun, args()) 用于创建情节。
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"))
}
正如我们所见,如果需要,该模块会删除创建的图像文件,并提供使用自定义缓存目录的选项,以防需要持久缓存(就像在我的实际用例中一样)。
对于一个用法示例,我将使用 hist(faithful[, 2]) 示例,就像 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))
)
}
)