Allow to manually call output render functions
Dear devs,
I was wondering if shiny can provide functions to call output renderers manually without knowing the expressions inside of the render calls. For example, something like shiny::renderOutput as follows:
# server:
function(input, output, session) {
output$plot1 <- shiny::renderPlot({ ... })
output$download <- shiny::downloadHandler(
...,
content = function(con) {
# Re-render plot1 without knowing the expression
pdf(...)
shiny::renderOutput(output, "download")
dev.off()
}
)
}
Also it would be nice if shiny::outputOptions can add arbitrary (customized) key-value pairs, so we can store additional information needed (for example the arguments needed by pdf() function.
I understand that there could be lots of things to consider (such as potential side effects). However, it would be neat if there is such function, as we can programmatically write widget functions for outputs. For example,
- downloading graphs, saving HTML widgets (without writing handlers),
- embed an output in another session/output zoomed in or as a sub-plot,
- allow a third person to add additional processing/extract information from output results (from ggplot2 object, or htmlwidget)
My attempts
-
For some outputs, I am able to extract the expression from
cacheHintattribute ofshiny.render.functionobjects. However, ifcacheHintis set to false inmarkRenderFunction(such asDT::renderDT), I couldn't obtain any expressions. -
Another attempt is to directly call
shiny.render.functionwith a given session and output. However, that only gives me processed results instead of what's generated fromexpr. For example,renderPlotreturns the base64-encoded image, and I cannot set the width nor height.
I think you may be able to achieve your intended goal with adding an extra level of indirection. In your example there is a mystery expression inside of a renderPlot({}); I suggest that however you have architected that to come about, have it populate a reactive() instead, then this reactive can itself be used as a parameter into a renderPlot as well as to a downloadHandler.
@dipterix :
When I have different types of Output I use shiny::renderUI() / shiny::uiOutput().
Thanks @nir4most that's exactly what I was doing. The reason why I posted this issue was because I think it would be easier if the render functions can store the expression as one of its attributes, such that the add-ons can work without having users to change their existing code.
Also I can render directly with shiny.render.function. However, the render functions might not return the results that I want. For example, renderPlot returns base64 encoded images, and I cannot capture the image with graphic devices such as pdf, nor can I add pre/post-processing to the images (add lines, legend, change palettes)
@philibe , That's not gonna solve my issues. I don't need multiple output support. I need ways to get renderers' expression and program on the context so I can provide add-ons to any shiny outputs without knowing the details of implementation.