Pre-caching Shiny renderCachedPlot the first time automatically?

Is there a sensible way to pre-cache the rendering of cached plots automatically or as batch with a given set of inputs, without relying on the user to go there first?

More explanation of the problem:- let's say I have a Shiny app with a plot which (sometimes) takes a long time (30+ seconds) to render, or a page with multiple plots which together take a long time (in user waiting terms).

I can use renderCachedPlot() with a memory or disk cache which means that after loading the plot once, the next time, the plot will load much faster (as below).

(This is a toy example, the real example is much more complex)

function(input, output) {
  renderCachedPlot(
    {
      rownums <- seq_len(input$n)
      plot(cars$speed[rownums], cars$dist[rownums])
    },
    cacheKeyExpr = { input$n }
  )
}

But that first time is still too long, and if running on a server, users are likely to think it has failed, or get bored and do something else.

If the number input$n options are small, I could manually go through each input option in order to pre-cache, but then I'd have to do that everytime I update the code; and this seems like something that should be automatable. If the options are in 100+ range then I don't want to do this manually.

If I know all the expected inputs in advance (e.g. all the versions of input$n), I could alternatively pre-render the plots as PNGs outside the Shiny app, and then renderPNG instead, but that loses the convenience of keeping the plotting code in the Shiny app (when sometimes it is fast enough, at least during testing).

So, is there a way to generate the first plot cache in advance given a set of predefined inputs, e.g. call renderCachedPlot() from an environment which mimics the Shiny environment, but is solely designed to create the cache, and therefore speed up rendering for real users(TM)?

Very grateful for any thoughts on this!

I can't answer your question about whether or not you can pre-cache outputs within renderCachedPlot(), but for what it's worth, I think I would tackle your problem as follows.

  1. Write a function that generates the plot in question with non-reactive versions of your inputs as variables.

  2. Outside the app, use lapply or map to iterate that function over a vector or list containing all the possible combinations of those inputs.

  3. Save the plotting function, vector or list, and resulting list of plots in an .RData file that you store in a data folder in the directory where your app lives.

  4. When your Shiny app launches, load this .RData file, then have your server reactively pull plots from it instead of generating them on the fly.

This way, the user doesn't have to wait at all, but you also store the code used to generate the plots within the app, and it's easy to modify that plotting function and rerun the script as needed outside the app.

Hi @ulfelder,

Many thanks indeed for the suggestion... I've started to institute something like this (transform the plotting scripts within the renderCachedPlot to functions), though in my particular use case, I'm dependent on tmap which is slow to generate plots (maps) when there is a lot of data sets included, so to get the speed benefits, I think I need to render a rendered image, not just storing the result of the plot (which in case of tmap would be print(tmap)) in .RData.

Since this is what renderCachedPlot is doing behind the scenes, it would easier to call renderCachedPlot() from outside the app using a disk cache... This would obviously require managing expected 'input$' in the generator script, using lapply or whatever, but means depending on a pre-existing caching system, rather than re-inventing a way to manage pre-rendered images.

Perhaps it is simply not possible, with the current renderCachedPlot design, and I'll have to custom build a caching system.

Thanks again

This topic was automatically closed 54 days after the last reply. New replies are no longer allowed.