Implement custom render functions — createRenderFunction
R/shinywrappers.R
, R/utils-lang.R
Description
Developer-facing utilities for implementing a custom renderXXX()
function.
Before using these utilities directly, consider using the htmlwidgets
package to implement custom
outputs (i.e., custom renderXXX()
/xxxOutput()
functions). That said,
these utilities can be used more directly if a full-blown htmlwidget isn't
needed and/or the user-supplied reactive expression needs to be wrapped in
additional call(s).
createRenderFunction(
func,
transform = function(value, session, name, ...) value,
outputFunc = NULL,
outputArgs = NULL,
cacheHint = "auto",
cacheWriteHook = NULL,
cacheReadHook = NULL
)
quoToFunction(q, label = sys.call(-1)[[1]], ..stacktraceon = FALSE)
installExprFunction(
expr,
name,
eval.env = parent.frame(2),
quoted = FALSE,
assign.env = parent.frame(1),
label = sys.call(-1)[[1]],
wrappedWithLabel = TRUE,
..stacktraceon = FALSE
)
Arguments
- func
A function without parameters, that returns user data. If the returned value is a promise, then the render function will proceed in async mode.
- transform
A function that takes four arguments:
value
,session
,name
, and...
(for future-proofing). This function will be invoked each time a value is returned fromfunc
, and is responsible for changing the value into a JSON-ready value to be JSON-encoded and sent to the browser.- outputFunc
The UI function that is used (or most commonly used) with this render function. This can be used in R Markdown documents to create complete output widgets out of just the render function.
- outputArgs
A list of arguments to pass to the
uiFunc
. Render functions should includeoutputArgs = list()
in their own parameter list, and pass through the value tomarkRenderFunction
, to allow app authors to customize outputs. (Currently, this is only supported for dynamically generated UIs, such as those created by Shiny code snippets embedded in R Markdown documents).- cacheHint
One of
"auto"
,FALSE
, or some other information to identify this instance for caching usingbindCache()
. If"auto"
, it will try to automatically infer caching information. IfFALSE
, do not allow caching for the object. Some render functions (such as renderPlot) contain internal state that makes them unsuitable for caching.- cacheWriteHook
Used if the render function is passed to
bindCache()
. This is an optional callback function to invoke before saving the value from the render function to the cache. This function must accept one argument, the value returned fromrenderFunc
, and should return the value to store in the cache.- cacheReadHook
Used if the render function is passed to
bindCache()
. This is an optional callback function to invoke after reading a value from the cache (if there is a cache hit). The function will be passed one argument, the value retrieved from the cache. This can be useful when some side effect needs to occur for a render function to behave correctly. For example, some render functions callcreateWebDependency()
so that Shiny is able to serve JS and CSS resources.- q
Quosure of the expression
x
. When capturing expressions to create your quosure, it is recommended to userlang::enquo0()
to not unquote the object too early. Seerlang::enquo0()
for more details.- label
A label for the object to be shown in the debugger. Defaults to the name of the calling function.
- expr
A quoted or unquoted expression, or a quosure.
- name
The name the function should be given
- eval.env
The desired environment for the function. Defaults to the calling environment two steps back.
- quoted
Is the expression quoted?
- assign.env
The environment in which the function should be assigned.
- wrappedWithLabel, ..stacktraceon
Advanced use only. For stack manipulation purposes; see
stacktrace()
.
Value
An annotated render function, ready to be assigned to an
output
slot.
Details
To implement a custom renderXXX()
function, essentially 2 things are needed:
Capture the user's reactive expression as a function.
New
renderXXX()
functions can usequoToFunction()
for this, but already existingrenderXXX()
functions that containenv
andquoted
parameters may want to continue usinginstallExprFunction()
for better legacy support (see examples).
Flag the resulting function (from 1) as a Shiny rendering function and also provide a UI container for displaying the result of the rendering function.
createRenderFunction()
is currently recommended (instead ofmarkRenderFunction()
) for this step (see examples).
Functions
quoToFunction()
: convert a quosure to a function.installExprFunction()
: converts a user's reactiveexpr
into a function that's assigned to aname
in theassign.env
.
Examples
# A custom render function that repeats the supplied value 3 times
renderTriple <- function(expr) {
# Wrap user-supplied reactive expression into a function
func <- quoToFunction(rlang::enquo0(expr))
createRenderFunction(
func,
transform = function(value, session, name, ...) {
paste(rep(value, 3), collapse=", ")
},
outputFunc = textOutput
)
}
# For better legacy support, consider using installExprFunction() over quoToFunction()
renderTripleLegacy <- function(expr, env = parent.frame(), quoted = FALSE) {
func <- installExprFunction(expr, "func", env, quoted)
createRenderFunction(
func,
transform = function(value, session, name, ...) {
paste(rep(value, 3), collapse=", ")
},
outputFunc = textOutput
)
}
# Test render function from the console
reactiveConsole(TRUE)
v <- reactiveVal("basic")
r <- renderTriple({ v() })
r()
#> [1] "basic, basic, basic"
# User can supply quoted code via rlang::quo(). Note that evaluation of the
# expression happens when r2() is invoked, not when r2 is created.
q <- rlang::quo({ v() })
r2 <- rlang::inject(renderTriple(!!q))
v("rlang")
r2()
#> [1] "rlang, rlang, rlang"
# Supplying quoted code without rlang::quo() requires installExprFunction()
expr <- quote({ v() })
r3 <- renderTripleLegacy(expr, quoted = TRUE)
v("legacy")
r3()
#> [1] "legacy, legacy, legacy"
# The legacy approach also supports with quosures (env is ignored in this case)
q <- rlang::quo({ v() })
r4 <- renderTripleLegacy(q, quoted = TRUE)
v("legacy-rlang")
r4()
#> [1] "legacy-rlang, legacy-rlang, legacy-rlang"
# Turn off reactivity in the console
reactiveConsole(FALSE)