What's the difference between Reactive Value and Reactive Expression?
Using currentFib <- reactiveValues({ fib(as.numeric(input$n)) })
will not work in this context.
You will get an error saying that you are accessing reactive values outside of the "reactive context."
However, if you wrap it inside a function call instead, it will work:
currentFib <- function(){ fib(as.numeric(input$n)) }
This works because now the function call is inside a reactive context.
The key difference is the distinction they make in the Shiny documentation, between reactive "sources" and "conductors." In that terminology, reactive({...})
is a conductor, but reactiveValues
can only be a source.
Here's how I think of
reactiveValues
- as a way to extendinput
which gets specified in UI.R. Sometimes, the slots ininput
are not enough, and we want derived values based on those input slots. In other words, it is a way to extend the list ofinput
slots for future reactive computations.Reactive()
does what you say -- it returns the value, after re-running the expression each time any reactive Value changes. If you look at the source code forreactive
you can see it:
The last line is that cached value that is being returned:Observable$new(fun, label)$getValue
where 'fun' is the expression that was sent in the call toreactive.
R Shiny: reactiveValues vs reactive
There is a catch, though it won't come into play in your example.
The shiny developers designed reactive()
to be lazy, meaning that the expression contained in it will only be executed when it is called by one of its dependents. When one of its reactive dependencies is changed, it clears its cache and notifies its own dependents, but it is not itself executed until asked to by one of those dependents. (So if, say, its sole dependent is a textOutput()
element on a hidden tab, it won't actually be executed unless and until that tab is opened.)
observe()
, on the other hand, is eager; the expression that it contains will be executed right away whenever one of its reactive dependencies is changed -- even if it's value is not needed by any of its dependents (and in fact even if has no dependents). Such eagerness is desirable when you're calling observe()
for its side-effects, but it can be wasteful when you're only using it to pass on the return value of its contents to other reactive expressions or endpoints down the line.
Joe Cheng explains this distinction quite well in his 2016 Shiny Developer Conference presentation on "Effective reactive programming", available here. See especially the bit starting around 30:20 in the presentation's second hour. If you watch until 40:42 (blink and you'll miss it!) he briefly characterizes the behavior of the observe()
/reactiveValue ()
combination that you like.
Advantages of reactive vs. observe vs. observeEvent
First off this stuff is sort of ambiguous, and not very intuitive in some ways, it even says so on the Shiny blog!
Here is my best understanding of the topic..
Lets start with reactive
The reactive function allows a user to monitor the status of an input or other changing variable and return the value to be used elsewhere in the code. The monitoring of a reactive variable is considered lazy, "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.(Source)". You show this well in example 2, as you can call the variable inside the renderText
environment, once called the code inside the reactive call executes and re-evaluates the variable.
For science nerds, this is a lot like quantum mechanics in that by calling the reactive variable (observing it) causes it to change by re-evaluating, too much of a stretch?
Now to observe
Observe is similar reactive, the main difference is that it does not return any values to any other environment besides its own, and it is not lazy. The observe function continually monitors any changes in all reactive values within its environment and runs the code in it's environment when these values are changed. So, observe is not a "lazy" evaluation since it does not wait to be called before it re-evaluates. Again note that you cannot assign variables from observe.
For sake of experiment:
server <- function(input,output,session)({
observe({
if (input$choice == 'Hello') {
getStatus <- 'Hi there'
}
})
observe({
if (input$choice == 'Goodbye') {
getStatus <- 'See you later'
}
})
output$result <- renderText({
getStatus
})
})
shinyApp(ui = ui, server = server)
What is important to notice is that during the code executed in observe
, we can manipulate outside environment reactive variables. In your case you assign text <- reactiveValues()
and then manipulate that by calling text$result <- 'Hi there'
. We can also do things like update selectInput
choices, or other shiny widgets, but we cannot assign any non-reactive variables in this environment like our getStatus in the example above. And this idea is mentioned on the observe
documentation,
"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 expressions, 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)(Source)"
Lastly, observeEvent
The best way to use observeEvent
is to think of it as a defined trigger, as in it watches one event or change in a variable, and then fires when the event happens. I most commonly use this to watch input to buttons, as that is a defined event in which I want things to happen after the button is pushed. It uses an isolate
environment which I think is the perfect name for how this function works.
Inside this environment we can call a bunch of reactive variables, but we only define one as the trigger. The main difference between observeEvent
and observe
being the trigger, as observe
runs anytime anything changes, and observeEvent
waits for the trigger. Note that this environment is similar to observe in that it does not return non-reactive variables.
Summary
Here is an example that brings all these ideas together:
library(shiny)
ui<-
fluidPage(
fluidRow(
column(4,
h2("Reactive Test"),
textInput("Test_R","Test_R"),
textInput("Test_R2","Test_R2"),
textInput("Test_R3","Test_R3"),
tableOutput("React_Out")
),
column(4,
h2("Observe Test"),
textInput("Test","Test"),
textInput("Test2","Test2"),
textInput("Test3","Test3"),
tableOutput("Observe_Out")
),
column(4,
h2("Observe Event Test"),
textInput("Test_OE","Test_OE"),
textInput("Test_OE2","Test_OE2"),
textInput("Test_OE3","Test_OE3"),
tableOutput("Observe_Out_E"),
actionButton("Go","Test")
)
),
fluidRow(
column(8,
h4("Note that observe and reactive work very much the same on the surface,
it is when we get into the server where we see the differences, and how those
can be exploited for diffrent uses.")
))
)
server<-function(input,output,session){
# Create a reactive Evironment. Note that we can call the varaible outside same place
# where it was created by calling Reactive_Var(). When the varaible is called by
# renderTable is when it is evaluated. No real diffrence on the surface, all in the server.
Reactive_Var<-reactive({c(input$Test_R, input$Test_R2, input$Test_R3)})
output$React_Out<-renderTable({
Reactive_Var()
})
# Create an observe Evironment. Note that we cannot access the created "df" outside
# of the env. A, B,and C will update with any input into any of the three Text Feilds.
observe({
A<-input$Test
B<-input$Test2
C<-input$Test3
df<-c(A,B,C)
output$Observe_Out<-renderTable({df})
})
#We can change any input as much as we want, but the code wont run until the trigger
# input$Go is pressed.
observeEvent(input$Go, {
A<-input$Test_OE
B<-input$Test_OE2
C<-input$Test_OE3
df<-c(A,B,C)
output$Observe_Out_E<-renderTable({df})
})
}
shinyApp(ui, server)
reactive
Create a variable that can be changed over time by user inputs, evaluates "lazy" meaning only when called.
observe
Continually monitor reactive events and variables, whenever ANY reactive variable is changed in the environment (the observed environment), the code is evaluated. Can change values of previously defined reactive variables, cannot create/return variables.
observeEvent
(Domino Effect)
Continually monitor ONE defined reactive variable/event (the trigger) and run the code when the the trigger is activated by change/input of that trigger. Can change values of previously defined reactive variables, cannot create/return variables.
eventReactive
Create a variable, with a defined trigger similar to observeEvent
. Use this when you want a reactive variable that evaluates due to a trigger instead of when it is called.
Feel free to edit to improve or correct this post.
Using a reactive value and a reactive expression to trigger an observeEvent
observeEvent
has ignoreNULL = TRUE
set by default. As you correctly suspect, while the observer will trigger for a change to any part of {x;y}
, it will only do that if the value of that whole expression is not NULL. In this example, as long as y
is NULL, the observer won't trigger, no matter what you do to x
. This is easily fixed by setting ignoreNULL = FALSE
.
When to use a reactive expression vs to use - to create a global object
At the outset, I think we need to clarify the scope of the question.
- If you write a function in R, it is good practice to return value using either
return()
at the end of the function, for clarity, or at least putting the data object last before the curly brackets. in this context, the use of<<-
can create any sort of errors and complications (in short is a reminder of spaghetti programming, breaking the rule of having a single exit point to the function in question). - Different is the case of
shiny
special functions. I just like to remind thatshiny
coders usually does not usereturn()
at the end of a shiny function (even if it would still work). Here either there is no value returned, orreactive
is used or other similar constructs.
Part of the confusion comes from the minimal example in the question: the example is not a shiny
special function but just a normal function.
In shiny
, using for example constructs like observe
, it may happen to use <<-
to update global objects. A very good example (a great piece of code I often go back to) is the application ShinyChat developed by Jeff Allen, one of shiny developers - see here on github.
In this case Jeff uses <<-
to update a reactiveValue defined at the global level from within an observe
function: very good style.
I conclude with a minor point: if you have any function and you update a variable with <<-
, and you have a variable of the same name defined locally, only the global variable is updated.
In these cases you need to do something like
data <<- data <- 3
From right to left: the first <-
updated the local variable named data
: the second <<-
updated the global variable named data
. Talk about confusing.
On the other hand, in shiny or standard R I never noticed a drastic slowness because of <<-
, certainly provided that there aren't too many in the code.
On the issue of alternative techniques like reactive
or reactiveValues
, please see this good answer on SO to a similar question here.
difference between global variable and reactive value
A reactiveValue is something that you can update from observers or observeEvents. Any reactive expression that is dependent on that value, will then get invalidated, and thus updated if necessary.
A global variable is a variable that is defined globally, i.e. all users that are in the process of your shiny App share that variable. The most simple example of this would be a large dataset.
Note that your 'global' variable is not global. You define it as:
global <- list()
within the server. Therefore, it is unique to one user in your app, it is not shared. i.e. if it would be
global <- runif(1)
the numbers in 'global' would be different for multiple users. If you want the value to be the same, you should initialize it above your server definition. Note also that this line:
global <- creerCube(input)
does not modify your 'global' variable, because it is out of scope. It creates a variable 'global' within your observer, and discards it when the function finishes. What is probably best is to set global as a reactiveValue:
global <- reactiveVal()
and then update it as:
global(creerCube(input))
I hope this helps.
R Shiny update reactive value using a non reactive variable
The start
value needs to be reactive as well to working with other reactive values. Here's a re-write that will work
library(shiny)
ui <- fluidPage(
uiOutput("text_header"),
actionButton("go", "Go")
)
server <- function(input, output) {
start <- reactiveVal(0)
rv <- reactive(paste("clicks",start()))
observeEvent(input$go, {
start(start() + 1)
})
output$text_header <- renderUI({
h1(rv(), align = "center")
})
}
shinyApp(ui, server)
We make start
the reactive value, and then rv
just depends completely on the current value of start
. Maybe "start" isn't the best word here, you could rename it
library(shiny)
ui <- fluidPage(
uiOutput("text_header"),
actionButton("go", "Go")
)
server <- function(input, output) {
start <- 0
clickCount <- reactiveVal(start)
rv <- reactive(paste("clicks",clickCount()))
observeEvent(input$go, {
clickCount(clickCount() + 1)
})
output$text_header <- renderUI({
h1(rv(), align = "center")
})
}
shinyApp(ui, server)
How to manage/call a Shiny `reactive()` expression with unfulfilled `validate(need())` conditions
When using req
or validate
/need
, the chain of reactivity is disrupted if not completely valid. This means that anything that depends on the reactive block will also not fire (due to the data
block). I don't know of a way to "peek" into the reactive block's validation, since that would involve evaluating the expression and catching the shiny-specific signals.
Typically, it is sufficient in a shiny app that the actbtn
observer will not fire due to data
not validating. However, if you need to know in one expression whether another is fire-able, you can set up a third reactive block that always returns a known element (i.e., no validate
in it).
library(shiny) # don't use require without checking its return value
# https://stackoverflow.com/a/51263513/3358272
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
selectInput("data", label = "Data set",
choices = c("", "mtcars", "faithful", "iris"))
),
mainPanel(
actionButton(inputId = "actbtn", label = "Print in console reactive value")
)
)
)
server <- function(input, output) {
isgood <- reactive({
if (is.null(input$data) || !nzchar(input$data)) {
"Please select a data set"
} else if (!input$data %in% c("mtcars", "faithful", "iris")) {
"Unrecognized data set"
} else character(0)
})
data <- reactive({
validate(need(!length(isgood()), isgood()))
get(input$data, 'package:datasets')
})
observeEvent(input$actbtn, {
validate(need(!length(isgood()), isgood()))
print("This message will only be printed when data() validate/need are fulfilled.")
})
}
shinyApp(ui, server)
An alternative is to disable the button (cannot be clicked) until data()
is valid. This can be done with shinyjs
, which also requires a change to the ui
component.
library(shiny)
library(shinyjs)
ui <- fluidPage(
shinyjs::useShinyjs(), # <-- add this
sidebarLayout(
sidebarPanel(
selectInput("data", label = "Data set",
choices = c("", "mtcars", "faithful", "iris"))
),
mainPanel(
actionButton(inputId = "actbtn", label = "Print in console reactive value")
)
)
)
server <- function(input, output) {
observeEvent(TRUE, {
message("quux")
shinyjs::disable("actbtn")
}, once = TRUE)
data <- reactive({
validate(
need(input$data != "", "Please select a data set"),
need(input$data %in% c("mtcars", "faithful", "iris"),
"Unrecognized data set"),
need(input$data, "Input is an empty string"),
need(!is.null(input$data),
"Input is not an empty string, it is NULL")
)
get(input$data, 'package:datasets')
})
observeEvent(data(), {
shinyjs::toggleState("actbtn", condition = !is.null(data()))
})
observeEvent(input$actbtn, {
print("This message will only be printed when data() validate/need are fulfilled.")
})
}
shinyApp(ui, server)
Due to the choices you have available in your UI, the toggleState
observer will only ever toggle the disabled state once, after that it should always be valid. Because of that, there are ways to possibly reduce it. For instance, once could add once=TRUE
as in the first observeEvent
I added, in which case once the observer fires once, it is removed and never fires again. In your real-world use, if you believe that data()
might toggle back to an unusable state (e.g., 0 rows), then you would likely want to keep the default of once=FALSE
and add more logic on nrow(data())
to your data
validation.
Related Topics
Rank a Vector Based on Order and Replace Ties with Their Average
Change Level of Multiple Factor Variables
Running Multiple Linear Regressions Across Several Columns of a Data Frame in R
Difference Between Mean(C(1,2,21)) and Mean(1,2,21)
Ggplot Aes_String Does Not Work Inside a Function
Azure Put Blob Authentication Fails in R
Ggplot2: Issues with Dual Y-Axes and Loess Smoothing
R Xml - Combining Parent and Child Nodes(W Same Name) into Data Frame
R Column Check If Contains Value from Another Column
Displaying Data in the Chart Based on Plotly_Click in R Shiny
Compute All Fixed Window Averages with Dplyr and Rcpproll
Replacing the Duplicate Values Except 1 Row in R Dataframe
How to Get Rows, by Group, of Data Frame with Earliest Timestamp
Is R Superstitious Regarding Posixct Data Type
How to Remove Rows with All Zeros Without Using Rowsums in R
Aggregate by Specific Year in R
Multiple Graphs of Each Time Series
Obtain Latitude and Longitude from Address Without the Use of Google API