mirror of
https://github.com/rstudio/shiny.git
synced 2026-01-10 23:48:01 -05:00
Compare commits
66 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6e7e8eb44a | ||
|
|
308c583254 | ||
|
|
97b2f7e5ca | ||
|
|
3ea88a07d9 | ||
|
|
588f8bb96a | ||
|
|
c93c0dd721 | ||
|
|
fc59c254fd | ||
|
|
2f8b6a150f | ||
|
|
db60ac5c17 | ||
|
|
e1f09853c5 | ||
|
|
24656713a5 | ||
|
|
7dd0269292 | ||
|
|
8b87cea7aa | ||
|
|
c7559a6946 | ||
|
|
945c6080ad | ||
|
|
44590965d1 | ||
|
|
7ab64d678f | ||
|
|
e406a76b62 | ||
|
|
e26f175a8f | ||
|
|
d4ab84745d | ||
|
|
32dbc3101e | ||
|
|
0a924eb718 | ||
|
|
a284327bfc | ||
|
|
2ea38d6ecc | ||
|
|
6a34bbfddd | ||
|
|
58323ada4b | ||
|
|
5fd723cb80 | ||
|
|
5c626e6957 | ||
|
|
5d949842eb | ||
|
|
b595c17d78 | ||
|
|
b84973ba2b | ||
|
|
61be49e7b2 | ||
|
|
8faf5659ee | ||
|
|
cc9267a646 | ||
|
|
55838bb032 | ||
|
|
67619ac5e8 | ||
|
|
952b342859 | ||
|
|
c7149c460d | ||
|
|
fd0613ea0e | ||
|
|
36d2dddc59 | ||
|
|
63c5b05584 | ||
|
|
4b235e5b87 | ||
|
|
6c51fffdaa | ||
|
|
5d6d638c85 | ||
|
|
90eb515167 | ||
|
|
17526711a2 | ||
|
|
cf0118e090 | ||
|
|
868d6fec42 | ||
|
|
851f5854bf | ||
|
|
eb5428c971 | ||
|
|
81188df7ef | ||
|
|
9fd365cc41 | ||
|
|
999df6e40f | ||
|
|
076d069568 | ||
|
|
2738648197 | ||
|
|
36013009a1 | ||
|
|
1b60233862 | ||
|
|
2cba10dd05 | ||
|
|
b3944127ea | ||
|
|
f1674378ca | ||
|
|
6f0191e1cf | ||
|
|
1848844be6 | ||
|
|
8b6362c749 | ||
|
|
d860d13361 | ||
|
|
4b077dbf4c | ||
|
|
40f73bbfe2 |
@@ -1,7 +1,7 @@
|
||||
Package: shiny
|
||||
Type: Package
|
||||
Title: Web Application Framework for R
|
||||
Version: 0.3.1
|
||||
Version: 0.4.0
|
||||
Date: 2013-01-23
|
||||
Author: RStudio, Inc.
|
||||
Maintainer: Winston Chang <winston@rstudio.com>
|
||||
|
||||
13
NAMESPACE
13
NAMESPACE
@@ -1,9 +1,13 @@
|
||||
S3method("$",reactivevalues)
|
||||
S3method("$",shinyoutput)
|
||||
S3method("$<-",reactivevalues)
|
||||
S3method("$<-",shinyoutput)
|
||||
S3method("[",reactivevalues)
|
||||
S3method("[",shinyoutput)
|
||||
S3method("[<-",reactivevalues)
|
||||
S3method("[<-",shinyoutput)
|
||||
S3method("[[",reactivevalues)
|
||||
S3method("[[",shinyoutput)
|
||||
S3method("[[<-",reactivevalues)
|
||||
S3method("[[<-",shinyoutput)
|
||||
S3method("names<-",reactivevalues)
|
||||
@@ -15,8 +19,6 @@ S3method(format,shiny.tag.list)
|
||||
S3method(names,reactivevalues)
|
||||
S3method(print,shiny.tag)
|
||||
S3method(print,shiny.tag.list)
|
||||
S3method(reactive,"function")
|
||||
S3method(reactive,default)
|
||||
export(HTML)
|
||||
export(a)
|
||||
export(addResourcePath)
|
||||
@@ -32,6 +34,7 @@ export(downloadButton)
|
||||
export(downloadHandler)
|
||||
export(downloadLink)
|
||||
export(em)
|
||||
export(exprToFunction)
|
||||
export(fileInput)
|
||||
export(h1)
|
||||
export(h2)
|
||||
@@ -51,6 +54,7 @@ export(isolate)
|
||||
export(mainPanel)
|
||||
export(numericInput)
|
||||
export(observe)
|
||||
export(outputOptions)
|
||||
export(p)
|
||||
export(pageWithSidebar)
|
||||
export(plotOutput)
|
||||
@@ -65,6 +69,11 @@ export(reactiveTimer)
|
||||
export(reactiveUI)
|
||||
export(reactiveValues)
|
||||
export(reactiveValuesToList)
|
||||
export(renderPlot)
|
||||
export(renderPrint)
|
||||
export(renderTable)
|
||||
export(renderText)
|
||||
export(renderUI)
|
||||
export(repeatable)
|
||||
export(runApp)
|
||||
export(runExample)
|
||||
|
||||
19
NEWS
19
NEWS
@@ -1,3 +1,22 @@
|
||||
shiny 0.4.0
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
* Added suspend/resume capability to observers.
|
||||
|
||||
* Output objects are automatically suspended when they are hidden on the user's
|
||||
web browser.
|
||||
|
||||
* `runGist()` accepts GitHub's new URL format, which includes the username.
|
||||
|
||||
* `reactive()` and `observe()` now take expressions instead of functions.
|
||||
|
||||
* `reactiveText()`, `reactivePlot()`, and so on, have been renamed to
|
||||
`renderText()`, `renderPlot()`, etc. They also now take expressions instead
|
||||
of functions.
|
||||
|
||||
* Fixed a bug where empty values in a numericInput were sent to the R process
|
||||
as 0. They are now sent as NA.
|
||||
|
||||
shiny 0.3.1
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -708,7 +708,7 @@ tabsetPanel <- function(..., id = NULL) {
|
||||
#' @param outputId output variable to read the value from
|
||||
#' @return A text output element that can be included in a panel
|
||||
#' @details Text is HTML-escaped prior to rendering. This element is often used
|
||||
#' to dispaly \link{reactiveText} output variables.
|
||||
#' to display \link{renderText} output variables.
|
||||
#' @examples
|
||||
#' h3(textOutput("caption"))
|
||||
#' @export
|
||||
@@ -723,7 +723,7 @@ textOutput <- function(outputId) {
|
||||
#' @param outputId output variable to read the value from
|
||||
#' @return A verbatim text output element that can be included in a panel
|
||||
#' @details Text is HTML-escaped prior to rendering. This element is often used
|
||||
#' with the \link{reactivePrint} function to preserve fixed-width formatting
|
||||
#' with the \link{renderPrint} function to preserve fixed-width formatting
|
||||
#' of printed objects.
|
||||
#' @examples
|
||||
#' mainPanel(
|
||||
@@ -740,7 +740,7 @@ verbatimTextOutput <- function(outputId) {
|
||||
|
||||
#' Create a plot output element
|
||||
#'
|
||||
#' Render a \link{reactivePlot} within an application page.
|
||||
#' Render a \link{renderPlot} within an application page.
|
||||
#' @param outputId output variable to read the plot from
|
||||
#' @param width Plot width. Must be a valid CSS unit (like \code{"100\%"},
|
||||
#' \code{"400px"}, \code{"auto"}) or a number, which will be coerced to a
|
||||
@@ -761,7 +761,7 @@ plotOutput <- function(outputId, width = "100%", height="400px") {
|
||||
|
||||
#' Create a table output element
|
||||
#'
|
||||
#' Render a \link{reactiveTable} within an application page.
|
||||
#' Render a \link{renderTable} within an application page.
|
||||
#' @param outputId output variable to read the table from
|
||||
#' @return A table output element that can be included in a panel
|
||||
#' @examples
|
||||
@@ -779,7 +779,7 @@ tableOutput <- function(outputId) {
|
||||
#' text will be included within an HTML \code{div} tag, and is presumed to
|
||||
#' contain HTML content which should not be escaped.
|
||||
#'
|
||||
#' \code{uiOutput} is intended to be used with \code{reactiveUI} on the
|
||||
#' \code{uiOutput} is intended to be used with \code{renderUI} on the
|
||||
#' server side. It is currently just an alias for \code{htmlOutput}.
|
||||
#'
|
||||
#' @param outputId output variable to read the value from
|
||||
|
||||
13
R/react.R
13
R/react.R
@@ -68,12 +68,18 @@ Context <- setRefClass(
|
||||
|
||||
ReactiveEnvironment <- setRefClass(
|
||||
'ReactiveEnvironment',
|
||||
fields = c('.currentContext', '.nextId', '.pendingFlush'),
|
||||
fields = list(
|
||||
.currentContext = 'ANY',
|
||||
.nextId = 'integer',
|
||||
.pendingFlush = 'list',
|
||||
.inFlush = 'logical'
|
||||
),
|
||||
methods = list(
|
||||
initialize = function() {
|
||||
.currentContext <<- NULL
|
||||
.nextId <<- 0L
|
||||
.pendingFlush <<- list()
|
||||
.inFlush <<- FALSE
|
||||
},
|
||||
nextId = function() {
|
||||
.nextId <<- .nextId + 1L
|
||||
@@ -96,6 +102,11 @@ ReactiveEnvironment <- setRefClass(
|
||||
.pendingFlush <<- c(ctx, .pendingFlush)
|
||||
},
|
||||
flush = function() {
|
||||
# If already in a flush, don't start another one
|
||||
if (.inFlush) return()
|
||||
.inFlush <<- TRUE
|
||||
on.exit(.inFlush <<- FALSE)
|
||||
|
||||
while (length(.pendingFlush) > 0) {
|
||||
ctx <- .pendingFlush[[1]]
|
||||
.pendingFlush <<- .pendingFlush[-1]
|
||||
|
||||
273
R/reactives.R
273
R/reactives.R
@@ -26,6 +26,8 @@ Dependents <- setRefClass(
|
||||
)
|
||||
|
||||
|
||||
# ReactiveValues ------------------------------------------------------------
|
||||
|
||||
ReactiveValues <- setRefClass(
|
||||
'ReactiveValues',
|
||||
fields = list(
|
||||
@@ -112,13 +114,14 @@ ReactiveValues <- setRefClass(
|
||||
)
|
||||
|
||||
|
||||
# reactivevalues: S3 wrapper class for Values class -----------------------
|
||||
# reactivevalues ------------------------------------------------------------
|
||||
# S3 wrapper class for ReactiveValues reference class
|
||||
|
||||
#' Create an object for storing reactive values
|
||||
#'
|
||||
#' This function returns an object for storing reactive values. It is similar
|
||||
#' to a list, but with special capabilities for reactive programming. When you
|
||||
#' read a value from it, the calling reactive function takes a reactive
|
||||
#' read a value from it, the calling reactive expression takes a reactive
|
||||
#' dependency on that value, and when you write to it, it notifies any reactive
|
||||
#' functions that depend on that value.
|
||||
#'
|
||||
@@ -168,10 +171,7 @@ reactiveValues <- function(...) {
|
||||
# @param values A ReactiveValues object
|
||||
# @param readonly Should this object be read-only?
|
||||
.createReactiveValues <- function(values = NULL, readonly = FALSE) {
|
||||
acc <- list(impl=values)
|
||||
class(acc) <- 'reactivevalues'
|
||||
attr(acc, 'readonly') <- readonly
|
||||
return(acc)
|
||||
structure(list(impl=values), class='reactivevalues', readonly=readonly)
|
||||
}
|
||||
|
||||
#' @S3method $ reactivevalues
|
||||
@@ -219,7 +219,7 @@ names.reactivevalues <- function(x) {
|
||||
|
||||
#' @S3method as.list reactivevalues
|
||||
as.list.reactivevalues <- function(x, all.names=FALSE, ...) {
|
||||
.Deprecated("reactiveValuesToList",
|
||||
shinyDeprecated("reactiveValuesToList",
|
||||
msg = paste("'as.list.reactivevalues' is deprecated. ",
|
||||
"Use reactiveValuesToList instead.",
|
||||
"\nPlease see ?reactiveValuesToList for more information.",
|
||||
@@ -254,13 +254,15 @@ reactiveValuesToList <- function(x, all.names=FALSE) {
|
||||
.subset2(x, 'impl')$toList(all.names)
|
||||
}
|
||||
|
||||
# Observable ----------------------------------------------------------------
|
||||
|
||||
Observable <- setRefClass(
|
||||
'Observable',
|
||||
fields = list(
|
||||
.func = 'function',
|
||||
.label = 'character',
|
||||
.dependents = 'Dependents',
|
||||
.dirty = 'logical',
|
||||
.invalidated = 'logical',
|
||||
.running = 'logical',
|
||||
.value = 'ANY',
|
||||
.visible = 'logical',
|
||||
@@ -269,11 +271,11 @@ Observable <- setRefClass(
|
||||
methods = list(
|
||||
initialize = function(func, label=deparse(substitute(func))) {
|
||||
if (length(formals(func)) > 0)
|
||||
stop("Can't make a reactive function from a function that takes one ",
|
||||
stop("Can't make a reactive expression from a function that takes one ",
|
||||
"or more parameters; only functions without parameters can be ",
|
||||
"reactive.")
|
||||
.func <<- func
|
||||
.dirty <<- TRUE
|
||||
.invalidated <<- TRUE
|
||||
.running <<- FALSE
|
||||
.label <<- label
|
||||
.execCount <<- 0L
|
||||
@@ -281,7 +283,7 @@ Observable <- setRefClass(
|
||||
getValue = function() {
|
||||
.dependents$register()
|
||||
|
||||
if (.dirty || .running) {
|
||||
if (.invalidated || .running) {
|
||||
.self$.updateValue()
|
||||
}
|
||||
|
||||
@@ -296,12 +298,12 @@ Observable <- setRefClass(
|
||||
.updateValue = function() {
|
||||
ctx <- Context$new(.label)
|
||||
ctx$onInvalidate(function() {
|
||||
.dirty <<- TRUE
|
||||
.invalidated <<- TRUE
|
||||
.dependents$invalidate()
|
||||
})
|
||||
.execCount <<- .execCount + 1L
|
||||
|
||||
.dirty <<- FALSE
|
||||
.invalidated <<- FALSE
|
||||
|
||||
wasRunning <- .running
|
||||
.running <<- TRUE
|
||||
@@ -316,41 +318,60 @@ Observable <- setRefClass(
|
||||
)
|
||||
)
|
||||
|
||||
#' Create a Reactive Function
|
||||
#'
|
||||
#' Wraps a normal function to create a reactive function. Conceptually, a
|
||||
#' reactive function is a function whose result will change over time.
|
||||
#'
|
||||
#' Reactive functions are functions that can read reactive values and call other
|
||||
#' reactive functions. Whenever a reactive value changes, any reactive functions
|
||||
#' that depended on it are marked as "invalidated" and will automatically
|
||||
#' re-execute if necessary. If a reactive function is marked as invalidated, any
|
||||
#' other reactive functions that recently called it are also marked as
|
||||
#' invalidated. In this way, invalidations ripple through the functions that
|
||||
#' Create a reactive expression
|
||||
#'
|
||||
#' Wraps a normal expression to create a reactive expression. Conceptually, a
|
||||
#' reactive expression is a expression whose result will change over time.
|
||||
#'
|
||||
#' Reactive expressions are expressions that can read reactive values and call other
|
||||
#' reactive expressions. Whenever a reactive value changes, any reactive expressions
|
||||
#' that depended on it are marked as "invalidated" and will automatically
|
||||
#' re-execute if necessary. If a reactive expression is marked as invalidated, any
|
||||
#' other reactive expressions that recently called it are also marked as
|
||||
#' invalidated. In this way, invalidations ripple through the expressions that
|
||||
#' depend on each other.
|
||||
#'
|
||||
#' See the \href{http://rstudio.github.com/shiny/tutorial/}{Shiny tutorial} for
|
||||
#' more information about reactive functions.
|
||||
#'
|
||||
#' @param x The value or function to make reactive. The function must not have
|
||||
#' any parameters.
|
||||
#' @return A reactive function. (Note that reactive functions can only be called
|
||||
#' from within other reactive functions.)
|
||||
#'
|
||||
#'
|
||||
#' See the \href{http://rstudio.github.com/shiny/tutorial/}{Shiny tutorial} for
|
||||
#' more information about reactive expressions.
|
||||
#'
|
||||
#' @param x An expression (quoted or unquoted).
|
||||
#' @param env The parent environment for the reactive expression. By default, this
|
||||
#' is the calling environment, the same as when defining an ordinary
|
||||
#' non-reactive expression.
|
||||
#' @param quoted Is the expression quoted? By default, this is \code{FALSE}.
|
||||
#' This is useful when you want to use an expression that is stored in a
|
||||
#' variable; to do so, it must be quoted with `quote()`.
|
||||
#' @param label A label for the reactive expression, useful for debugging.
|
||||
#'
|
||||
#' @examples
|
||||
#' values <- reactiveValues(A=1)
|
||||
#'
|
||||
#' reactiveB <- reactive({
|
||||
#' values$A + 1
|
||||
#' })
|
||||
#'
|
||||
#' # Can use quoted expressions
|
||||
#' reactiveC <- reactive(quote({ values$A + 2 }), quoted = TRUE)
|
||||
#'
|
||||
#' # To store expressions for later conversion to reactive, use quote()
|
||||
#' expr_q <- quote({ values$A + 3 })
|
||||
#' reactiveD <- reactive(expr_q, quoted = TRUE)
|
||||
#'
|
||||
#' # View the values from the R console with isolate()
|
||||
#' isolate(reactiveB())
|
||||
#' isolate(reactiveC())
|
||||
#' isolate(reactiveD())
|
||||
#'
|
||||
#' @export
|
||||
reactive <- function(x) {
|
||||
UseMethod("reactive")
|
||||
}
|
||||
#' @S3method reactive function
|
||||
reactive.function <- function(x) {
|
||||
return(Observable$new(x, deparse(substitute(x)))$getValue)
|
||||
}
|
||||
#' @S3method reactive default
|
||||
reactive.default <- function(x) {
|
||||
stop("Don't know how to make this object reactive!")
|
||||
reactive <- function(x, env = parent.frame(), quoted = FALSE, label = NULL) {
|
||||
fun <- exprToFunction(x, env, quoted)
|
||||
if (is.null(label))
|
||||
label <- deparse(body(fun))
|
||||
|
||||
Observable$new(fun, label)$getValue
|
||||
}
|
||||
|
||||
# Return the number of times that a reactive function or observer has been run
|
||||
# Return the number of times that a reactive expression or observer has been run
|
||||
execCount <- function(x) {
|
||||
if (is.function(x))
|
||||
return(environment(x)$.execCount)
|
||||
@@ -360,16 +381,20 @@ execCount <- function(x) {
|
||||
stop('Unexpected argument to execCount')
|
||||
}
|
||||
|
||||
# Observer ------------------------------------------------------------------
|
||||
|
||||
Observer <- setRefClass(
|
||||
'Observer',
|
||||
fields = list(
|
||||
.func = 'function',
|
||||
.label = 'character',
|
||||
.flushCallbacks = 'list',
|
||||
.execCount = 'integer'
|
||||
.invalidateCallbacks = 'list',
|
||||
.execCount = 'integer',
|
||||
.onResume = 'function',
|
||||
.suspended = 'logical'
|
||||
),
|
||||
methods = list(
|
||||
initialize = function(func, label) {
|
||||
initialize = function(func, label, suspended = FALSE) {
|
||||
if (length(formals(func)) > 0)
|
||||
stop("Can't make an observer from a function that takes parameters; ",
|
||||
"only functions without parameters can be reactive.")
|
||||
@@ -377,68 +402,133 @@ Observer <- setRefClass(
|
||||
.func <<- func
|
||||
.label <<- label
|
||||
.execCount <<- 0L
|
||||
.suspended <<- suspended
|
||||
.onResume <<- function() NULL
|
||||
|
||||
# Defer the first running of this until flushReact is called
|
||||
ctx <- Context$new(.label)
|
||||
ctx$onFlush(function() {
|
||||
run()
|
||||
})
|
||||
ctx$addPendingFlush()
|
||||
.createContext()$invalidate()
|
||||
},
|
||||
run = function() {
|
||||
.createContext = function() {
|
||||
ctx <- Context$new(.label)
|
||||
|
||||
ctx$onInvalidate(function() {
|
||||
lapply(.flushCallbacks, function(func) {
|
||||
lapply(.invalidateCallbacks, function(func) {
|
||||
func()
|
||||
NULL
|
||||
})
|
||||
ctx$addPendingFlush()
|
||||
})
|
||||
|
||||
continue <- function() {
|
||||
ctx$addPendingFlush()
|
||||
}
|
||||
|
||||
if (.suspended == FALSE)
|
||||
continue()
|
||||
else
|
||||
.onResume <<- continue
|
||||
})
|
||||
|
||||
ctx$onFlush(function() {
|
||||
run()
|
||||
})
|
||||
|
||||
return(ctx)
|
||||
},
|
||||
run = function() {
|
||||
ctx <- .createContext()
|
||||
.execCount <<- .execCount + 1L
|
||||
ctx$run(.func)
|
||||
},
|
||||
onInvalidate = function(func) {
|
||||
.flushCallbacks <<- c(.flushCallbacks, func)
|
||||
"Register a function to run when this observer is invalidated"
|
||||
.invalidateCallbacks <<- c(.invalidateCallbacks, func)
|
||||
},
|
||||
suspend = function() {
|
||||
"Causes this observer to stop scheduling flushes (re-executions) in
|
||||
response to invalidations. If the observer was invalidated prior to this
|
||||
call but it has not re-executed yet (because it waits until onFlush is
|
||||
called) then that re-execution will still occur, becasue the flush is
|
||||
already scheduled."
|
||||
.suspended <<- TRUE
|
||||
},
|
||||
resume = function() {
|
||||
"Causes this observer to start re-executing in response to invalidations.
|
||||
If the observer was invalidated while suspended, then it will schedule
|
||||
itself for re-execution (pending flush)."
|
||||
if (.suspended) {
|
||||
.suspended <<- FALSE
|
||||
.onResume()
|
||||
.onResume <<- function() NULL
|
||||
}
|
||||
invisible()
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
#' Create a reactive observer
|
||||
#'
|
||||
#' Creates an observer from the given function. An observer is like a reactive
|
||||
#' function in that it can read reactive values and call reactive functions, and
|
||||
#' Creates an observer from the given expression An observer is like a reactive
|
||||
#' expression in that it can read reactive values and call reactive expressions, and
|
||||
#' will automatically re-execute when those dependencies change. But unlike
|
||||
#' reactive functions, it doesn't yield a result and can't be used as an input
|
||||
#' to other reactive functions. Thus, observers are only useful for their side
|
||||
#' reactive expression, it doesn't yield a result and can't be used as an input
|
||||
#' to other reactive expressions. Thus, observers are only useful for their side
|
||||
#' effects (for example, performing I/O).
|
||||
#'
|
||||
#' Another contrast between reactive functions and observers is their execution
|
||||
#' strategy. Reactive functions use lazy evaluation; that is, when their
|
||||
#' Another contrast between reactive expressions and observers is their execution
|
||||
#' strategy. Reactive expressions use lazy evaluation; that is, when their
|
||||
#' dependencies change, they don't re-execute right away but rather wait until
|
||||
#' they are called by someone else. Indeed, if they are not called then they
|
||||
#' will never re-execute. In contrast, observers use eager evaluation; as soon
|
||||
#' as their dependencies change, they schedule themselves to re-execute.
|
||||
#'
|
||||
#' @param func The function to observe. It must not have any parameters. Any
|
||||
#' return value from this function will be ignored.
|
||||
#'
|
||||
#' @param x An expression (quoted or unquoted). Any return value will be ignored.
|
||||
#' @param env The parent environment for the reactive expression. By default, this
|
||||
#' is the calling environment, the same as when defining an ordinary
|
||||
#' non-reactive expression.
|
||||
#' @param quoted Is the expression quoted? By default, this is \code{FALSE}.
|
||||
#' This is useful when you want to use an expression that is stored in a
|
||||
#' variable; to do so, it must be quoted with `quote()`.
|
||||
#' @param label A label for the observer, useful for debugging.
|
||||
#' @param suspended If \code{TRUE}, start the observer in a suspended state.
|
||||
#' If \code{FALSE} (the default), start in a non-suspended state.
|
||||
#'
|
||||
#' @examples
|
||||
#' values <- reactiveValues(A=1)
|
||||
#'
|
||||
#' obsB <- observe({
|
||||
#' print(values$A + 1)
|
||||
#' })
|
||||
#'
|
||||
#' # Can use quoted expressions
|
||||
#' obsC <- observe(quote({ print(values$A + 2) }), quoted = TRUE)
|
||||
#'
|
||||
#' # To store expressions for later conversion to observe, use quote()
|
||||
#' expr_q <- quote({ print(values$A + 3) })
|
||||
#' obsD <- observe(expr_q, quoted = TRUE)
|
||||
#'
|
||||
#' # In a normal Shiny app, the web client will trigger flush events. If you
|
||||
#' # are at the console, you can force a flush with flushReact()
|
||||
#' shiny:::flushReact()
|
||||
#'
|
||||
#' @export
|
||||
observe <- function(func) {
|
||||
invisible(Observer$new(func, deparse(substitute(func))))
|
||||
observe <- function(x, env=parent.frame(), quoted=FALSE, label=NULL,
|
||||
suspended=FALSE) {
|
||||
|
||||
fun <- exprToFunction(x, env, quoted)
|
||||
if (is.null(label))
|
||||
label <- deparse(body(fun))
|
||||
|
||||
invisible(Observer$new(fun, label=label, suspended=suspended))
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
#' Timer
|
||||
#'
|
||||
#' Creates a reactive timer with the given interval. A reactive timer is like a
|
||||
#' reactive value, except reactive values are triggered when they are set, while
|
||||
#' reactive timers are triggered simply by the passage of time.
|
||||
#'
|
||||
#' \link[=reactive]{Reactive functions} and observers that want to be
|
||||
#' \link[=reactive]{Reactive expressions} and observers that want to be
|
||||
#' invalidated by the timer need to call the timer function that
|
||||
#' \code{reactiveTimer} returns, even if the current time value is not actually
|
||||
#' needed.
|
||||
@@ -492,22 +582,32 @@ invalidateLater <- function(millis) {
|
||||
|
||||
#' Create a non-reactive scope for an expression
|
||||
#'
|
||||
#' Executes the given expression in a scope where reactive values or functions
|
||||
#' Executes the given expression in a scope where reactive values or expression
|
||||
#' can be read, but they cannot cause the reactive scope of the caller to be
|
||||
#' re-evaluated when they change.
|
||||
#'
|
||||
#' Ordinarily, the simple act of reading a reactive value causes a relationship
|
||||
#' to be established between the caller and the reactive value, where a change
|
||||
#' to the reactive value will cause the caller to re-execute. (The same applies
|
||||
#' for the act of getting a reactive function's value.) The \code{isolate}
|
||||
#' function lets you read a reactive value or function without establishing this
|
||||
#' for the act of getting a reactive expression's value.) The \code{isolate}
|
||||
#' function lets you read a reactive value or expression without establishing this
|
||||
#' relationship.
|
||||
#'
|
||||
#' @param expr An expression that can access reactive values or functions.
|
||||
#' The expression given to \code{isolate()} is evaluated in the calling
|
||||
#' environment. This means that if you assign a variable inside the
|
||||
#' \code{isolate()}, its value will be visible outside of the \code{isolate()}.
|
||||
#' If you want to avoid this, you can use \code{\link{local}()} inside the
|
||||
#' \code{isolate()}.
|
||||
#'
|
||||
#' This function can also be useful for calling reactive expression at the
|
||||
#' console, which can be useful for debugging. To do so, simply wrap the
|
||||
#' calls to the reactive expression with \code{isolate()}.
|
||||
#'
|
||||
#' @param expr An expression that can access reactive values or expressions.
|
||||
#'
|
||||
#' @examples
|
||||
#' \dontrun{
|
||||
#' observer(function() {
|
||||
#' observe({
|
||||
#' input$saveButton # Do take a dependency on input$saveButton
|
||||
#'
|
||||
#' # isolate a simple expression
|
||||
@@ -515,7 +615,7 @@ invalidateLater <- function(millis) {
|
||||
#' writeToDatabase(data)
|
||||
#' })
|
||||
#'
|
||||
#' observer(function() {
|
||||
#' observe({
|
||||
#' input$saveButton # Do take a dependency on input$saveButton
|
||||
#'
|
||||
#' # isolate a whole block
|
||||
@@ -526,7 +626,30 @@ invalidateLater <- function(millis) {
|
||||
#' })
|
||||
#' writeToDatabase(data)
|
||||
#' })
|
||||
#'
|
||||
#' observe({
|
||||
#' x <- 1
|
||||
#' # x outside of isolate() is affected
|
||||
#' isolate(x <- 2)
|
||||
#' print(x) # 2
|
||||
#'
|
||||
#' y <- 1
|
||||
#' # Use local() to avoid affecting calling environment
|
||||
#' isolate(local(y <- 2))
|
||||
#' print(y) # 1
|
||||
#' })
|
||||
#'
|
||||
#' }
|
||||
#'
|
||||
#' # Can also use isolate to call reactive expressions from the R console
|
||||
#' values <- reactiveValues(A=1)
|
||||
#' fun <- reactive({ as.character(values$A) })
|
||||
#' isolate(fun())
|
||||
#' # "1"
|
||||
#'
|
||||
#' # isolate also works if the reactive expression accesses values from the
|
||||
#' # input object, like input$x
|
||||
#'
|
||||
#' @export
|
||||
isolate <- function(expr) {
|
||||
ctx <- Context$new('[isolate]')
|
||||
|
||||
17
R/run-url.R
17
R/run-url.R
@@ -3,8 +3,9 @@
|
||||
#' Download and launch a Shiny application that is hosted on GitHub as a gist.
|
||||
#'
|
||||
#' @param gist The identifier of the gist. For example, if the gist is
|
||||
#' https://gist.github.com/3239667, then \code{3239667}, \code{'3239667'}, and
|
||||
#' \code{'https://gist.github.com/3239667'} are all valid values.
|
||||
#' https://gist.github.com/jcheng5/3239667, then \code{3239667},
|
||||
#' \code{'3239667'}, and \code{'https://gist.github.com/jcheng5/3239667'}
|
||||
#' are all valid values.
|
||||
#' @param port The TCP port that the application should listen on. Defaults to
|
||||
#' port 8100.
|
||||
#' @param launch.browser If true, the system's default web browser will be
|
||||
@@ -13,8 +14,11 @@
|
||||
#'
|
||||
#' @examples
|
||||
#' \dontrun{
|
||||
#' runGist(4034323)
|
||||
#' runGist("https://gist.github.com/4034323")
|
||||
#' runGist(3239667)
|
||||
#' runGist("https://gist.github.com/jcheng5/3239667")
|
||||
#'
|
||||
#' # Old URL format without username
|
||||
#' runGist("https://gist.github.com/3239667")
|
||||
#' }
|
||||
#'
|
||||
#' @export
|
||||
@@ -25,7 +29,7 @@ runGist <- function(gist,
|
||||
|
||||
gistUrl <- if (is.numeric(gist) || grepl('^[0-9a-f]+$', gist)) {
|
||||
sprintf('https://gist.github.com/%s/download', gist)
|
||||
} else if(grepl('^https://gist.github.com/([0-9a-f]+)$', gist)) {
|
||||
} else if(grepl('^https://gist.github.com/([^/]+/)?([0-9a-f]+)$', gist)) {
|
||||
paste(gist, '/download', sep='')
|
||||
} else {
|
||||
stop('Unrecognized gist identifier format')
|
||||
@@ -87,6 +91,9 @@ runGitHub <- function(repo, username = getOption("github.user"),
|
||||
#'
|
||||
#' Download and launch a Shiny application that is hosted at a downloadable
|
||||
#' URL. The Shiny application must be saved in a .zip, .tar, or .tar.gz file.
|
||||
#' The Shiny application files must be contained in a subdirectory in the
|
||||
#' archive. For example, the files might be \code{myapp/server.r} and
|
||||
#' \code{myapp/ui.r}.
|
||||
#'
|
||||
#' @param url URL of the application.
|
||||
#' @param filetype The file type (\code{".zip"}, \code{".tar"}, or
|
||||
|
||||
153
R/shiny.R
153
R/shiny.R
@@ -18,6 +18,8 @@ ShinyApp <- setRefClass(
|
||||
.websocket = 'list',
|
||||
.invalidatedOutputValues = 'Map',
|
||||
.invalidatedOutputErrors = 'Map',
|
||||
.outputs = 'list', # Keeps track of all the output observer objects
|
||||
.outputOptions = 'list', # Options for each of the output observer objects
|
||||
.progressKeys = 'character',
|
||||
.fileUploadContext = 'FileUploadContext',
|
||||
session = 'ReactiveValues',
|
||||
@@ -37,6 +39,8 @@ ShinyApp <- setRefClass(
|
||||
session <<- ReactiveValues$new()
|
||||
|
||||
token <<- createUniqueId(16)
|
||||
.outputs <<- list()
|
||||
.outputOptions <<- list()
|
||||
|
||||
allowDataUriScheme <<- TRUE
|
||||
},
|
||||
@@ -49,6 +53,11 @@ ShinyApp <- setRefClass(
|
||||
# jcheng 08/31/2012: User submitted an example of a dynamically calculated
|
||||
# name not working unless name was eagerly evaluated. Yikes!
|
||||
force(name)
|
||||
|
||||
# If overwriting an output object, suspend the previous copy of it
|
||||
if (!is.null(.outputs[[name]])) {
|
||||
.outputs[[name]]$suspend()
|
||||
}
|
||||
|
||||
if (is.function(func)) {
|
||||
if (length(formals(func)) != 0) {
|
||||
@@ -58,7 +67,7 @@ ShinyApp <- setRefClass(
|
||||
}
|
||||
}
|
||||
|
||||
obs <- Observer$new(function() {
|
||||
obs <- observe({
|
||||
|
||||
value <- try(func(), silent=FALSE)
|
||||
|
||||
@@ -74,11 +83,15 @@ ShinyApp <- setRefClass(
|
||||
}
|
||||
else
|
||||
.invalidatedOutputValues$set(name, value)
|
||||
}, label)
|
||||
}, label=label, suspended=TRUE)
|
||||
|
||||
obs$onInvalidate(function() {
|
||||
showProgress(name)
|
||||
})
|
||||
|
||||
.outputs[[name]] <<- obs
|
||||
# Default is to suspend when hidden
|
||||
.outputOptions[[name]][['suspendWhenHidden']] <<- TRUE
|
||||
}
|
||||
else {
|
||||
stop(paste("Unexpected", class(func), "output for", name))
|
||||
@@ -283,25 +296,126 @@ ShinyApp <- setRefClass(
|
||||
return(sprintf('session/%s/download/%s',
|
||||
URLencode(token, TRUE),
|
||||
URLencode(name, TRUE)))
|
||||
},
|
||||
# This function suspends observers for hidden outputs and resumes observers
|
||||
# for un-hidden outputs.
|
||||
manageHiddenOutputs = function() {
|
||||
# Find hidden state for each output, and suspend/resume accordingly
|
||||
for (outputName in names(.outputs)) {
|
||||
# Find corresponding hidden state input variable, with the format
|
||||
# ".shinyout_foo_hidden".
|
||||
# Some tricky stuff: instead of accessing names using session$names(),
|
||||
# get the names directly via session$.values, to avoid triggering reactivity.
|
||||
# Need to handle cases where the output object isn't actually used
|
||||
# in the web page; in these cases, there's no .shinyout_foo_hidden flag,
|
||||
# and hidden should be TRUE. In other words, NULL and TRUE should map
|
||||
# to TRUE, FALSE should map to FALSE.
|
||||
hidden <- session$.values[[paste(".shinyout_", outputName, "_hidden", sep="")]]
|
||||
if (is.null(hidden)) hidden <- TRUE
|
||||
|
||||
if (hidden && .outputOptions[[outputName]][['suspendWhenHidden']]) {
|
||||
.outputs[[outputName]]$suspend()
|
||||
} else {
|
||||
.outputs[[outputName]]$resume()
|
||||
}
|
||||
}
|
||||
},
|
||||
outputOptions = function(name, ...) {
|
||||
# If no name supplied, return the list of options for all outputs
|
||||
if (is.null(name))
|
||||
return(.outputOptions)
|
||||
if (! name %in% names(.outputs))
|
||||
stop(name, " is not in list of output objects")
|
||||
|
||||
opts <- list(...)
|
||||
# If no options are set, return the options for the specified output
|
||||
if (length(opts) == 0)
|
||||
return(.outputOptions[[name]])
|
||||
|
||||
# Set the appropriate option
|
||||
validOpts <- "suspendWhenHidden"
|
||||
for (optname in names(opts)) {
|
||||
if (! optname %in% validOpts)
|
||||
stop(optname, " is not a valid option")
|
||||
|
||||
.outputOptions[[name]][[optname]] <<- opts[[optname]]
|
||||
}
|
||||
|
||||
# If any changes to suspendWhenHidden, need to re-run manageHiddenOutputs
|
||||
if ("suspendWhenHidden" %in% names(opts)) {
|
||||
manageHiddenOutputs()
|
||||
}
|
||||
|
||||
invisible()
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
.createOutputWriter <- function(shinyapp) {
|
||||
ow <- list(impl=shinyapp)
|
||||
class(ow) <- 'shinyoutput'
|
||||
return(ow)
|
||||
structure(list(impl=shinyapp), class='shinyoutput')
|
||||
}
|
||||
|
||||
#' @S3method $<- shinyoutput
|
||||
`$<-.shinyoutput` <- function(x, name, value) {
|
||||
x[['impl']]$defineOutput(name, value, deparse(substitute(value)))
|
||||
.subset2(x, 'impl')$defineOutput(name, value, deparse(substitute(value)))
|
||||
return(invisible(x))
|
||||
}
|
||||
|
||||
#' @S3method [[<- shinyoutput
|
||||
`[[<-.shinyoutput` <- `$<-.shinyoutput`
|
||||
|
||||
#' @S3method $ shinyoutput
|
||||
`$.shinyoutput` <- function(x, name) {
|
||||
stop("Reading objects from shinyoutput object not allowed.")
|
||||
}
|
||||
|
||||
#' @S3method [[ shinyoutput
|
||||
`[[.shinyoutput` <- `$.shinyoutput`
|
||||
|
||||
#' @S3method [ shinyoutput
|
||||
`[.shinyoutput` <- function(values, name) {
|
||||
stop("Single-bracket indexing of shinyoutput object is not allowed.")
|
||||
}
|
||||
|
||||
#' @S3method [<- shinyoutput
|
||||
`[<-.shinyoutput` <- function(values, name, value) {
|
||||
stop("Single-bracket indexing of shinyoutput object is not allowed.")
|
||||
}
|
||||
|
||||
#' Set options for an output object.
|
||||
#'
|
||||
#' These are the available options for an output object:
|
||||
#' \itemize{
|
||||
#' \item suspendWhenHidden. When \code{TRUE} (the default), the output object
|
||||
#' will be suspended (not execute) when it is hidden on the web page. When
|
||||
#' \code{FALSE}, the output object will not suspend when hidden, and if it
|
||||
#' was already hidden and suspended, then it will resume immediately.
|
||||
#' }
|
||||
#'
|
||||
#' @examples
|
||||
#' \dontrun{
|
||||
#' # Get the list of options for all observers within output
|
||||
#' outputOptions(output)
|
||||
#'
|
||||
#' # Disable suspend for output$myplot
|
||||
#' outputOptions(output, "myplot", suspendWhenHidden = FALSE)
|
||||
#'
|
||||
#' # Get the list of options for output$myplot
|
||||
#' outputOptions(output, "myplot")
|
||||
#' }
|
||||
#'
|
||||
#' @param x A shinyoutput object (typically \code{output}).
|
||||
#' @param name The name of an output observer in the shinyoutput object.
|
||||
#' @param ... Options to set for the output observer.
|
||||
#' @export
|
||||
outputOptions <- function(x, name, ...) {
|
||||
if (!inherits(x, "shinyoutput"))
|
||||
stop("x must be a shinyoutput object.")
|
||||
|
||||
.subset2(x, 'impl')$outputOptions(name, ...)
|
||||
}
|
||||
|
||||
|
||||
resolve <- function(dir, relpath) {
|
||||
abs.path <- file.path(dir, relpath)
|
||||
if (!file.exists(abs.path))
|
||||
@@ -320,7 +434,11 @@ resolve <- function(dir, relpath) {
|
||||
httpResponse <- function(status = 200,
|
||||
content_type = "text/html; charset=UTF-8",
|
||||
content = "",
|
||||
headers = c()) {
|
||||
headers = list()) {
|
||||
# Make sure it's a list, not a vector
|
||||
headers <- as.list(headers)
|
||||
if (is.null(headers$`X-UA-Compatible`))
|
||||
headers$`X-UA-Compatible` <- "chrome=1"
|
||||
resp <- list(status = status, content_type = content_type, content = content,
|
||||
headers = headers)
|
||||
class(resp) <- 'httpResponse'
|
||||
@@ -584,7 +702,7 @@ resourcePathHandler <- function(ws, header) {
|
||||
#' # A very simple Shiny app that takes a message from the user
|
||||
#' # and outputs an uppercase version of it.
|
||||
#' shinyServer(function(input, output) {
|
||||
#' output$uppercase <- reactiveText(function() {
|
||||
#' output$uppercase <- renderText({
|
||||
#' toupper(input$message)
|
||||
#' })
|
||||
#' })
|
||||
@@ -730,6 +848,7 @@ startApp <- function(port=8101L) {
|
||||
msg$data[[ splitName[[1]] ]] <- switch(
|
||||
splitName[[2]],
|
||||
matrix = unpackMatrix(val),
|
||||
number = ifelse(is.null(val), NA, val),
|
||||
stop('Unknown type specified for ', name)
|
||||
)
|
||||
}
|
||||
@@ -766,7 +885,6 @@ startApp <- function(port=8101L) {
|
||||
shinyapp$allowDataUriScheme <- msg$data[['__allowDataUriScheme']]
|
||||
msg$data[['__allowDataUriScheme']] <- NULL
|
||||
shinyapp$session$mset(msg$data)
|
||||
flushReact()
|
||||
local({
|
||||
serverFunc(input=.createReactiveValues(shinyapp$session, readonly=TRUE),
|
||||
output=.createOutputWriter(shinyapp))
|
||||
@@ -777,6 +895,7 @@ startApp <- function(port=8101L) {
|
||||
},
|
||||
shinyapp$dispatch(msg)
|
||||
)
|
||||
shinyapp$manageHiddenOutputs()
|
||||
flushReact()
|
||||
lapply(apps$values(), function(shinyapp) {
|
||||
shinyapp$flushOutput()
|
||||
@@ -796,11 +915,15 @@ startApp <- function(port=8101L) {
|
||||
# @param ws_env The return value from \code{\link{startApp}}.
|
||||
serviceApp <- function(ws_env) {
|
||||
if (timerCallbacks$executeElapsed()) {
|
||||
for (shinyapp in apps$values()) {
|
||||
shinyapp$manageHiddenOutputs()
|
||||
}
|
||||
|
||||
flushReact()
|
||||
lapply(apps$values(), function(shinyapp) {
|
||||
shinyapp$flushOutput()
|
||||
NULL
|
||||
})
|
||||
|
||||
for (shinyapp in apps$values()) {
|
||||
shinyapp$flushOutput()
|
||||
}
|
||||
}
|
||||
|
||||
# If this R session is interactive, then call service() with a short timeout
|
||||
@@ -902,8 +1025,8 @@ runExample <- function(example=NA,
|
||||
# The only difference is that, if the protocol is https, it changes the
|
||||
# download settings, depending on platform.
|
||||
download <- function(url, ...) {
|
||||
# First, check protocol. If https, check platform:
|
||||
if (grepl('^https://', url)) {
|
||||
# First, check protocol. If http or https, check platform:
|
||||
if (grepl('^https?://', url)) {
|
||||
|
||||
# If Windows, call setInternet2, then use download.file with defaults.
|
||||
if (.Platform$OS.type == "windows") {
|
||||
|
||||
@@ -5,7 +5,7 @@ suppressPackageStartupMessages({
|
||||
|
||||
#' Plot Output
|
||||
#'
|
||||
#' Creates a reactive plot that is suitable for assigning to an \code{output}
|
||||
#' Renders a reactive plot that is suitable for assigning to an \code{output}
|
||||
#' slot.
|
||||
#'
|
||||
#' The corresponding HTML output tag should be \code{div} or \code{img} and have
|
||||
@@ -17,7 +17,7 @@ suppressPackageStartupMessages({
|
||||
#' output. Notably, plain \code{png} output on Linux and Windows may not
|
||||
#' antialias some point shapes, resulting in poor quality output.
|
||||
#'
|
||||
#' @param func A function that generates a plot.
|
||||
#' @param expr An expression that generates a plot.
|
||||
#' @param width The width of the rendered plot, in pixels; or \code{'auto'} to
|
||||
#' use the \code{offsetWidth} of the HTML element that is bound to this plot.
|
||||
#' You can also pass in a function that returns the width in pixels or
|
||||
@@ -30,15 +30,28 @@ suppressPackageStartupMessages({
|
||||
#' values and functions.
|
||||
#' @param ... Arguments to be passed through to \code{\link[grDevices]{png}}.
|
||||
#' These can be used to set the width, height, background color, etc.
|
||||
#' @param env The environment in which to evaluate \code{expr}.
|
||||
#' @param quoted Is \code{expr} a quoted expression (with \code{quote()})? This
|
||||
#' is useful if you want to save an expression in a variable.
|
||||
#' @param func A function that generates a plot (deprecated; use \code{expr}
|
||||
#' instead).
|
||||
#'
|
||||
#' @export
|
||||
reactivePlot <- function(func, width='auto', height='auto', ...) {
|
||||
renderPlot <- function(expr, width='auto', height='auto', ...,
|
||||
env=parent.frame(), quoted=FALSE, func=NULL) {
|
||||
if (!is.null(func)) {
|
||||
shinyDeprecated(msg="renderPlot: argument 'func' is deprecated. Please use 'expr' instead.")
|
||||
} else {
|
||||
func <- exprToFunction(expr, env, quoted)
|
||||
}
|
||||
|
||||
|
||||
args <- list(...)
|
||||
|
||||
if (is.function(width))
|
||||
width <- reactive(width)
|
||||
width <- reactive({ width() })
|
||||
if (is.function(height))
|
||||
height <- reactive(height)
|
||||
height <- reactive({ height() })
|
||||
|
||||
return(function(shinyapp, name, ...) {
|
||||
png.file <- tempfile(fileext='.png')
|
||||
@@ -102,14 +115,25 @@ reactivePlot <- function(func, width='auto', height='auto', ...) {
|
||||
#' The corresponding HTML output tag should be \code{div} and have the CSS class
|
||||
#' name \code{shiny-html-output}.
|
||||
#'
|
||||
#' @param func A function that returns an R object that can be used with
|
||||
#' @param expr An expression that returns an R object that can be used with
|
||||
#' \code{\link[xtable]{xtable}}.
|
||||
#' @param ... Arguments to be passed through to \code{\link[xtable]{xtable}} and
|
||||
#' \code{\link[xtable]{print.xtable}}.
|
||||
#' @param env The environment in which to evaluate \code{expr}.
|
||||
#' @param quoted Is \code{expr} a quoted expression (with \code{quote()})? This
|
||||
#' is useful if you want to save an expression in a variable.
|
||||
#' @param func A function that returns an R object that can be used with
|
||||
#' \code{\link[xtable]{xtable}} (deprecated; use \code{expr} instead).
|
||||
#'
|
||||
#' @export
|
||||
reactiveTable <- function(func, ...) {
|
||||
reactive(function() {
|
||||
renderTable <- function(expr, ..., env=parent.frame(), quoted=FALSE, func=NULL) {
|
||||
if (!is.null(func)) {
|
||||
shinyDeprecated(msg="renderTable: argument 'func' is deprecated. Please use 'expr' instead.")
|
||||
} else {
|
||||
func <- exprToFunction(expr, env, quoted)
|
||||
}
|
||||
|
||||
function() {
|
||||
classNames <- getOption('shiny.table.class', 'data table table-bordered table-condensed')
|
||||
data <- func()
|
||||
|
||||
@@ -125,7 +149,7 @@ reactiveTable <- function(func, ...) {
|
||||
'"',
|
||||
sep=''), ...)),
|
||||
collapse="\n"))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#' Printable Output
|
||||
@@ -146,23 +170,33 @@ reactiveTable <- function(func, ...) {
|
||||
#' returns \code{NULL} then \code{NULL} will actually be visible in the output.
|
||||
#' To display nothing, make your function return \code{\link{invisible}()}.
|
||||
#'
|
||||
#' @param func A function that may print output and/or return a printable R
|
||||
#' @param expr An expression that may print output and/or return a printable R
|
||||
#' object.
|
||||
#' @param env The environment in which to evaluate \code{expr}.
|
||||
#' @param quoted Is \code{expr} a quoted expression (with \code{quote()})? This
|
||||
#' @param func A function that may print output and/or return a printable R
|
||||
#' object (deprecated; use \code{expr} instead).
|
||||
#'
|
||||
#' @seealso \code{\link{reactiveText}} for displaying the value returned from a
|
||||
#' @seealso \code{\link{renderText}} for displaying the value returned from a
|
||||
#' function, instead of the printed output.
|
||||
#'
|
||||
#' @example res/text-example.R
|
||||
#'
|
||||
#' @export
|
||||
reactivePrint <- function(func) {
|
||||
reactive(function() {
|
||||
renderPrint <- function(expr, env=parent.frame(), quoted=FALSE, func=NULL) {
|
||||
if (!is.null(func)) {
|
||||
shinyDeprecated(msg="renderPrint: argument 'func' is deprecated. Please use 'expr' instead.")
|
||||
} else {
|
||||
func <- exprToFunction(expr, env, quoted)
|
||||
}
|
||||
|
||||
function() {
|
||||
return(paste(capture.output({
|
||||
result <- withVisible(func())
|
||||
if (result$visible)
|
||||
print(result$value)
|
||||
}), collapse="\n"))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#' Text Output
|
||||
@@ -178,20 +212,31 @@ reactivePrint <- function(func) {
|
||||
#' The result of executing \code{func} will passed to \code{cat}, inside a
|
||||
#' \code{\link[utils]{capture.output}} call.
|
||||
#'
|
||||
#' @param func A function that returns an R object that can be used as an
|
||||
#' @param expr An expression that returns an R object that can be used as an
|
||||
#' argument to \code{cat}.
|
||||
#' @param env The environment in which to evaluate \code{expr}.
|
||||
#' @param quoted Is \code{expr} a quoted expression (with \code{quote()})? This
|
||||
#' is useful if you want to save an expression in a variable.
|
||||
#' @param func A function that returns an R object that can be used as an
|
||||
#' argument to \code{cat}.(deprecated; use \code{expr} instead).
|
||||
#'
|
||||
#' @seealso \code{\link{reactivePrint}} for capturing the print output of a
|
||||
#' @seealso \code{\link{renderPrint}} for capturing the print output of a
|
||||
#' function, rather than the returned text value.
|
||||
#'
|
||||
#' @example res/text-example.R
|
||||
#'
|
||||
#' @export
|
||||
reactiveText <- function(func) {
|
||||
reactive(function() {
|
||||
renderText <- function(expr, env=parent.frame(), quoted=FALSE, func=NULL) {
|
||||
if (!is.null(func)) {
|
||||
shinyDeprecated(msg="renderText: argument 'func' is deprecated. Please use 'expr' instead.")
|
||||
} else {
|
||||
func <- exprToFunction(expr, env, quoted)
|
||||
}
|
||||
|
||||
function() {
|
||||
value <- func()
|
||||
return(paste(capture.output(cat(value)), collapse="\n"))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#' UI Output
|
||||
@@ -202,28 +247,39 @@ reactiveText <- function(func) {
|
||||
#' The corresponding HTML output tag should be \code{div} and have the CSS class
|
||||
#' name \code{shiny-html-output} (or use \code{\link{uiOutput}}).
|
||||
#'
|
||||
#' @param func A function that returns a Shiny tag object, \code{\link{HTML}},
|
||||
#' @param expr An expression that returns a Shiny tag object, \code{\link{HTML}},
|
||||
#' or a list of such objects.
|
||||
#' @param env The environment in which to evaluate \code{expr}.
|
||||
#' @param quoted Is \code{expr} a quoted expression (with \code{quote()})? This
|
||||
#' is useful if you want to save an expression in a variable.
|
||||
#' @param func A function that returns a Shiny tag object, \code{\link{HTML}},
|
||||
#' or a list of such objects (deprecated; use \code{expr} instead).
|
||||
#'
|
||||
#' @seealso conditionalPanel
|
||||
#'
|
||||
#' @export
|
||||
#' @examples
|
||||
#' \dontrun{
|
||||
#' output$moreControls <- reactiveUI(function() {
|
||||
#' output$moreControls <- renderUI({
|
||||
#' list(
|
||||
#'
|
||||
#' )
|
||||
#' })
|
||||
#' }
|
||||
reactiveUI <- function(func) {
|
||||
reactive(function() {
|
||||
renderUI <- function(expr, env=parent.frame(), quoted=FALSE, func=NULL) {
|
||||
if (!is.null(func)) {
|
||||
shinyDeprecated(msg="renderUI: argument 'func' is deprecated. Please use 'expr' instead.")
|
||||
} else {
|
||||
func <- exprToFunction(expr, env, quoted)
|
||||
}
|
||||
|
||||
function() {
|
||||
result <- func()
|
||||
if (is.null(result) || length(result) == 0)
|
||||
return(NULL)
|
||||
# Wrap result in tagList in case it is an ordinary list
|
||||
return(as.character(tagList(result)))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#' File Downloads
|
||||
@@ -271,4 +327,61 @@ downloadHandler <- function(filename, content, contentType=NA) {
|
||||
return(function(shinyapp, name, ...) {
|
||||
shinyapp$registerDownload(name, filename, contentType, content)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Deprecated functions ------------------------------------------------------
|
||||
|
||||
#' Plot output (deprecated)
|
||||
#'
|
||||
#' See \code{\link{renderPlot}}.
|
||||
#' @param func A function.
|
||||
#' @param width Width.
|
||||
#' @param height Height.
|
||||
#' @param ... Other arguments to pass on.
|
||||
#' @export
|
||||
reactivePlot <- function(func, width='auto', height='auto', ...) {
|
||||
shinyDeprecated(new="renderPlot")
|
||||
renderPlot({ func() }, width='auto', height='auto', ...)
|
||||
}
|
||||
|
||||
#' Table output (deprecated)
|
||||
#'
|
||||
#' See \code{\link{renderTable}}.
|
||||
#' @param func A function.
|
||||
#' @param ... Other arguments to pass on.
|
||||
#' @export
|
||||
reactiveTable <- function(func, ...) {
|
||||
shinyDeprecated(new="renderTable")
|
||||
renderTable({ func() })
|
||||
}
|
||||
|
||||
#' Print output (deprecated)
|
||||
#'
|
||||
#' See \code{\link{renderPrint}}.
|
||||
#' @param func A function.
|
||||
#' @export
|
||||
reactivePrint <- function(func) {
|
||||
shinyDeprecated(new="renderPrint")
|
||||
renderPrint({ func() })
|
||||
}
|
||||
|
||||
#' UI output (deprecated)
|
||||
#'
|
||||
#' See \code{\link{renderUI}}.
|
||||
#' @param func A function.
|
||||
#' @export
|
||||
reactiveUI <- function(func) {
|
||||
shinyDeprecated(new="renderUI")
|
||||
renderUI({ func() })
|
||||
}
|
||||
|
||||
#' Text output (deprecated)
|
||||
#'
|
||||
#' See \code{\link{renderText}}.
|
||||
#' @param func A function.
|
||||
#' @export
|
||||
reactiveText <- function(func) {
|
||||
shinyDeprecated(new="renderText")
|
||||
renderText({ func() })
|
||||
}
|
||||
|
||||
110
R/utils.R
110
R/utils.R
@@ -101,4 +101,112 @@ knownContentTypes$mset(
|
||||
|
||||
getContentType <- function(ext, defaultType='application/octet-stream') {
|
||||
knownContentTypes$get(tolower(ext)) %OR% defaultType
|
||||
}
|
||||
}
|
||||
|
||||
# Create a zero-arg function from a quoted expression and environment
|
||||
# @examples
|
||||
# makeFunction(body=quote(print(3)))
|
||||
makeFunction <- function(args = pairlist(), body, env = parent.frame()) {
|
||||
eval(call("function", args, body), env)
|
||||
}
|
||||
|
||||
#' Convert an expression or quoted expression to a function
|
||||
#'
|
||||
#' This is to be called from another function, because it will attempt to get
|
||||
#' an unquoted expression from two calls back.
|
||||
#'
|
||||
#' If expr is a quoted expression, then this just converts it to a function.
|
||||
#' If expr is a function, then this simply returns expr (and prints a
|
||||
#' deprecation message.
|
||||
#' If expr was a non-quoted expression from two calls back, then this will
|
||||
#' quote the original expression and convert it to a function.
|
||||
#
|
||||
#' @param expr A quoted or unquoted expression, or a function.
|
||||
#' @param env The desired environment for the function. Defaults to the
|
||||
#' calling environment two steps back.
|
||||
#' @param quoted Is the expression quoted?
|
||||
#'
|
||||
#' @examples
|
||||
#' # Example of a new renderer, similar to renderText
|
||||
#' # This is something that toolkit authors will do
|
||||
#' renderTriple <- function(expr, env=parent.frame(), quoted=FALSE) {
|
||||
#' # Convert expr to a function
|
||||
#' func <- shiny::exprToFunction(expr, env, quoted)
|
||||
#'
|
||||
#' function() {
|
||||
#' value <- func()
|
||||
#' paste(rep(value, 3), collapse=", ")
|
||||
#' }
|
||||
#' }
|
||||
#'
|
||||
#'
|
||||
#' # Example of using the renderer.
|
||||
#' # This is something that app authors will do.
|
||||
#' values <- reactiveValues(A="text")
|
||||
#'
|
||||
#' \dontrun{
|
||||
#' # Create an output object
|
||||
#' output$tripleA <- renderTriple({
|
||||
#' values$A
|
||||
#' })
|
||||
#' }
|
||||
#'
|
||||
#' # At the R console, you can experiment with the renderer using isolate()
|
||||
#' tripleA <- renderTriple({
|
||||
#' values$A
|
||||
#' })
|
||||
#'
|
||||
#' isolate(tripleA())
|
||||
#' # "text, text, text"
|
||||
#'
|
||||
#' @export
|
||||
exprToFunction <- function(expr, env=parent.frame(2), quoted=FALSE) {
|
||||
# Get the quoted expr from two calls back
|
||||
expr_sub <- eval(substitute(substitute(expr)), parent.frame())
|
||||
|
||||
# Check if expr is a function, making sure not to evaluate expr, in case it
|
||||
# is actually an unquoted expression.
|
||||
# If expr is a single token, then indexing with [[ will error; if it has multiple
|
||||
# tokens, then [[ works. In the former case it will be a name object; in the
|
||||
# latter, it will be a language object.
|
||||
if (!is.name(expr_sub) && expr_sub[[1]] == as.name('function')) {
|
||||
# Get name of function that called this function
|
||||
called_fun <- sys.call(-1)[[1]]
|
||||
|
||||
shinyDeprecated(msg = paste("Passing functions to '", called_fun,
|
||||
"' is deprecated. Please use expressions instead. See ?", called_fun,
|
||||
" for more information.", sep=""))
|
||||
return(expr)
|
||||
}
|
||||
|
||||
if (quoted) {
|
||||
# expr is a quoted expression
|
||||
makeFunction(body=expr, env=env)
|
||||
} else {
|
||||
# expr is an unquoted expression
|
||||
makeFunction(body=expr_sub, env=env)
|
||||
}
|
||||
}
|
||||
|
||||
#' Print message for deprecated functions in Shiny
|
||||
#'
|
||||
#' To disable these messages, use \code{options(shiny.deprecation.messages=FALSE)}.
|
||||
#'
|
||||
#' @param new Name of replacement function.
|
||||
#' @param msg Message to print. If used, this will override the default message.
|
||||
#' @param old Name of deprecated function.
|
||||
shinyDeprecated <- function(new=NULL, msg=NULL,
|
||||
old=as.character(sys.call(sys.parent()))[1L]) {
|
||||
|
||||
if (getOption("shiny.deprecation.messages", default=TRUE) == FALSE)
|
||||
return(invisible())
|
||||
|
||||
if (is.null(msg)) {
|
||||
msg <- paste(old, "is deprecated.")
|
||||
if (!is.null(new))
|
||||
msg <- paste(msg, "Please use", new, "instead.",
|
||||
"To disable this message, run options(shiny.deprecation.messages=FALSE)")
|
||||
}
|
||||
# Similar to .Deprecated(), but print a message instead of warning
|
||||
message(msg)
|
||||
}
|
||||
|
||||
@@ -3,14 +3,14 @@ library(shiny)
|
||||
# Define server logic required to generate and plot a random distribution
|
||||
shinyServer(function(input, output) {
|
||||
|
||||
# Function that generates a plot of the distribution. The function
|
||||
# is wrapped in a call to reactivePlot to indicate that:
|
||||
# Expression that generates a plot of the distribution. The expression
|
||||
# is wrapped in a call to renderPlot to indicate that:
|
||||
#
|
||||
# 1) It is "reactive" and therefore should be automatically
|
||||
# re-executed when inputs change
|
||||
# 2) Its output type is a plot
|
||||
#
|
||||
output$distPlot <- reactivePlot(function() {
|
||||
output$distPlot <- renderPlot({
|
||||
|
||||
# generate an rnorm distribution and plot it
|
||||
dist <- rnorm(input$obs)
|
||||
|
||||
@@ -5,7 +5,7 @@ library(datasets)
|
||||
shinyServer(function(input, output) {
|
||||
|
||||
# Return the requested dataset
|
||||
datasetInput <- reactive(function() {
|
||||
datasetInput <- reactive({
|
||||
switch(input$dataset,
|
||||
"rock" = rock,
|
||||
"pressure" = pressure,
|
||||
@@ -13,13 +13,13 @@ shinyServer(function(input, output) {
|
||||
})
|
||||
|
||||
# Generate a summary of the dataset
|
||||
output$summary <- reactivePrint(function() {
|
||||
output$summary <- renderPrint({
|
||||
dataset <- datasetInput()
|
||||
summary(dataset)
|
||||
})
|
||||
|
||||
# Show the first "n" observations
|
||||
output$view <- reactiveTable(function() {
|
||||
output$view <- renderTable({
|
||||
head(datasetInput(), n = input$obs)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -4,47 +4,47 @@ library(datasets)
|
||||
# Define server logic required to summarize and view the selected dataset
|
||||
shinyServer(function(input, output) {
|
||||
|
||||
# By declaring databaseInput as a reactive function we ensure that:
|
||||
# By declaring databaseInput as a reactive expression we ensure that:
|
||||
#
|
||||
# 1) It is only called when the inputs it depends on changes
|
||||
# 2) The computation and result are shared by all the callers (it
|
||||
# only executes a single time)
|
||||
# 3) When the inputs change and the function is re-executed, the
|
||||
# 3) When the inputs change and the expression is re-executed, the
|
||||
# new result is compared to the previous result; if the two are
|
||||
# identical, then the callers are not notified
|
||||
#
|
||||
datasetInput <- reactive(function() {
|
||||
datasetInput <- reactive({
|
||||
switch(input$dataset,
|
||||
"rock" = rock,
|
||||
"pressure" = pressure,
|
||||
"cars" = cars)
|
||||
})
|
||||
|
||||
# The output$caption is computed based on a reactive function that
|
||||
# The output$caption is computed based on a reactive expression that
|
||||
# returns input$caption. When the user changes the "caption" field:
|
||||
#
|
||||
# 1) This function is automatically called to recompute the output
|
||||
# 2) The new caption is pushed back to the browser for re-display
|
||||
#
|
||||
# Note that because the data-oriented reactive functions below don't
|
||||
# depend on input$caption, those functions are NOT called when
|
||||
# Note that because the data-oriented reactive expressions below don't
|
||||
# depend on input$caption, those expressions are NOT called when
|
||||
# input$caption changes.
|
||||
output$caption <- reactiveText(function() {
|
||||
output$caption <- renderText({
|
||||
input$caption
|
||||
})
|
||||
|
||||
# The output$summary depends on the datasetInput reactive function,
|
||||
# The output$summary depends on the datasetInput reactive expression,
|
||||
# so will be re-executed whenever datasetInput is re-executed
|
||||
# (i.e. whenever the input$dataset changes)
|
||||
output$summary <- reactivePrint(function() {
|
||||
output$summary <- renderPrint({
|
||||
dataset <- datasetInput()
|
||||
summary(dataset)
|
||||
})
|
||||
|
||||
# The output$view depends on both the databaseInput reactive function
|
||||
# The output$view depends on both the databaseInput reactive expression
|
||||
# and input$obs, so will be re-executed whenever input$dataset or
|
||||
# input$obs is changed.
|
||||
output$view <- reactiveTable(function() {
|
||||
output$view <- renderTable({
|
||||
head(datasetInput(), n = input$obs)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -11,20 +11,20 @@ mpgData$am <- factor(mpgData$am, labels = c("Automatic", "Manual"))
|
||||
# Define server logic required to plot various variables against mpg
|
||||
shinyServer(function(input, output) {
|
||||
|
||||
# Compute the forumla text in a reactive function since it is
|
||||
# Compute the forumla text in a reactive expression since it is
|
||||
# shared by the output$caption and output$mpgPlot functions
|
||||
formulaText <- reactive(function() {
|
||||
formulaText <- reactive({
|
||||
paste("mpg ~", input$variable)
|
||||
})
|
||||
|
||||
# Return the formula text for printing as a caption
|
||||
output$caption <- reactiveText(function() {
|
||||
output$caption <- renderText({
|
||||
formulaText()
|
||||
})
|
||||
|
||||
# Generate a plot of the requested variable against mpg and only
|
||||
# include outliers if requested
|
||||
output$mpgPlot <- reactivePlot(function() {
|
||||
output$mpgPlot <- renderPlot({
|
||||
boxplot(as.formula(formulaText()),
|
||||
data = mpgData,
|
||||
outline = input$outliers)
|
||||
|
||||
@@ -3,8 +3,8 @@ library(shiny)
|
||||
# Define server logic for slider examples
|
||||
shinyServer(function(input, output) {
|
||||
|
||||
# Reactive function to compose a data frame containing all of the values
|
||||
sliderValues <- reactive(function() {
|
||||
# Reactive expression to compose a data frame containing all of the values
|
||||
sliderValues <- reactive({
|
||||
|
||||
# Compose data frame
|
||||
data.frame(
|
||||
@@ -22,7 +22,7 @@ shinyServer(function(input, output) {
|
||||
})
|
||||
|
||||
# Show the values using an HTML table
|
||||
output$values <- reactiveTable(function() {
|
||||
output$values <- renderTable({
|
||||
sliderValues()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -3,10 +3,10 @@ library(shiny)
|
||||
# Define server logic for random distribution application
|
||||
shinyServer(function(input, output) {
|
||||
|
||||
# Reactive function to generate the requested distribution. This is
|
||||
# Reactive expression to generate the requested distribution. This is
|
||||
# called whenever the inputs change. The output functions defined
|
||||
# below then all use the value computed from this function
|
||||
data <- reactive(function() {
|
||||
# below then all use the value computed from this expression
|
||||
data <- reactive({
|
||||
dist <- switch(input$dist,
|
||||
norm = rnorm,
|
||||
unif = runif,
|
||||
@@ -19,9 +19,9 @@ shinyServer(function(input, output) {
|
||||
|
||||
# Generate a plot of the data. Also uses the inputs to build the
|
||||
# plot label. Note that the dependencies on both the inputs and
|
||||
# the data reactive function are both tracked, and all functions
|
||||
# the data reactive expression are both tracked, and all expressions
|
||||
# are called in the sequence implied by the dependency graph
|
||||
output$plot <- reactivePlot(function() {
|
||||
output$plot <- renderPlot({
|
||||
dist <- input$dist
|
||||
n <- input$n
|
||||
|
||||
@@ -30,12 +30,12 @@ shinyServer(function(input, output) {
|
||||
})
|
||||
|
||||
# Generate a summary of the data
|
||||
output$summary <- reactivePrint(function() {
|
||||
output$summary <- renderPrint({
|
||||
summary(data())
|
||||
})
|
||||
|
||||
# Generate an HTML table view of the data
|
||||
output$table <- reactiveTable(function() {
|
||||
output$table <- renderTable({
|
||||
data.frame(x=data())
|
||||
})
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ library(datasets)
|
||||
shinyServer(function(input, output) {
|
||||
|
||||
# Return the requested dataset
|
||||
datasetInput <- reactive(function() {
|
||||
datasetInput <- reactive({
|
||||
switch(input$dataset,
|
||||
"rock" = rock,
|
||||
"pressure" = pressure,
|
||||
@@ -13,13 +13,13 @@ shinyServer(function(input, output) {
|
||||
})
|
||||
|
||||
# Generate a summary of the dataset
|
||||
output$summary <- reactivePrint(function() {
|
||||
output$summary <- renderPrint({
|
||||
dataset <- datasetInput()
|
||||
summary(dataset)
|
||||
})
|
||||
|
||||
# Show the first "n" observations
|
||||
output$view <- reactiveTable(function() {
|
||||
output$view <- renderTable({
|
||||
head(datasetInput(), n = input$obs)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -3,10 +3,10 @@ library(shiny)
|
||||
# Define server logic for random distribution application
|
||||
shinyServer(function(input, output) {
|
||||
|
||||
# Reactive function to generate the requested distribution. This is
|
||||
# called whenever the inputs change. The output functions defined
|
||||
# below then all used the value computed from this function
|
||||
data <- reactive(function() {
|
||||
# Reactive expression to generate the requested distribution. This is
|
||||
# called whenever the inputs change. The output expressions defined
|
||||
# below then all used the value computed from this expression
|
||||
data <- reactive({
|
||||
dist <- switch(input$dist,
|
||||
norm = rnorm,
|
||||
unif = runif,
|
||||
@@ -19,9 +19,9 @@ shinyServer(function(input, output) {
|
||||
|
||||
# Generate a plot of the data. Also uses the inputs to build the
|
||||
# plot label. Note that the dependencies on both the inputs and
|
||||
# the data reactive function are both tracked, and all functions
|
||||
# the data reactive expression are both tracked, and all expressions
|
||||
# are called in the sequence implied by the dependency graph
|
||||
output$plot <- reactivePlot(function() {
|
||||
output$plot <- renderPlot({
|
||||
dist <- input$dist
|
||||
n <- input$n
|
||||
|
||||
@@ -30,12 +30,12 @@ shinyServer(function(input, output) {
|
||||
})
|
||||
|
||||
# Generate a summary of the data
|
||||
output$summary <- reactivePrint(function() {
|
||||
output$summary <- renderPrint({
|
||||
summary(data())
|
||||
})
|
||||
|
||||
# Generate an HTML table view of the data
|
||||
output$table <- reactiveTable(function() {
|
||||
output$table <- renderTable({
|
||||
data.frame(x=data())
|
||||
})
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
library(shiny)
|
||||
|
||||
shinyServer(function(input, output) {
|
||||
output$contents <- reactiveTable(function() {
|
||||
output$contents <- renderTable({
|
||||
|
||||
# input$file1 will be NULL initially. After the user selects and uploads a
|
||||
# file, it will be a data frame with 'name', 'size', 'type', and 'data'
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
shinyServer(function(input, output) {
|
||||
datasetInput <- reactive(function() {
|
||||
datasetInput <- reactive({
|
||||
switch(input$dataset,
|
||||
"rock" = rock,
|
||||
"pressure" = pressure,
|
||||
"cars" = cars)
|
||||
})
|
||||
|
||||
output$table <- reactiveTable(function() {
|
||||
output$table <- renderTable({
|
||||
datasetInput()
|
||||
})
|
||||
|
||||
|
||||
73
inst/tests/test-gc.r
Normal file
73
inst/tests/test-gc.r
Normal file
@@ -0,0 +1,73 @@
|
||||
context("garbage collection")
|
||||
|
||||
test_that("unreferenced observers are garbage collected", {
|
||||
vals_removed <- FALSE
|
||||
obs_removed <- FALSE
|
||||
vals <- reactiveValues(A=1)
|
||||
obs <- observe({ vals$A })
|
||||
|
||||
# These are called when the objects are garbage-collected
|
||||
reg.finalizer(attr(.subset2(vals,'impl'), ".xData"),
|
||||
function(e) vals_removed <<- TRUE)
|
||||
reg.finalizer(attr(obs, ".xData"),
|
||||
function(e) obs_removed <<- TRUE)
|
||||
|
||||
flushReact()
|
||||
|
||||
# Removing this reference to obs doesn't delete it because vals still has a
|
||||
# reference to it
|
||||
rm(obs)
|
||||
invisible(gc())
|
||||
expect_equal(c(vals_removed, obs_removed), c(FALSE, FALSE))
|
||||
|
||||
# Updating vals$A and flushing won't make obs go away because it creates a new
|
||||
# context, and vals$A's context tracks obs's context as a dependent
|
||||
vals$A <- 2
|
||||
flushReact()
|
||||
invisible(gc())
|
||||
expect_equal(c(vals_removed, obs_removed), c(FALSE, FALSE))
|
||||
|
||||
# Removing vals will result in vals and obs being garbage collected since
|
||||
# there are no other references to them
|
||||
rm(vals)
|
||||
invisible(gc())
|
||||
expect_equal(c(vals_removed, obs_removed), c(TRUE, TRUE))
|
||||
})
|
||||
|
||||
|
||||
test_that("suspended observers are garbage collected", {
|
||||
vals_removed <- FALSE
|
||||
obs_removed <- FALSE
|
||||
vals <- reactiveValues(A=1)
|
||||
obs <- observe({ vals$A })
|
||||
|
||||
# These are called when the objects are garbage-collected
|
||||
reg.finalizer(attr(.subset2(vals,'impl'), ".xData"),
|
||||
function(e) vals_removed <<- TRUE)
|
||||
reg.finalizer(attr(obs, ".xData"),
|
||||
function(e) obs_removed <<- TRUE)
|
||||
|
||||
flushReact()
|
||||
|
||||
vals$A <- 2
|
||||
flushReact()
|
||||
invisible(gc())
|
||||
|
||||
# Simply suspending and removing our reference to obs doesn't result in GC,
|
||||
# because vals's context still has a reference to obs's context, as a dependent
|
||||
obs$suspend()
|
||||
rm(obs)
|
||||
invisible(gc())
|
||||
expect_equal(c(vals_removed, obs_removed), c(FALSE, FALSE))
|
||||
|
||||
# Next time we update vals$A and flush, there's no more reference to obs
|
||||
vals$A <- 3
|
||||
flushReact()
|
||||
invisible(gc())
|
||||
expect_equal(c(vals_removed, obs_removed), c(FALSE, TRUE))
|
||||
|
||||
# Deleting vals should work immediately now
|
||||
rm(vals)
|
||||
invisible(gc()) # Removes vals object
|
||||
expect_equal(c(vals_removed, obs_removed), c(TRUE, TRUE))
|
||||
})
|
||||
@@ -59,16 +59,16 @@ test_that("Functions are not over-reactive", {
|
||||
|
||||
values <- reactiveValues(A=10)
|
||||
|
||||
funcA <- reactive(function() {
|
||||
funcA <- reactive({
|
||||
values$A
|
||||
})
|
||||
|
||||
funcB <- reactive(function() {
|
||||
funcB <- reactive({
|
||||
funcA()
|
||||
values$A
|
||||
})
|
||||
|
||||
obsC <- observe(function() {
|
||||
obsC <- observe({
|
||||
funcB()
|
||||
})
|
||||
|
||||
@@ -100,13 +100,13 @@ test_that("overreactivity2", {
|
||||
observed_value2 <- NA
|
||||
|
||||
values <- reactiveValues(A=1)
|
||||
funcB <- reactive(function() {
|
||||
funcB <- reactive({
|
||||
values$A + 5
|
||||
})
|
||||
obsC <- observe(function() {
|
||||
obsC <- observe({
|
||||
observed_value1 <<- funcB() * values$A
|
||||
})
|
||||
obsD <- observe(function() {
|
||||
obsD <- observe({
|
||||
observed_value2 <<- funcB() * values$A
|
||||
})
|
||||
|
||||
@@ -135,15 +135,15 @@ test_that("overreactivity2", {
|
||||
test_that("isolation", {
|
||||
values <- reactiveValues(A=10, C=NULL)
|
||||
|
||||
obsB <- observe(function() {
|
||||
obsB <- observe({
|
||||
values$C <- values$A > 0
|
||||
})
|
||||
|
||||
funcD <- reactive(function() {
|
||||
funcD <- reactive({
|
||||
values$C
|
||||
})
|
||||
|
||||
obsE <- observe(function() {
|
||||
obsE <- observe({
|
||||
funcD()
|
||||
})
|
||||
|
||||
@@ -163,15 +163,15 @@ test_that("laziness", {
|
||||
|
||||
values <- reactiveValues(A=10)
|
||||
|
||||
funcA <- reactive(function() {
|
||||
funcA <- reactive({
|
||||
values$A > 0
|
||||
})
|
||||
|
||||
funcB <- reactive(function() {
|
||||
funcB <- reactive({
|
||||
funcA()
|
||||
})
|
||||
|
||||
obsC <- observe(function() {
|
||||
obsC <- observe({
|
||||
if (values$A > 10)
|
||||
return()
|
||||
funcB()
|
||||
@@ -203,10 +203,10 @@ test_that("order of evaluation", {
|
||||
observed_value <- NA
|
||||
|
||||
values <- reactiveValues(A=1)
|
||||
funcB <- reactive(function() {
|
||||
funcB <- reactive({
|
||||
values$A + 5
|
||||
})
|
||||
obsC <- observe(function() {
|
||||
obsC <- observe({
|
||||
observed_value <<- values$A * funcB()
|
||||
})
|
||||
|
||||
@@ -230,10 +230,10 @@ test_that("order of evaluation", {
|
||||
observed_value <- NA
|
||||
|
||||
values <- reactiveValues(A=1)
|
||||
funcB <- reactive(function() {
|
||||
funcB <- reactive({
|
||||
values$A + 5
|
||||
})
|
||||
obsC <- observe(function() {
|
||||
obsC <- observe({
|
||||
observed_value <<- funcB() * values$A
|
||||
})
|
||||
|
||||
@@ -259,18 +259,18 @@ test_that("isolate() blocks invalidations from propagating", {
|
||||
obsD_value <- NA
|
||||
|
||||
values <- reactiveValues(A=1, B=10)
|
||||
funcB <- reactive(function() {
|
||||
funcB <- reactive({
|
||||
values$B + 100
|
||||
})
|
||||
|
||||
# References to valueB and funcB are isolated
|
||||
obsC <- observe(function() {
|
||||
obsC <- observe({
|
||||
obsC_value <<-
|
||||
values$A + isolate(values$B) + isolate(funcB())
|
||||
})
|
||||
|
||||
# In contrast with obsC, this has a non-isolated reference to funcB
|
||||
obsD <- observe(function() {
|
||||
obsD <- observe({
|
||||
obsD_value <<-
|
||||
values$A + isolate(values$B) + funcB()
|
||||
})
|
||||
@@ -309,11 +309,29 @@ test_that("isolate() blocks invalidations from propagating", {
|
||||
expect_equal(execCount(obsD), 4)
|
||||
})
|
||||
|
||||
|
||||
test_that("isolate() evaluates expressions in calling environment", {
|
||||
outside <- 1
|
||||
inside <- 1
|
||||
loc <- 1
|
||||
|
||||
outside <- isolate(2) # Assignment outside isolate
|
||||
isolate(inside <- 2) # Assignment inside isolate
|
||||
# Should affect vars in the calling environment
|
||||
expect_equal(outside, 2)
|
||||
expect_equal(inside, 2)
|
||||
|
||||
isolate(local(loc <<- 2)) # <<- inside isolate(local)
|
||||
isolate(local(loc <- 3)) # <- inside isolate(local) - should have no effect
|
||||
expect_equal(loc, 2)
|
||||
})
|
||||
|
||||
|
||||
test_that("Circular refs/reentrancy in reactive functions work", {
|
||||
|
||||
values <- reactiveValues(A=3)
|
||||
|
||||
funcB <- reactive(function() {
|
||||
funcB <- reactive({
|
||||
# Each time fB executes, it reads and then writes valueA,
|
||||
# effectively invalidating itself--until valueA becomes 0.
|
||||
if (values$A == 0)
|
||||
@@ -322,7 +340,7 @@ test_that("Circular refs/reentrancy in reactive functions work", {
|
||||
return(values$A)
|
||||
})
|
||||
|
||||
obsC <- observe(function() {
|
||||
obsC <- observe({
|
||||
funcB()
|
||||
})
|
||||
|
||||
@@ -339,14 +357,14 @@ test_that("Circular refs/reentrancy in reactive functions work", {
|
||||
test_that("Simple recursion", {
|
||||
|
||||
values <- reactiveValues(A=5)
|
||||
funcB <- reactive(function() {
|
||||
funcB <- reactive({
|
||||
if (values$A == 0)
|
||||
return(0)
|
||||
values$A <- values$A - 1
|
||||
funcB()
|
||||
})
|
||||
|
||||
obsC <- observe(function() {
|
||||
obsC <- observe({
|
||||
funcB()
|
||||
})
|
||||
|
||||
@@ -359,13 +377,13 @@ test_that("Non-reactive recursion", {
|
||||
nonreactiveA <- 3
|
||||
outputD <- NULL
|
||||
|
||||
funcB <- reactive(function() {
|
||||
funcB <- reactive({
|
||||
if (nonreactiveA == 0)
|
||||
return(0)
|
||||
nonreactiveA <<- nonreactiveA - 1
|
||||
return(funcB())
|
||||
})
|
||||
obsC <- observe(function() {
|
||||
obsC <- observe({
|
||||
outputD <<- funcB()
|
||||
})
|
||||
|
||||
@@ -377,7 +395,7 @@ test_that("Non-reactive recursion", {
|
||||
test_that("Circular dep with observer only", {
|
||||
|
||||
values <- reactiveValues(A=3)
|
||||
obsB <- observe(function() {
|
||||
obsB <- observe({
|
||||
if (values$A == 0)
|
||||
return()
|
||||
values$A <- values$A - 1
|
||||
@@ -390,12 +408,12 @@ test_that("Circular dep with observer only", {
|
||||
test_that("Writing then reading value is not circular", {
|
||||
|
||||
values <- reactiveValues(A=3)
|
||||
funcB <- reactive(function() {
|
||||
funcB <- reactive({
|
||||
values$A <- isolate(values$A) - 1
|
||||
values$A
|
||||
})
|
||||
|
||||
obsC <- observe(function() {
|
||||
obsC <- observe({
|
||||
funcB()
|
||||
})
|
||||
|
||||
@@ -413,17 +431,17 @@ test_that("names() and reactiveValuesToList()", {
|
||||
values <- reactiveValues(A=1, .B=2)
|
||||
|
||||
# Dependent on names
|
||||
depNames <- observe(function() {
|
||||
depNames <- observe({
|
||||
names(values)
|
||||
})
|
||||
|
||||
# Dependent on all non-hidden objects
|
||||
depValues <- observe(function() {
|
||||
depValues <- observe({
|
||||
reactiveValuesToList(values)
|
||||
})
|
||||
|
||||
# Dependent on all objects, including hidden
|
||||
depAllValues <- observe(function() {
|
||||
depAllValues <- observe({
|
||||
reactiveValuesToList(values, all.names = TRUE)
|
||||
})
|
||||
|
||||
@@ -441,27 +459,194 @@ test_that("names() and reactiveValuesToList()", {
|
||||
expect_equal(execCount(depValues), 1)
|
||||
expect_equal(execCount(depAllValues), 1)
|
||||
|
||||
# Update existing variable
|
||||
values$A <- 2
|
||||
flushReact()
|
||||
expect_equal(execCount(depNames), 1)
|
||||
expect_equal(execCount(depValues), 2)
|
||||
expect_equal(execCount(depAllValues), 2)
|
||||
|
||||
# Update existing hidden variable
|
||||
values$.B <- 3
|
||||
flushReact()
|
||||
expect_equal(execCount(depNames), 1)
|
||||
expect_equal(execCount(depValues), 2)
|
||||
expect_equal(execCount(depAllValues), 3)
|
||||
|
||||
# Add new variable
|
||||
values$C <- 1
|
||||
flushReact()
|
||||
expect_equal(execCount(depNames), 2)
|
||||
expect_equal(execCount(depValues), 3)
|
||||
expect_equal(execCount(depAllValues), 4)
|
||||
|
||||
# Add new hidden variable
|
||||
values$.D <- 1
|
||||
flushReact()
|
||||
expect_equal(execCount(depNames), 3)
|
||||
expect_equal(execCount(depValues), 3)
|
||||
expect_equal(execCount(depAllValues), 5)
|
||||
})
|
||||
|
||||
test_that("Observer pausing works", {
|
||||
values <- reactiveValues(a=1)
|
||||
|
||||
funcA <- reactive({
|
||||
values$a
|
||||
})
|
||||
|
||||
obsB <- observe({
|
||||
funcA()
|
||||
})
|
||||
|
||||
# Important: suspend() only affects observer at invalidation time
|
||||
|
||||
# Observers are invalidated at creation time, so it will run once regardless
|
||||
# of being suspended
|
||||
obsB$suspend()
|
||||
flushReact()
|
||||
expect_equal(execCount(funcA), 1)
|
||||
expect_equal(execCount(obsB), 1)
|
||||
|
||||
# When resuming, if nothing changed, don't do anything
|
||||
obsB$resume()
|
||||
flushReact()
|
||||
expect_equal(execCount(funcA), 1)
|
||||
expect_equal(execCount(obsB), 1)
|
||||
|
||||
# Make sure suspended observers do not flush, but do invalidate
|
||||
obsB_invalidated <- FALSE
|
||||
obsB$onInvalidate(function() {obsB_invalidated <<- TRUE})
|
||||
obsB$suspend()
|
||||
values$a <- 2
|
||||
flushReact()
|
||||
expect_equal(obsB_invalidated, TRUE)
|
||||
expect_equal(execCount(funcA), 1)
|
||||
expect_equal(execCount(obsB), 1)
|
||||
|
||||
obsB$resume()
|
||||
values$a <- 2.5
|
||||
obsB$suspend()
|
||||
flushReact()
|
||||
expect_equal(execCount(funcA), 2)
|
||||
expect_equal(execCount(obsB), 2)
|
||||
|
||||
values$a <- 3
|
||||
flushReact()
|
||||
|
||||
expect_equal(execCount(funcA), 2)
|
||||
expect_equal(execCount(obsB), 2)
|
||||
|
||||
# If onInvalidate() is added _after_ obsB is suspended and the values$a
|
||||
# changes, then it shouldn't get run (onInvalidate runs on invalidation, not
|
||||
# on flush)
|
||||
values$a <- 4
|
||||
obsB_invalidated2 <- FALSE
|
||||
obsB$onInvalidate(function() {obsB_invalidated2 <<- TRUE})
|
||||
obsB$resume()
|
||||
flushReact()
|
||||
|
||||
expect_equal(execCount(funcA), 3)
|
||||
expect_equal(execCount(obsB), 3)
|
||||
expect_equal(obsB_invalidated2, FALSE)
|
||||
})
|
||||
|
||||
test_that("suspended/resumed observers run at most once", {
|
||||
|
||||
values <- reactiveValues(A=1)
|
||||
obs <- observe(function() {
|
||||
values$A
|
||||
})
|
||||
expect_equal(execCount(obs), 0)
|
||||
|
||||
# First flush should run obs once
|
||||
flushReact()
|
||||
expect_equal(execCount(obs), 1)
|
||||
|
||||
# Modify the dependency at each stage of suspend/resume/flush should still
|
||||
# only result in one run of obs()
|
||||
values$A <- 2
|
||||
obs$suspend()
|
||||
values$A <- 3
|
||||
obs$resume()
|
||||
values$A <- 4
|
||||
flushReact()
|
||||
expect_equal(execCount(obs), 2)
|
||||
|
||||
})
|
||||
|
||||
|
||||
test_that("reactive() accepts quoted and unquoted expressions", {
|
||||
vals <- reactiveValues(A=1)
|
||||
|
||||
# Unquoted expression, with curly braces
|
||||
fun <- reactive({ vals$A + 1 })
|
||||
expect_equal(isolate(fun()), 2)
|
||||
|
||||
# Unquoted expression, no curly braces
|
||||
fun <- reactive(vals$A + 1)
|
||||
expect_equal(isolate(fun()), 2)
|
||||
|
||||
# Quoted expression
|
||||
fun <- reactive(quote(vals$A + 1), quoted = TRUE)
|
||||
expect_equal(isolate(fun()), 2)
|
||||
|
||||
# Quoted expression, saved in a variable
|
||||
q_expr <- quote(vals$A + 1)
|
||||
fun <- reactive(q_expr, quoted = TRUE)
|
||||
expect_equal(isolate(fun()), 2)
|
||||
|
||||
# If function is used, work, but print message
|
||||
expect_message(fun <- reactive(function() { vals$A + 1 }))
|
||||
expect_equal(isolate(fun()), 2)
|
||||
|
||||
|
||||
# Check that environment is correct - parent environment should be this one
|
||||
this_env <- environment()
|
||||
fun <- reactive(environment())
|
||||
expect_identical(isolate(parent.env(fun())), this_env)
|
||||
|
||||
# Sanity check: environment structure for a reactive() should be the same as for
|
||||
# a normal function
|
||||
fun <- function() environment()
|
||||
expect_identical(parent.env(fun()), this_env)
|
||||
})
|
||||
|
||||
test_that("observe() accepts quoted and unquoted expressions", {
|
||||
vals <- reactiveValues(A=0)
|
||||
valB <- 0
|
||||
|
||||
# Unquoted expression, with curly braces
|
||||
observe({ valB <<- vals$A + 1})
|
||||
flushReact()
|
||||
expect_equal(valB, 1)
|
||||
|
||||
# Unquoted expression, no curly braces
|
||||
observe({ valB <<- vals$A + 2})
|
||||
flushReact()
|
||||
expect_equal(valB, 2)
|
||||
|
||||
# Quoted expression
|
||||
observe(quote(valB <<- vals$A + 3), quoted = TRUE)
|
||||
flushReact()
|
||||
expect_equal(valB, 3)
|
||||
|
||||
# Quoted expression, saved in a variable
|
||||
q_expr <- quote(valB <<- vals$A + 4)
|
||||
fun <- observe(q_expr, quoted = TRUE)
|
||||
flushReact()
|
||||
expect_equal(valB, 4)
|
||||
|
||||
# If function is used, work, but print message
|
||||
expect_message(observe(function() { valB <<- vals$A + 5 }))
|
||||
flushReact()
|
||||
expect_equal(valB, 5)
|
||||
|
||||
|
||||
# Check that environment is correct - parent environment should be this one
|
||||
this_env <- environment()
|
||||
inside_env <- NULL
|
||||
fun <- observe(inside_env <<- environment())
|
||||
flushReact()
|
||||
expect_identical(parent.env(inside_env), this_env)
|
||||
})
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
context("text")
|
||||
|
||||
test_that("reactivePrint and reactiveText behavior is correct", {
|
||||
expect_equal(isolate(reactivePrint(function() "foo")()),
|
||||
test_that("renderPrint and renderText behavior is correct", {
|
||||
expect_equal(isolate(renderPrint({ "foo" })()),
|
||||
'[1] "foo"')
|
||||
expect_equal(isolate(reactivePrint(function() invisible("foo"))()),
|
||||
expect_equal(isolate(renderPrint({ invisible("foo") })()),
|
||||
'')
|
||||
expect_equal(isolate(reactivePrint(function() { print("foo"); "bar"})()),
|
||||
expect_equal(isolate(renderPrint({ print("foo"); "bar"})()),
|
||||
'[1] "foo"\n[1] "bar"')
|
||||
expect_equal(isolate(reactivePrint(function() NULL)()),
|
||||
expect_equal(isolate(renderPrint({ NULL })()),
|
||||
'NULL')
|
||||
expect_equal(isolate(reactivePrint(function() invisible())()),
|
||||
expect_equal(isolate(renderPrint({ invisible() })()),
|
||||
'')
|
||||
expect_equal(isolate(reactivePrint(function() 1:5)()),
|
||||
expect_equal(isolate(renderPrint({ 1:5 })()),
|
||||
'[1] 1 2 3 4 5')
|
||||
|
||||
expect_equal(isolate(reactiveText(function() "foo")()),
|
||||
expect_equal(isolate(renderText({ "foo" })()),
|
||||
'foo')
|
||||
expect_equal(isolate(reactiveText(function() invisible("foo"))()),
|
||||
expect_equal(isolate(renderText({ invisible("foo") })()),
|
||||
'foo')
|
||||
# Capture the print output so it's not shown on console during test, and
|
||||
# also check that it is correct
|
||||
print_out <- capture.output(ret <- isolate(reactiveText(function() { print("foo"); "bar"})()))
|
||||
print_out <- capture.output(ret <- isolate(renderText({ print("foo"); "bar"})()))
|
||||
expect_equal(ret, 'bar')
|
||||
expect_equal(print_out, '[1] "foo"')
|
||||
expect_equal(isolate(reactiveText(function() NULL)()),
|
||||
expect_equal(isolate(renderText({ NULL })()),
|
||||
'')
|
||||
expect_equal(isolate(reactiveText(function() invisible())()),
|
||||
expect_equal(isolate(renderText({ invisible() })()),
|
||||
'')
|
||||
expect_equal(isolate(reactiveText(function() 1:5)()),
|
||||
expect_equal(isolate(renderText({ 1:5 })()),
|
||||
'1 2 3 4 5')
|
||||
})
|
||||
|
||||
@@ -35,22 +35,22 @@ test_that("reactive functions save visibility state", {
|
||||
# Call each function twice - should be no change in state with second call
|
||||
|
||||
# invisible NULL
|
||||
f <- reactive(function() invisible())
|
||||
f <- reactive({ invisible() })
|
||||
expect_identical(withVisible(isolate(f())), list(value=NULL, visible=FALSE))
|
||||
expect_identical(withVisible(isolate(f())), list(value=NULL, visible=FALSE))
|
||||
|
||||
# visible NULL
|
||||
f <- reactive(function() NULL)
|
||||
f <- reactive({ NULL })
|
||||
expect_identical(withVisible(isolate(f())), list(value=NULL, visible=TRUE))
|
||||
expect_identical(withVisible(isolate(f())), list(value=NULL, visible=TRUE))
|
||||
|
||||
# invisible non-NULL value
|
||||
f <- reactive(function() invisible(10))
|
||||
f <- reactive({ invisible(10)})
|
||||
expect_identical(withVisible(isolate(f())), list(value=10, visible=FALSE))
|
||||
expect_identical(withVisible(isolate(f())), list(value=10, visible=FALSE))
|
||||
|
||||
# visible non-NULL value
|
||||
f <- reactive(function() 10)
|
||||
f <- reactive({ 10 })
|
||||
expect_identical(withVisible(isolate(f())), list(value=10, visible=TRUE))
|
||||
expect_identical(withVisible(isolate(f())), list(value=10, visible=TRUE))
|
||||
})
|
||||
|
||||
@@ -278,8 +278,13 @@
|
||||
this.lastSentValues[name] = jsonValue;
|
||||
this.target.setInput(name, value);
|
||||
};
|
||||
this.reset = function() {
|
||||
this.lastSentValues = {};
|
||||
this.reset = function(values) {
|
||||
values = values || {};
|
||||
var strValues = {};
|
||||
$.each(values, function(key, value) {
|
||||
strValues[key] = JSON.stringify(value);
|
||||
});
|
||||
this.lastSentValues = strValues;
|
||||
};
|
||||
}).call(InputNoResendDecorator.prototype);
|
||||
|
||||
@@ -1007,17 +1012,22 @@
|
||||
},
|
||||
getValue: function(el) {
|
||||
var numberVal = $(el).val();
|
||||
if (!isNaN(numberVal))
|
||||
if (/^\s*$/.test(numberVal)) // Return null if all whitespace
|
||||
return null;
|
||||
else if (!isNaN(numberVal)) // If valid Javascript number string, coerce to number
|
||||
return +numberVal;
|
||||
else
|
||||
return numberVal;
|
||||
return numberVal; // If other string like "1e6", send it unchanged
|
||||
},
|
||||
getType: function(el) {
|
||||
return "number"
|
||||
}
|
||||
});
|
||||
inputBindings.register(numberInputBinding, 'shiny.numberInput');
|
||||
|
||||
|
||||
var sliderInputBinding = {};
|
||||
$.extend(sliderInputBinding, numberInputBinding, {
|
||||
$.extend(sliderInputBinding, textInputBinding, {
|
||||
find: function(scope) {
|
||||
// Check if jslider plugin is loaded
|
||||
if (!$.fn.slider)
|
||||
@@ -1278,6 +1288,7 @@
|
||||
|
||||
// Send later in case DOM layout isn't final yet.
|
||||
setTimeout(sendPlotSize, 0);
|
||||
setTimeout(sendOutputHiddenState, 0);
|
||||
}
|
||||
|
||||
function unbindOutputs(scope) {
|
||||
@@ -1302,9 +1313,9 @@
|
||||
return $(el).val();
|
||||
}
|
||||
|
||||
var inputs = new InputNoResendDecorator(new InputBatchSender(shinyapp));
|
||||
var inputsRate = new InputRateDecorator(inputs);
|
||||
var inputsDefer = new InputDeferDecorator(inputs);
|
||||
var inputsNoResend = new InputNoResendDecorator(new InputBatchSender(shinyapp));
|
||||
var inputsRate = new InputRateDecorator(inputsNoResend);
|
||||
var inputsDefer = new InputDeferDecorator(inputsNoResend);
|
||||
|
||||
inputs = inputsRate;
|
||||
$('input[type="submit"], button[type="submit"]').each(function() {
|
||||
@@ -1372,7 +1383,7 @@
|
||||
var ratePolicy = binding.getRatePolicy();
|
||||
if (ratePolicy != null) {
|
||||
inputsRate.setRatePolicy(
|
||||
id,
|
||||
effectiveId,
|
||||
ratePolicy.policy,
|
||||
ratePolicy.delay);
|
||||
}
|
||||
@@ -1490,15 +1501,37 @@
|
||||
// The server needs to know the size of each plot output element, in case
|
||||
// the plot is auto-sizing
|
||||
$('.shiny-plot-output').each(function() {
|
||||
var width = this.offsetWidth;
|
||||
var height = this.offsetHeight;
|
||||
initialValues['.shinyout_' + this.id + '_width'] = width;
|
||||
initialValues['.shinyout_' + this.id + '_height'] = height;
|
||||
if (this.offsetWidth !== 0 || this.offsetHeight !== 0) {
|
||||
initialValues['.shinyout_' + this.id + '_width'] = this.offsetWidth;
|
||||
initialValues['.shinyout_' + this.id + '_height'] = this.offsetHeight;
|
||||
}
|
||||
});
|
||||
function sendPlotSize() {
|
||||
$('.shiny-plot-output').each(function() {
|
||||
inputs.setInput('.shinyout_' + this.id + '_width', this.offsetWidth);
|
||||
inputs.setInput('.shinyout_' + this.id + '_height', this.offsetHeight);
|
||||
if (this.offsetWidth !== 0 || this.offsetHeight !== 0) {
|
||||
inputs.setInput('.shinyout_' + this.id + '_width', this.offsetWidth);
|
||||
inputs.setInput('.shinyout_' + this.id + '_height', this.offsetHeight);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Set initial state of outputs to hidden, if needed
|
||||
$('.shiny-bound-output').each(function() {
|
||||
if (this.offsetWidth === 0 && this.offsetHeight === 0) {
|
||||
initialValues['.shinyout_' + this.id + '_hidden'] = true;
|
||||
} else {
|
||||
initialValues['.shinyout_' + this.id + '_hidden'] = false;
|
||||
}
|
||||
});
|
||||
// Send update when hidden state changes
|
||||
function sendOutputHiddenState() {
|
||||
$('.shiny-bound-output').each(function() {
|
||||
// Assume that the object is hidden when width and height are 0
|
||||
if (this.offsetWidth === 0 && this.offsetHeight === 0) {
|
||||
inputs.setInput('.shinyout_' + this.id + '_hidden', true);
|
||||
} else {
|
||||
inputs.setInput('.shinyout_' + this.id + '_hidden', false);
|
||||
}
|
||||
});
|
||||
}
|
||||
// The size of each plot may change either because the browser window was
|
||||
@@ -1506,9 +1539,12 @@
|
||||
// of 0x0). It's OK to over-report sizes because the input pipeline will
|
||||
// filter out values that haven't changed.
|
||||
$(window).resize(debounce(500, sendPlotSize));
|
||||
$('body').on('shown.sendPlotSize hidden.sendPlotSize', '*', sendPlotSize);
|
||||
$('body').on('shown.sendPlotSize', '*', sendPlotSize);
|
||||
$('body').on('shown.sendOutputHiddenState hidden.sendOutputHiddenState', '*',
|
||||
sendOutputHiddenState);
|
||||
|
||||
// We've collected all the initial values--start the server process!
|
||||
inputsNoResend.reset(initialValues);
|
||||
shinyapp.connect(initialValues);
|
||||
} // function initShiny()
|
||||
|
||||
|
||||
63
man/exprToFunction.Rd
Normal file
63
man/exprToFunction.Rd
Normal file
@@ -0,0 +1,63 @@
|
||||
\name{exprToFunction}
|
||||
\alias{exprToFunction}
|
||||
\title{Convert an expression or quoted expression to a function}
|
||||
\usage{
|
||||
exprToFunction(expr, env = parent.frame(2),
|
||||
quoted = FALSE)
|
||||
}
|
||||
\arguments{
|
||||
\item{expr}{A quoted or unquoted expression, or a
|
||||
function.}
|
||||
|
||||
\item{env}{The desired environment for the function.
|
||||
Defaults to the calling environment two steps back.}
|
||||
|
||||
\item{quoted}{Is the expression quoted?}
|
||||
}
|
||||
\description{
|
||||
This is to be called from another function, because it
|
||||
will attempt to get an unquoted expression from two calls
|
||||
back.
|
||||
}
|
||||
\details{
|
||||
If expr is a quoted expression, then this just converts
|
||||
it to a function. If expr is a function, then this simply
|
||||
returns expr (and prints a deprecation message. If expr
|
||||
was a non-quoted expression from two calls back, then
|
||||
this will quote the original expression and convert it to
|
||||
a function.
|
||||
}
|
||||
\examples{
|
||||
# Example of a new renderer, similar to renderText
|
||||
# This is something that toolkit authors will do
|
||||
renderTriple <- function(expr, env=parent.frame(), quoted=FALSE) {
|
||||
# Convert expr to a function
|
||||
func <- shiny::exprToFunction(expr, env, quoted)
|
||||
|
||||
function() {
|
||||
value <- func()
|
||||
paste(rep(value, 3), collapse=", ")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Example of using the renderer.
|
||||
# This is something that app authors will do.
|
||||
values <- reactiveValues(A="text")
|
||||
|
||||
\dontrun{
|
||||
# Create an output object
|
||||
output$tripleA <- renderTriple({
|
||||
values$A
|
||||
})
|
||||
}
|
||||
|
||||
# At the R console, you can experiment with the renderer using isolate()
|
||||
tripleA <- renderTriple({
|
||||
values$A
|
||||
})
|
||||
|
||||
isolate(tripleA())
|
||||
# "text, text, text"
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
}
|
||||
\details{
|
||||
\code{uiOutput} is intended to be used with
|
||||
\code{reactiveUI} on the server side. It is currently
|
||||
just an alias for \code{htmlOutput}.
|
||||
\code{renderUI} on the server side. It is currently just
|
||||
an alias for \code{htmlOutput}.
|
||||
}
|
||||
\examples{
|
||||
htmlOutput("summary")
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
}
|
||||
\arguments{
|
||||
\item{expr}{An expression that can access reactive values
|
||||
or functions.}
|
||||
or expressions.}
|
||||
}
|
||||
\description{
|
||||
Executes the given expression in a scope where reactive
|
||||
values or functions can be read, but they cannot cause
|
||||
values or expression can be read, but they cannot cause
|
||||
the reactive scope of the caller to be re-evaluated when
|
||||
they change.
|
||||
}
|
||||
@@ -19,14 +19,26 @@
|
||||
causes a relationship to be established between the
|
||||
caller and the reactive value, where a change to the
|
||||
reactive value will cause the caller to re-execute. (The
|
||||
same applies for the act of getting a reactive function's
|
||||
value.) The \code{isolate} function lets you read a
|
||||
reactive value or function without establishing this
|
||||
relationship.
|
||||
same applies for the act of getting a reactive
|
||||
expression's value.) The \code{isolate} function lets you
|
||||
read a reactive value or expression without establishing
|
||||
this relationship.
|
||||
|
||||
The expression given to \code{isolate()} is evaluated in
|
||||
the calling environment. This means that if you assign a
|
||||
variable inside the \code{isolate()}, its value will be
|
||||
visible outside of the \code{isolate()}. If you want to
|
||||
avoid this, you can use \code{\link{local}()} inside the
|
||||
\code{isolate()}.
|
||||
|
||||
This function can also be useful for calling reactive
|
||||
expression at the console, which can be useful for
|
||||
debugging. To do so, simply wrap the calls to the
|
||||
reactive expression with \code{isolate()}.
|
||||
}
|
||||
\examples{
|
||||
\dontrun{
|
||||
observer(function() {
|
||||
observe({
|
||||
input$saveButton # Do take a dependency on input$saveButton
|
||||
|
||||
# isolate a simple expression
|
||||
@@ -34,7 +46,7 @@ observer(function() {
|
||||
writeToDatabase(data)
|
||||
})
|
||||
|
||||
observer(function() {
|
||||
observe({
|
||||
input$saveButton # Do take a dependency on input$saveButton
|
||||
|
||||
# isolate a whole block
|
||||
@@ -45,6 +57,28 @@ observer(function() {
|
||||
})
|
||||
writeToDatabase(data)
|
||||
})
|
||||
}
|
||||
|
||||
observe({
|
||||
x <- 1
|
||||
# x outside of isolate() is affected
|
||||
isolate(x <- 2)
|
||||
print(x) # 2
|
||||
|
||||
y <- 1
|
||||
# Use local() to avoid affecting calling environment
|
||||
isolate(local(y <- 2))
|
||||
print(y) # 1
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
# Can also use isolate to call reactive expressions from the R console
|
||||
values <- reactiveValues(A=1)
|
||||
fun <- reactive({ as.character(values$A) })
|
||||
isolate(fun())
|
||||
# "1"
|
||||
|
||||
# isolate also works if the reactive expression accesses values from the
|
||||
# input object, like input$x
|
||||
}
|
||||
|
||||
|
||||
@@ -2,32 +2,67 @@
|
||||
\alias{observe}
|
||||
\title{Create a reactive observer}
|
||||
\usage{
|
||||
observe(func)
|
||||
observe(x, env = parent.frame(), quoted = FALSE,
|
||||
label = NULL, suspended = FALSE)
|
||||
}
|
||||
\arguments{
|
||||
\item{func}{The function to observe. It must not have any
|
||||
parameters. Any return value from this function will be
|
||||
ignored.}
|
||||
\item{x}{An expression (quoted or unquoted). Any return
|
||||
value will be ignored.}
|
||||
|
||||
\item{env}{The parent environment for the reactive
|
||||
expression. By default, this is the calling environment,
|
||||
the same as when defining an ordinary non-reactive
|
||||
expression.}
|
||||
|
||||
\item{quoted}{Is the expression quoted? By default, this
|
||||
is \code{FALSE}. This is useful when you want to use an
|
||||
expression that is stored in a variable; to do so, it
|
||||
must be quoted with `quote()`.}
|
||||
|
||||
\item{label}{A label for the observer, useful for
|
||||
debugging.}
|
||||
|
||||
\item{suspended}{If \code{TRUE}, start the observer in a
|
||||
suspended state. If \code{FALSE} (the default), start in
|
||||
a non-suspended state.}
|
||||
}
|
||||
\description{
|
||||
Creates an observer from the given function. An observer
|
||||
is like a reactive function in that it can read reactive
|
||||
values and call reactive functions, and will
|
||||
Creates an observer from the given expression An observer
|
||||
is like a reactive expression in that it can read
|
||||
reactive values and call reactive expressions, and will
|
||||
automatically re-execute when those dependencies change.
|
||||
But unlike reactive functions, it doesn't yield a result
|
||||
But unlike reactive expression, it doesn't yield a result
|
||||
and can't be used as an input to other reactive
|
||||
functions. Thus, observers are only useful for their side
|
||||
effects (for example, performing I/O).
|
||||
expressions. Thus, observers are only useful for their
|
||||
side effects (for example, performing I/O).
|
||||
}
|
||||
\details{
|
||||
Another contrast between reactive functions and observers
|
||||
is their execution strategy. Reactive functions use lazy
|
||||
evaluation; that is, when their dependencies change, they
|
||||
don't re-execute right away but rather wait until they
|
||||
are called by someone else. Indeed, if they are not
|
||||
called then they will never re-execute. In contrast,
|
||||
observers use eager evaluation; as soon as their
|
||||
dependencies change, they schedule themselves to
|
||||
re-execute.
|
||||
Another contrast between reactive expressions and
|
||||
observers is their execution strategy. Reactive
|
||||
expressions use lazy evaluation; that is, when their
|
||||
dependencies change, they don't re-execute right away but
|
||||
rather wait until they are called by someone else.
|
||||
Indeed, if they are not called then they will never
|
||||
re-execute. In contrast, observers use eager evaluation;
|
||||
as soon as their dependencies change, they schedule
|
||||
themselves to re-execute.
|
||||
}
|
||||
\examples{
|
||||
values <- reactiveValues(A=1)
|
||||
|
||||
obsB <- observe({
|
||||
print(values$A + 1)
|
||||
})
|
||||
|
||||
# Can use quoted expressions
|
||||
obsC <- observe(quote({ print(values$A + 2) }), quoted = TRUE)
|
||||
|
||||
# To store expressions for later conversion to observe, use quote()
|
||||
expr_q <- quote({ print(values$A + 3) })
|
||||
obsD <- observe(expr_q, quoted = TRUE)
|
||||
|
||||
# In a normal Shiny app, the web client will trigger flush events. If you
|
||||
# are at the console, you can force a flush with flushReact()
|
||||
shiny:::flushReact()
|
||||
}
|
||||
|
||||
|
||||
36
man/outputOptions.Rd
Normal file
36
man/outputOptions.Rd
Normal file
@@ -0,0 +1,36 @@
|
||||
\name{outputOptions}
|
||||
\alias{outputOptions}
|
||||
\title{Set options for an output object.}
|
||||
\usage{
|
||||
outputOptions(x, name, ...)
|
||||
}
|
||||
\arguments{
|
||||
\item{x}{A shinyoutput object (typically \code{output}).}
|
||||
|
||||
\item{name}{The name of an output observer in the
|
||||
shinyoutput object.}
|
||||
|
||||
\item{...}{Options to set for the output observer.}
|
||||
}
|
||||
\description{
|
||||
These are the available options for an output object:
|
||||
\itemize{ \item suspendWhenHidden. When \code{TRUE} (the
|
||||
default), the output object will be suspended (not
|
||||
execute) when it is hidden on the web page. When
|
||||
\code{FALSE}, the output object will not suspend when
|
||||
hidden, and if it was already hidden and suspended, then
|
||||
it will resume immediately. }
|
||||
}
|
||||
\examples{
|
||||
\dontrun{
|
||||
# Get the list of options for all observers within output
|
||||
outputOptions(output)
|
||||
|
||||
# Disable suspend for output$myplot
|
||||
outputOptions(output, "myplot", suspendWhenHidden = FALSE)
|
||||
|
||||
# Get the list of options for output$myplot
|
||||
outputOptions(output, "myplot")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
A plot output element that can be included in a panel
|
||||
}
|
||||
\description{
|
||||
Render a \link{reactivePlot} within an application page.
|
||||
Render a \link{renderPlot} within an application page.
|
||||
}
|
||||
\examples{
|
||||
# Show a plot of the generated distribution
|
||||
|
||||
@@ -1,35 +1,65 @@
|
||||
\name{reactive}
|
||||
\alias{reactive}
|
||||
\title{Create a Reactive Function}
|
||||
\title{Create a reactive expression}
|
||||
\usage{
|
||||
reactive(x)
|
||||
reactive(x, env = parent.frame(), quoted = FALSE,
|
||||
label = NULL)
|
||||
}
|
||||
\arguments{
|
||||
\item{x}{The value or function to make reactive. The
|
||||
function must not have any parameters.}
|
||||
}
|
||||
\value{
|
||||
A reactive function. (Note that reactive functions can
|
||||
only be called from within other reactive functions.)
|
||||
\item{x}{An expression (quoted or unquoted).}
|
||||
|
||||
\item{env}{The parent environment for the reactive
|
||||
expression. By default, this is the calling environment,
|
||||
the same as when defining an ordinary non-reactive
|
||||
expression.}
|
||||
|
||||
\item{quoted}{Is the expression quoted? By default, this
|
||||
is \code{FALSE}. This is useful when you want to use an
|
||||
expression that is stored in a variable; to do so, it
|
||||
must be quoted with `quote()`.}
|
||||
|
||||
\item{label}{A label for the reactive expression, useful
|
||||
for debugging.}
|
||||
}
|
||||
\description{
|
||||
Wraps a normal function to create a reactive function.
|
||||
Conceptually, a reactive function is a function whose
|
||||
result will change over time.
|
||||
Wraps a normal expression to create a reactive
|
||||
expression. Conceptually, a reactive expression is a
|
||||
expression whose result will change over time.
|
||||
}
|
||||
\details{
|
||||
Reactive functions are functions that can read reactive
|
||||
values and call other reactive functions. Whenever a
|
||||
reactive value changes, any reactive functions that
|
||||
depended on it are marked as "invalidated" and will
|
||||
automatically re-execute if necessary. If a reactive
|
||||
function is marked as invalidated, any other reactive
|
||||
functions that recently called it are also marked as
|
||||
invalidated. In this way, invalidations ripple through
|
||||
the functions that depend on each other.
|
||||
Reactive expressions are expressions that can read
|
||||
reactive values and call other reactive expressions.
|
||||
Whenever a reactive value changes, any reactive
|
||||
expressions that depended on it are marked as
|
||||
"invalidated" and will automatically re-execute if
|
||||
necessary. If a reactive expression is marked as
|
||||
invalidated, any other reactive expressions that recently
|
||||
called it are also marked as invalidated. In this way,
|
||||
invalidations ripple through the expressions that depend
|
||||
on each other.
|
||||
|
||||
See the
|
||||
\href{http://rstudio.github.com/shiny/tutorial/}{Shiny
|
||||
tutorial} for more information about reactive functions.
|
||||
tutorial} for more information about reactive
|
||||
expressions.
|
||||
}
|
||||
\examples{
|
||||
values <- reactiveValues(A=1)
|
||||
|
||||
reactiveB <- reactive({
|
||||
values$A + 1
|
||||
})
|
||||
|
||||
# Can use quoted expressions
|
||||
reactiveC <- reactive(quote({ values$A + 2 }), quoted = TRUE)
|
||||
|
||||
# To store expressions for later conversion to reactive, use quote()
|
||||
expr_q <- quote({ values$A + 3 })
|
||||
reactiveD <- reactive(expr_q, quoted = TRUE)
|
||||
|
||||
# View the values from the R console with isolate()
|
||||
isolate(reactiveB())
|
||||
isolate(reactiveC())
|
||||
isolate(reactiveD())
|
||||
}
|
||||
|
||||
|
||||
@@ -1,45 +1,19 @@
|
||||
\name{reactivePlot}
|
||||
\alias{reactivePlot}
|
||||
\title{Plot Output}
|
||||
\title{Plot output (deprecated)}
|
||||
\usage{
|
||||
reactivePlot(func, width = "auto", height = "auto", ...)
|
||||
}
|
||||
\arguments{
|
||||
\item{func}{A function that generates a plot.}
|
||||
\item{func}{A function.}
|
||||
|
||||
\item{width}{The width of the rendered plot, in pixels;
|
||||
or \code{'auto'} to use the \code{offsetWidth} of the
|
||||
HTML element that is bound to this plot. You can also
|
||||
pass in a function that returns the width in pixels or
|
||||
\code{'auto'}; in the body of the function you may
|
||||
reference reactive values and functions.}
|
||||
\item{width}{Width.}
|
||||
|
||||
\item{height}{The height of the rendered plot, in pixels;
|
||||
or \code{'auto'} to use the \code{offsetHeight} of the
|
||||
HTML element that is bound to this plot. You can also
|
||||
pass in a function that returns the width in pixels or
|
||||
\code{'auto'}; in the body of the function you may
|
||||
reference reactive values and functions.}
|
||||
\item{height}{Height.}
|
||||
|
||||
\item{...}{Arguments to be passed through to
|
||||
\code{\link[grDevices]{png}}. These can be used to set
|
||||
the width, height, background color, etc.}
|
||||
\item{...}{Other arguments to pass on.}
|
||||
}
|
||||
\description{
|
||||
Creates a reactive plot that is suitable for assigning to
|
||||
an \code{output} slot.
|
||||
}
|
||||
\details{
|
||||
The corresponding HTML output tag should be \code{div} or
|
||||
\code{img} and have the CSS class name
|
||||
\code{shiny-plot-output}.
|
||||
|
||||
For output, it will try to use the following devices, in
|
||||
this order: quartz (via \code{\link[grDevices]{png}}),
|
||||
then \code{\link[Cairo]{CairoPNG}}, and finally
|
||||
\code{\link[grDevices]{png}}. This is in order of quality
|
||||
of output. Notably, plain \code{png} output on Linux and
|
||||
Windows may not antialias some point shapes, resulting in
|
||||
poor quality output.
|
||||
See \code{\link{renderPlot}}.
|
||||
}
|
||||
|
||||
|
||||
@@ -1,101 +1,13 @@
|
||||
\name{reactivePrint}
|
||||
\alias{reactivePrint}
|
||||
\title{Printable Output}
|
||||
\title{Print output (deprecated)}
|
||||
\usage{
|
||||
reactivePrint(func)
|
||||
}
|
||||
\arguments{
|
||||
\item{func}{A function that may print output and/or
|
||||
return a printable R object.}
|
||||
\item{func}{A function.}
|
||||
}
|
||||
\description{
|
||||
Makes a reactive version of the given function that
|
||||
captures any printed output, and also captures its
|
||||
printable result (unless \code{\link{invisible}}), into a
|
||||
string. The resulting function is suitable for assigning
|
||||
to an \code{output} slot.
|
||||
}
|
||||
\details{
|
||||
The corresponding HTML output tag can be anything (though
|
||||
\code{pre} is recommended if you need a monospace font
|
||||
and whitespace preserved) and should have the CSS class
|
||||
name \code{shiny-text-output}.
|
||||
|
||||
The result of executing \code{func} will be printed
|
||||
inside a \code{\link[utils]{capture.output}} call.
|
||||
|
||||
Note that unlike most other Shiny output functions, if
|
||||
the given function returns \code{NULL} then \code{NULL}
|
||||
will actually be visible in the output. To display
|
||||
nothing, make your function return
|
||||
\code{\link{invisible}()}.
|
||||
}
|
||||
\examples{
|
||||
isolate({
|
||||
|
||||
# reactivePrint captures any print output, converts it to a string, and
|
||||
# returns it
|
||||
visFun <- reactivePrint(function() "foo")
|
||||
visFun()
|
||||
# '[1] "foo"'
|
||||
|
||||
invisFun <- reactivePrint(function() invisible("foo"))
|
||||
invisFun()
|
||||
# ''
|
||||
|
||||
multiprintFun <- reactivePrint(function() {
|
||||
print("foo");
|
||||
"bar"
|
||||
})
|
||||
multiprintFun()
|
||||
# '[1] "foo"\\n[1] "bar"'
|
||||
|
||||
nullFun <- reactivePrint(function() NULL)
|
||||
nullFun()
|
||||
# 'NULL'
|
||||
|
||||
invisNullFun <- reactivePrint(function() invisible(NULL))
|
||||
invisNullFun()
|
||||
# ''
|
||||
|
||||
vecFun <- reactivePrint(function() 1:5)
|
||||
vecFun()
|
||||
# '[1] 1 2 3 4 5'
|
||||
|
||||
|
||||
# Contrast with reactiveText, which takes the value returned from the function
|
||||
# and uses cat() to convert it to a string
|
||||
visFun <- reactiveText(function() "foo")
|
||||
visFun()
|
||||
# 'foo'
|
||||
|
||||
invisFun <- reactiveText(function() invisible("foo"))
|
||||
invisFun()
|
||||
# 'foo'
|
||||
|
||||
multiprintFun <- reactiveText(function() {
|
||||
print("foo");
|
||||
"bar"
|
||||
})
|
||||
multiprintFun()
|
||||
# 'bar'
|
||||
|
||||
nullFun <- reactiveText(function() NULL)
|
||||
nullFun()
|
||||
# ''
|
||||
|
||||
invisNullFun <- reactiveText(function() invisible(NULL))
|
||||
invisNullFun()
|
||||
# ''
|
||||
|
||||
vecFun <- reactiveText(function() 1:5)
|
||||
vecFun()
|
||||
# '1 2 3 4 5'
|
||||
|
||||
})
|
||||
}
|
||||
\seealso{
|
||||
\code{\link{reactiveText}} for displaying the value
|
||||
returned from a function, instead of the printed output.
|
||||
See \code{\link{renderPrint}}.
|
||||
}
|
||||
|
||||
|
||||
@@ -1,23 +1,15 @@
|
||||
\name{reactiveTable}
|
||||
\alias{reactiveTable}
|
||||
\title{Table Output}
|
||||
\title{Table output (deprecated)}
|
||||
\usage{
|
||||
reactiveTable(func, ...)
|
||||
}
|
||||
\arguments{
|
||||
\item{func}{A function that returns an R object that can
|
||||
be used with \code{\link[xtable]{xtable}}.}
|
||||
\item{func}{A function.}
|
||||
|
||||
\item{...}{Arguments to be passed through to
|
||||
\code{\link[xtable]{xtable}} and
|
||||
\code{\link[xtable]{print.xtable}}.}
|
||||
\item{...}{Other arguments to pass on.}
|
||||
}
|
||||
\description{
|
||||
Creates a reactive table that is suitable for assigning
|
||||
to an \code{output} slot.
|
||||
}
|
||||
\details{
|
||||
The corresponding HTML output tag should be \code{div}
|
||||
and have the CSS class name \code{shiny-html-output}.
|
||||
See \code{\link{renderTable}}.
|
||||
}
|
||||
|
||||
|
||||
@@ -1,95 +1,13 @@
|
||||
\name{reactiveText}
|
||||
\alias{reactiveText}
|
||||
\title{Text Output}
|
||||
\title{Text output (deprecated)}
|
||||
\usage{
|
||||
reactiveText(func)
|
||||
}
|
||||
\arguments{
|
||||
\item{func}{A function that returns an R object that can
|
||||
be used as an argument to \code{cat}.}
|
||||
\item{func}{A function.}
|
||||
}
|
||||
\description{
|
||||
Makes a reactive version of the given function that also
|
||||
uses \code{\link[base]{cat}} to turn its result into a
|
||||
single-element character vector.
|
||||
}
|
||||
\details{
|
||||
The corresponding HTML output tag can be anything (though
|
||||
\code{pre} is recommended if you need a monospace font
|
||||
and whitespace preserved) and should have the CSS class
|
||||
name \code{shiny-text-output}.
|
||||
|
||||
The result of executing \code{func} will passed to
|
||||
\code{cat}, inside a \code{\link[utils]{capture.output}}
|
||||
call.
|
||||
}
|
||||
\examples{
|
||||
isolate({
|
||||
|
||||
# reactivePrint captures any print output, converts it to a string, and
|
||||
# returns it
|
||||
visFun <- reactivePrint(function() "foo")
|
||||
visFun()
|
||||
# '[1] "foo"'
|
||||
|
||||
invisFun <- reactivePrint(function() invisible("foo"))
|
||||
invisFun()
|
||||
# ''
|
||||
|
||||
multiprintFun <- reactivePrint(function() {
|
||||
print("foo");
|
||||
"bar"
|
||||
})
|
||||
multiprintFun()
|
||||
# '[1] "foo"\\n[1] "bar"'
|
||||
|
||||
nullFun <- reactivePrint(function() NULL)
|
||||
nullFun()
|
||||
# 'NULL'
|
||||
|
||||
invisNullFun <- reactivePrint(function() invisible(NULL))
|
||||
invisNullFun()
|
||||
# ''
|
||||
|
||||
vecFun <- reactivePrint(function() 1:5)
|
||||
vecFun()
|
||||
# '[1] 1 2 3 4 5'
|
||||
|
||||
|
||||
# Contrast with reactiveText, which takes the value returned from the function
|
||||
# and uses cat() to convert it to a string
|
||||
visFun <- reactiveText(function() "foo")
|
||||
visFun()
|
||||
# 'foo'
|
||||
|
||||
invisFun <- reactiveText(function() invisible("foo"))
|
||||
invisFun()
|
||||
# 'foo'
|
||||
|
||||
multiprintFun <- reactiveText(function() {
|
||||
print("foo");
|
||||
"bar"
|
||||
})
|
||||
multiprintFun()
|
||||
# 'bar'
|
||||
|
||||
nullFun <- reactiveText(function() NULL)
|
||||
nullFun()
|
||||
# ''
|
||||
|
||||
invisNullFun <- reactiveText(function() invisible(NULL))
|
||||
invisNullFun()
|
||||
# ''
|
||||
|
||||
vecFun <- reactiveText(function() 1:5)
|
||||
vecFun()
|
||||
# '1 2 3 4 5'
|
||||
|
||||
})
|
||||
}
|
||||
\seealso{
|
||||
\code{\link{reactivePrint}} for capturing the print
|
||||
output of a function, rather than the returned text
|
||||
value.
|
||||
See \code{\link{renderText}}.
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
timers are triggered simply by the passage of time.
|
||||
}
|
||||
\details{
|
||||
\link[=reactive]{Reactive functions} and observers that
|
||||
\link[=reactive]{Reactive expressions} and observers that
|
||||
want to be invalidated by the timer need to call the
|
||||
timer function that \code{reactiveTimer} returns, even if
|
||||
the current time value is not actually needed.
|
||||
|
||||
@@ -1,33 +1,13 @@
|
||||
\name{reactiveUI}
|
||||
\alias{reactiveUI}
|
||||
\title{UI Output}
|
||||
\title{UI output (deprecated)}
|
||||
\usage{
|
||||
reactiveUI(func)
|
||||
}
|
||||
\arguments{
|
||||
\item{func}{A function that returns a Shiny tag object,
|
||||
\code{\link{HTML}}, or a list of such objects.}
|
||||
\item{func}{A function.}
|
||||
}
|
||||
\description{
|
||||
\bold{Experimental feature.} Makes a reactive version of
|
||||
a function that generates HTML using the Shiny UI
|
||||
library.
|
||||
}
|
||||
\details{
|
||||
The corresponding HTML output tag should be \code{div}
|
||||
and have the CSS class name \code{shiny-html-output} (or
|
||||
use \code{\link{uiOutput}}).
|
||||
}
|
||||
\examples{
|
||||
\dontrun{
|
||||
output$moreControls <- reactiveUI(function() {
|
||||
list(
|
||||
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
\seealso{
|
||||
conditionalPanel
|
||||
See \code{\link{renderUI}}.
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
This function returns an object for storing reactive
|
||||
values. It is similar to a list, but with special
|
||||
capabilities for reactive programming. When you read a
|
||||
value from it, the calling reactive function takes a
|
||||
value from it, the calling reactive expression takes a
|
||||
reactive dependency on that value, and when you write to
|
||||
it, it notifies any reactive functions that depend on
|
||||
that value.
|
||||
|
||||
56
man/renderPlot.Rd
Normal file
56
man/renderPlot.Rd
Normal file
@@ -0,0 +1,56 @@
|
||||
\name{renderPlot}
|
||||
\alias{renderPlot}
|
||||
\title{Plot Output}
|
||||
\usage{
|
||||
renderPlot(expr, width = "auto", height = "auto", ...,
|
||||
env = parent.frame(), quoted = FALSE, func = NULL)
|
||||
}
|
||||
\arguments{
|
||||
\item{expr}{An expression that generates a plot.}
|
||||
|
||||
\item{width}{The width of the rendered plot, in pixels;
|
||||
or \code{'auto'} to use the \code{offsetWidth} of the
|
||||
HTML element that is bound to this plot. You can also
|
||||
pass in a function that returns the width in pixels or
|
||||
\code{'auto'}; in the body of the function you may
|
||||
reference reactive values and functions.}
|
||||
|
||||
\item{height}{The height of the rendered plot, in pixels;
|
||||
or \code{'auto'} to use the \code{offsetHeight} of the
|
||||
HTML element that is bound to this plot. You can also
|
||||
pass in a function that returns the width in pixels or
|
||||
\code{'auto'}; in the body of the function you may
|
||||
reference reactive values and functions.}
|
||||
|
||||
\item{...}{Arguments to be passed through to
|
||||
\code{\link[grDevices]{png}}. These can be used to set
|
||||
the width, height, background color, etc.}
|
||||
|
||||
\item{env}{The environment in which to evaluate
|
||||
\code{expr}.}
|
||||
|
||||
\item{quoted}{Is \code{expr} a quoted expression (with
|
||||
\code{quote()})? This is useful if you want to save an
|
||||
expression in a variable.}
|
||||
|
||||
\item{func}{A function that generates a plot (deprecated;
|
||||
use \code{expr} instead).}
|
||||
}
|
||||
\description{
|
||||
Renders a reactive plot that is suitable for assigning to
|
||||
an \code{output} slot.
|
||||
}
|
||||
\details{
|
||||
The corresponding HTML output tag should be \code{div} or
|
||||
\code{img} and have the CSS class name
|
||||
\code{shiny-plot-output}.
|
||||
|
||||
For output, it will try to use the following devices, in
|
||||
this order: quartz (via \code{\link[grDevices]{png}}),
|
||||
then \code{\link[Cairo]{CairoPNG}}, and finally
|
||||
\code{\link[grDevices]{png}}. This is in order of quality
|
||||
of output. Notably, plain \code{png} output on Linux and
|
||||
Windows may not antialias some point shapes, resulting in
|
||||
poor quality output.
|
||||
}
|
||||
|
||||
112
man/renderPrint.Rd
Normal file
112
man/renderPrint.Rd
Normal file
@@ -0,0 +1,112 @@
|
||||
\name{renderPrint}
|
||||
\alias{renderPrint}
|
||||
\title{Printable Output}
|
||||
\usage{
|
||||
renderPrint(expr, env = parent.frame(), quoted = FALSE,
|
||||
func = NULL)
|
||||
}
|
||||
\arguments{
|
||||
\item{expr}{An expression that may print output and/or
|
||||
return a printable R object.}
|
||||
|
||||
\item{env}{The environment in which to evaluate
|
||||
\code{expr}.}
|
||||
|
||||
\item{quoted}{Is \code{expr} a quoted expression (with
|
||||
\code{quote()})? This}
|
||||
|
||||
\item{func}{A function that may print output and/or
|
||||
return a printable R object (deprecated; use \code{expr}
|
||||
instead).}
|
||||
}
|
||||
\description{
|
||||
Makes a reactive version of the given function that
|
||||
captures any printed output, and also captures its
|
||||
printable result (unless \code{\link{invisible}}), into a
|
||||
string. The resulting function is suitable for assigning
|
||||
to an \code{output} slot.
|
||||
}
|
||||
\details{
|
||||
The corresponding HTML output tag can be anything (though
|
||||
\code{pre} is recommended if you need a monospace font
|
||||
and whitespace preserved) and should have the CSS class
|
||||
name \code{shiny-text-output}.
|
||||
|
||||
The result of executing \code{func} will be printed
|
||||
inside a \code{\link[utils]{capture.output}} call.
|
||||
|
||||
Note that unlike most other Shiny output functions, if
|
||||
the given function returns \code{NULL} then \code{NULL}
|
||||
will actually be visible in the output. To display
|
||||
nothing, make your function return
|
||||
\code{\link{invisible}()}.
|
||||
}
|
||||
\examples{
|
||||
isolate({
|
||||
|
||||
# renderPrint captures any print output, converts it to a string, and
|
||||
# returns it
|
||||
visFun <- renderPrint({ "foo" })
|
||||
visFun()
|
||||
# '[1] "foo"'
|
||||
|
||||
invisFun <- renderPrint({ invisible("foo") })
|
||||
invisFun()
|
||||
# ''
|
||||
|
||||
multiprintFun <- renderPrint({
|
||||
print("foo");
|
||||
"bar"
|
||||
})
|
||||
multiprintFun()
|
||||
# '[1] "foo"\\n[1] "bar"'
|
||||
|
||||
nullFun <- renderPrint({ NULL })
|
||||
nullFun()
|
||||
# 'NULL'
|
||||
|
||||
invisNullFun <- renderPrint({ invisible(NULL) })
|
||||
invisNullFun()
|
||||
# ''
|
||||
|
||||
vecFun <- renderPrint({ 1:5 })
|
||||
vecFun()
|
||||
# '[1] 1 2 3 4 5'
|
||||
|
||||
|
||||
# Contrast with renderText, which takes the value returned from the function
|
||||
# and uses cat() to convert it to a string
|
||||
visFun <- renderText({ "foo" })
|
||||
visFun()
|
||||
# 'foo'
|
||||
|
||||
invisFun <- renderText({ invisible("foo") })
|
||||
invisFun()
|
||||
# 'foo'
|
||||
|
||||
multiprintFun <- renderText({
|
||||
print("foo");
|
||||
"bar"
|
||||
})
|
||||
multiprintFun()
|
||||
# 'bar'
|
||||
|
||||
nullFun <- renderText({ NULL })
|
||||
nullFun()
|
||||
# ''
|
||||
|
||||
invisNullFun <- renderText({ invisible(NULL) })
|
||||
invisNullFun()
|
||||
# ''
|
||||
|
||||
vecFun <- renderText({ 1:5 })
|
||||
vecFun()
|
||||
# '1 2 3 4 5'
|
||||
|
||||
})
|
||||
}
|
||||
\seealso{
|
||||
\code{\link{renderText}} for displaying the value
|
||||
returned from a function, instead of the printed output.
|
||||
}
|
||||
|
||||
35
man/renderTable.Rd
Normal file
35
man/renderTable.Rd
Normal file
@@ -0,0 +1,35 @@
|
||||
\name{renderTable}
|
||||
\alias{renderTable}
|
||||
\title{Table Output}
|
||||
\usage{
|
||||
renderTable(expr, ..., env = parent.frame(),
|
||||
quoted = FALSE, func = NULL)
|
||||
}
|
||||
\arguments{
|
||||
\item{expr}{An expression that returns an R object that
|
||||
can be used with \code{\link[xtable]{xtable}}.}
|
||||
|
||||
\item{...}{Arguments to be passed through to
|
||||
\code{\link[xtable]{xtable}} and
|
||||
\code{\link[xtable]{print.xtable}}.}
|
||||
|
||||
\item{env}{The environment in which to evaluate
|
||||
\code{expr}.}
|
||||
|
||||
\item{quoted}{Is \code{expr} a quoted expression (with
|
||||
\code{quote()})? This is useful if you want to save an
|
||||
expression in a variable.}
|
||||
|
||||
\item{func}{A function that returns an R object that can
|
||||
be used with \code{\link[xtable]{xtable}} (deprecated;
|
||||
use \code{expr} instead).}
|
||||
}
|
||||
\description{
|
||||
Creates a reactive table that is suitable for assigning
|
||||
to an \code{output} slot.
|
||||
}
|
||||
\details{
|
||||
The corresponding HTML output tag should be \code{div}
|
||||
and have the CSS class name \code{shiny-html-output}.
|
||||
}
|
||||
|
||||
106
man/renderText.Rd
Normal file
106
man/renderText.Rd
Normal file
@@ -0,0 +1,106 @@
|
||||
\name{renderText}
|
||||
\alias{renderText}
|
||||
\title{Text Output}
|
||||
\usage{
|
||||
renderText(expr, env = parent.frame(), quoted = FALSE,
|
||||
func = NULL)
|
||||
}
|
||||
\arguments{
|
||||
\item{expr}{An expression that returns an R object that
|
||||
can be used as an argument to \code{cat}.}
|
||||
|
||||
\item{env}{The environment in which to evaluate
|
||||
\code{expr}.}
|
||||
|
||||
\item{quoted}{Is \code{expr} a quoted expression (with
|
||||
\code{quote()})? This is useful if you want to save an
|
||||
expression in a variable.}
|
||||
|
||||
\item{func}{A function that returns an R object that can
|
||||
be used as an argument to \code{cat}.(deprecated; use
|
||||
\code{expr} instead).}
|
||||
}
|
||||
\description{
|
||||
Makes a reactive version of the given function that also
|
||||
uses \code{\link[base]{cat}} to turn its result into a
|
||||
single-element character vector.
|
||||
}
|
||||
\details{
|
||||
The corresponding HTML output tag can be anything (though
|
||||
\code{pre} is recommended if you need a monospace font
|
||||
and whitespace preserved) and should have the CSS class
|
||||
name \code{shiny-text-output}.
|
||||
|
||||
The result of executing \code{func} will passed to
|
||||
\code{cat}, inside a \code{\link[utils]{capture.output}}
|
||||
call.
|
||||
}
|
||||
\examples{
|
||||
isolate({
|
||||
|
||||
# renderPrint captures any print output, converts it to a string, and
|
||||
# returns it
|
||||
visFun <- renderPrint({ "foo" })
|
||||
visFun()
|
||||
# '[1] "foo"'
|
||||
|
||||
invisFun <- renderPrint({ invisible("foo") })
|
||||
invisFun()
|
||||
# ''
|
||||
|
||||
multiprintFun <- renderPrint({
|
||||
print("foo");
|
||||
"bar"
|
||||
})
|
||||
multiprintFun()
|
||||
# '[1] "foo"\\n[1] "bar"'
|
||||
|
||||
nullFun <- renderPrint({ NULL })
|
||||
nullFun()
|
||||
# 'NULL'
|
||||
|
||||
invisNullFun <- renderPrint({ invisible(NULL) })
|
||||
invisNullFun()
|
||||
# ''
|
||||
|
||||
vecFun <- renderPrint({ 1:5 })
|
||||
vecFun()
|
||||
# '[1] 1 2 3 4 5'
|
||||
|
||||
|
||||
# Contrast with renderText, which takes the value returned from the function
|
||||
# and uses cat() to convert it to a string
|
||||
visFun <- renderText({ "foo" })
|
||||
visFun()
|
||||
# 'foo'
|
||||
|
||||
invisFun <- renderText({ invisible("foo") })
|
||||
invisFun()
|
||||
# 'foo'
|
||||
|
||||
multiprintFun <- renderText({
|
||||
print("foo");
|
||||
"bar"
|
||||
})
|
||||
multiprintFun()
|
||||
# 'bar'
|
||||
|
||||
nullFun <- renderText({ NULL })
|
||||
nullFun()
|
||||
# ''
|
||||
|
||||
invisNullFun <- renderText({ invisible(NULL) })
|
||||
invisNullFun()
|
||||
# ''
|
||||
|
||||
vecFun <- renderText({ 1:5 })
|
||||
vecFun()
|
||||
# '1 2 3 4 5'
|
||||
|
||||
})
|
||||
}
|
||||
\seealso{
|
||||
\code{\link{renderPrint}} for capturing the print output
|
||||
of a function, rather than the returned text value.
|
||||
}
|
||||
|
||||
45
man/renderUI.Rd
Normal file
45
man/renderUI.Rd
Normal file
@@ -0,0 +1,45 @@
|
||||
\name{renderUI}
|
||||
\alias{renderUI}
|
||||
\title{UI Output}
|
||||
\usage{
|
||||
renderUI(expr, env = parent.frame(), quoted = FALSE,
|
||||
func = NULL)
|
||||
}
|
||||
\arguments{
|
||||
\item{expr}{An expression that returns a Shiny tag
|
||||
object, \code{\link{HTML}}, or a list of such objects.}
|
||||
|
||||
\item{env}{The environment in which to evaluate
|
||||
\code{expr}.}
|
||||
|
||||
\item{quoted}{Is \code{expr} a quoted expression (with
|
||||
\code{quote()})? This is useful if you want to save an
|
||||
expression in a variable.}
|
||||
|
||||
\item{func}{A function that returns a Shiny tag object,
|
||||
\code{\link{HTML}}, or a list of such objects
|
||||
(deprecated; use \code{expr} instead).}
|
||||
}
|
||||
\description{
|
||||
\bold{Experimental feature.} Makes a reactive version of
|
||||
a function that generates HTML using the Shiny UI
|
||||
library.
|
||||
}
|
||||
\details{
|
||||
The corresponding HTML output tag should be \code{div}
|
||||
and have the CSS class name \code{shiny-html-output} (or
|
||||
use \code{\link{uiOutput}}).
|
||||
}
|
||||
\examples{
|
||||
\dontrun{
|
||||
output$moreControls <- renderUI({
|
||||
list(
|
||||
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
\seealso{
|
||||
conditionalPanel
|
||||
}
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
}
|
||||
\arguments{
|
||||
\item{gist}{The identifier of the gist. For example, if
|
||||
the gist is https://gist.github.com/3239667, then
|
||||
the gist is https://gist.github.com/jcheng5/3239667, then
|
||||
\code{3239667}, \code{'3239667'}, and
|
||||
\code{'https://gist.github.com/3239667'} are all valid
|
||||
values.}
|
||||
\code{'https://gist.github.com/jcheng5/3239667'} are all
|
||||
valid values.}
|
||||
|
||||
\item{port}{The TCP port that the application should
|
||||
listen on. Defaults to port 8100.}
|
||||
@@ -25,8 +25,11 @@
|
||||
}
|
||||
\examples{
|
||||
\dontrun{
|
||||
runGist(4034323)
|
||||
runGist("https://gist.github.com/4034323")
|
||||
runGist(3239667)
|
||||
runGist("https://gist.github.com/jcheng5/3239667")
|
||||
|
||||
# Old URL format without username
|
||||
runGist("https://gist.github.com/3239667")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,10 @@
|
||||
\description{
|
||||
Download and launch a Shiny application that is hosted at
|
||||
a downloadable URL. The Shiny application must be saved
|
||||
in a .zip, .tar, or .tar.gz file.
|
||||
in a .zip, .tar, or .tar.gz file. The Shiny application
|
||||
files must be contained in a subdirectory in the archive.
|
||||
For example, the files might be \code{myapp/server.r} and
|
||||
\code{myapp/ui.r}.
|
||||
}
|
||||
\examples{
|
||||
\dontrun{
|
||||
|
||||
20
man/shinyDeprecated.Rd
Normal file
20
man/shinyDeprecated.Rd
Normal file
@@ -0,0 +1,20 @@
|
||||
\name{shinyDeprecated}
|
||||
\alias{shinyDeprecated}
|
||||
\title{Print message for deprecated functions in Shiny}
|
||||
\usage{
|
||||
shinyDeprecated(new = NULL, msg = NULL,
|
||||
old = as.character(sys.call(sys.parent()))[1L])
|
||||
}
|
||||
\arguments{
|
||||
\item{new}{Name of replacement function.}
|
||||
|
||||
\item{msg}{Message to print. If used, this will override
|
||||
the default message.}
|
||||
|
||||
\item{old}{Name of deprecated function.}
|
||||
}
|
||||
\description{
|
||||
To disable these messages, use
|
||||
\code{options(shiny.deprecation.messages=FALSE)}.
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
# A very simple Shiny app that takes a message from the user
|
||||
# and outputs an uppercase version of it.
|
||||
shinyServer(function(input, output) {
|
||||
output$uppercase <- reactiveText(function() {
|
||||
output$uppercase <- renderText({
|
||||
toupper(input$message)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
A table output element that can be included in a panel
|
||||
}
|
||||
\description{
|
||||
Render a \link{reactiveTable} within an application page.
|
||||
Render a \link{renderTable} within an application page.
|
||||
}
|
||||
\examples{
|
||||
mainPanel(
|
||||
|
||||
@@ -17,8 +17,7 @@
|
||||
}
|
||||
\details{
|
||||
Text is HTML-escaped prior to rendering. This element is
|
||||
often used to dispaly \link{reactiveText} output
|
||||
variables.
|
||||
often used to display \link{renderText} output variables.
|
||||
}
|
||||
\examples{
|
||||
h3(textOutput("caption"))
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
}
|
||||
\details{
|
||||
Text is HTML-escaped prior to rendering. This element is
|
||||
often used with the \link{reactivePrint} function to
|
||||
often used with the \link{renderPrint} function to
|
||||
preserve fixed-width formatting of printed objects.
|
||||
}
|
||||
\examples{
|
||||
|
||||
@@ -1,61 +1,61 @@
|
||||
isolate({
|
||||
|
||||
# reactivePrint captures any print output, converts it to a string, and
|
||||
# renderPrint captures any print output, converts it to a string, and
|
||||
# returns it
|
||||
visFun <- reactivePrint(function() "foo")
|
||||
visFun <- renderPrint({ "foo" })
|
||||
visFun()
|
||||
# '[1] "foo"'
|
||||
|
||||
invisFun <- reactivePrint(function() invisible("foo"))
|
||||
invisFun <- renderPrint({ invisible("foo") })
|
||||
invisFun()
|
||||
# ''
|
||||
|
||||
multiprintFun <- reactivePrint(function() {
|
||||
multiprintFun <- renderPrint({
|
||||
print("foo");
|
||||
"bar"
|
||||
})
|
||||
multiprintFun()
|
||||
# '[1] "foo"\n[1] "bar"'
|
||||
|
||||
nullFun <- reactivePrint(function() NULL)
|
||||
nullFun <- renderPrint({ NULL })
|
||||
nullFun()
|
||||
# 'NULL'
|
||||
|
||||
invisNullFun <- reactivePrint(function() invisible(NULL))
|
||||
invisNullFun <- renderPrint({ invisible(NULL) })
|
||||
invisNullFun()
|
||||
# ''
|
||||
|
||||
vecFun <- reactivePrint(function() 1:5)
|
||||
vecFun <- renderPrint({ 1:5 })
|
||||
vecFun()
|
||||
# '[1] 1 2 3 4 5'
|
||||
|
||||
|
||||
# Contrast with reactiveText, which takes the value returned from the function
|
||||
# Contrast with renderText, which takes the value returned from the function
|
||||
# and uses cat() to convert it to a string
|
||||
visFun <- reactiveText(function() "foo")
|
||||
visFun <- renderText({ "foo" })
|
||||
visFun()
|
||||
# 'foo'
|
||||
|
||||
invisFun <- reactiveText(function() invisible("foo"))
|
||||
invisFun <- renderText({ invisible("foo") })
|
||||
invisFun()
|
||||
# 'foo'
|
||||
|
||||
multiprintFun <- reactiveText(function() {
|
||||
multiprintFun <- renderText({
|
||||
print("foo");
|
||||
"bar"
|
||||
})
|
||||
multiprintFun()
|
||||
# 'bar'
|
||||
|
||||
nullFun <- reactiveText(function() NULL)
|
||||
nullFun <- renderText({ NULL })
|
||||
nullFun()
|
||||
# ''
|
||||
|
||||
invisNullFun <- reactiveText(function() invisible(NULL))
|
||||
invisNullFun <- renderText({ invisible(NULL) })
|
||||
invisNullFun()
|
||||
# ''
|
||||
|
||||
vecFun <- reactiveText(function() 1:5)
|
||||
vecFun <- renderText({ 1:5 })
|
||||
vecFun()
|
||||
# '1 2 3 4 5'
|
||||
|
||||
|
||||
Reference in New Issue
Block a user