What's the difference between Reactive Value and Reactive Expression? - r

In Shiny tutorial, there is an example:
fib <- function(n) ifelse(n<3, 1, fib(n-1)+fib(n-2))
shinyServer(function(input, output) {
currentFib <- reactive({ fib(as.numeric(input$n)) })
output$nthValue <- renderText({ currentFib() })
output$nthValueInv <- renderText({ 1 / currentFib() })
})
I don't get how reactive caches the values. Does it internally do something like return(function() cachedValue)?
Now I am wondering if I can do this?
fib <- function(n) ifelse(n<3, 1, fib(n-1)+fib(n-2))
shinyServer(function(input, output) {
currentFib <- reactiveValues({ fib(as.numeric(input$n)) })
output$nthValue <- renderText({ currentFib })
output$nthValueInv <- renderText({ 1 / currentFib })
})

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 extend input which gets specified in UI.R. Sometimes, the slots in input are not enough, and we want derived values based on those input slots. In other words, it is a way to extend the list of input 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 for reactive 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 to reactive.

Related

How to set NULL to reactive within other reactive?

I need to set NULL to reactive upon clicking in a button. I wonder if it's possible to set NULL to reactive which is in another reactive - and more precisely to make second reactive to return NULL.
In my example below data (as module parameter) is passed as reactive from other module.
module_server <- function(id, data){
moduleServer(
id,
function(input, output, session) {
ns <- NS(id)
# 1st reactive
reactive1 <-reactive(data())
reactive1(NULL)
# more code...
As you see and I tried to set NULL to reactive1 but it doesn't work.
Do you want to give it a NULL value when a condition is met? e.g.
reactive1 <- reactive({
if(condition is met){
data()
} else {
return(NULL)
}
This is something Winston Chang calls 'catching the NULL'. The code by James will work, however, if you catch the null at the start, then anything that takes dependency on a reactive will also be null if the initial condition is not met. For example, if r0 in the example below is null, then r1 will also be null. Note that you don't have to explicitly set r1 (or r0) to be null. My personal method is doing this:
r0<- shiny::reactive({
if(!is.null(input$blah)){
#do something here
}
})
r1<- shiny::reactive({
if(!is.null(r0())){
#do some other thing
}
})

Updating non-reactive values in R Shiny

I have the following example:
library(shiny)
ui <- fluidPage(
textOutput("out"),
actionButton("plusX", "Increase X"),
actionButton("redraw", "redraw")
)
server <- function(input, output, session) {
x <- 0
observeEvent(input$plusX, {x <<- x+1})
output$out <- renderText({
input$redraw
x
})
}
shinyApp(ui, server)
Is this considered an anti-pattern in Shiny to modify a non-reactive variable in this way? Obviating the super assignment which can be problematic by itself.
I know this could be done, for example with a reactiveVal to store X, and isolate to obtain a similar result. This second way seems clearer and that would be my usual choice, but I was wondering if there any caveats in the first one, or it is possible way of doing that.
library(shiny)
ui <- fluidPage(
textOutput("out"),
actionButton("plusX", "Increase X"),
actionButton("redraw", "redraw")
)
server <- function(input, output, session) {
x <- reactiveVal(0)
observeEvent(input$plusX, {x(x()+1)})
output$out <- renderText({
input$redraw
isolate(x())
})
}
shinyApp(ui, server)
In this example there is no important difference between both codes as you are not using the benefit of ReactiveVal.
The benefit of ReactiveVal is that it has a reactive nature and thus can interact with other reactive elements.
Try for example to add a table to your code that depends on x:
output$tab <- renderTable({data.frame(y = x)})
(x() in the case of ReactiveVal)
The difference you will see that in the case of ReactiveVal the table automatically updates with plusX whereas in the case of the regular variable it does not update.

Error in .getReactiveEnvironment()$currentContext() while using reactive output in reactiveValues function

I'm trying to get a reactiveValue that is depending on a reactive. In the real code (this is a very simplified version), I load a dataset interactively. It changes when pushing the buttons (prevBtn/nextBtn). I need to know the number of rows in the dataset, using this to plot the datapoints with different colors.
The question: Why can't I use the reactive ro() in the reactiveValues function?
For understanding: Why is the error saying "You tried to do something that can only be done from inside a reactive expression or observer.", although ro() is used inside a reactive context.
The error is definitely due to vals(), I already checked the rest.
The code :
library(shiny)
datasets <- list(mtcars, iris, PlantGrowth)
ui <- fluidPage(
mainPanel(
titlePanel("Simplified example"),
tableOutput("cars"),
actionButton("prevBtn", icon = icon("arrow-left"), ""),
actionButton("nextBtn", icon = icon("arrow-right"), ""),
verbatimTextOutput("rows")
)
)
server <- function(input, output) {
output$cars <- renderTable({
head(dat())
})
dat <- reactive({
if (is.null(rv$nr)) {
d <- mtcars
}
else{
d <- datasets[[rv$nr]]
}
})
rv <- reactiveValues(nr = 1)
set_nr <- function(direction) {
rv$nr <- rv$nr + direction
}
observeEvent(input$nextBtn, {
set_nr(1)
})
observeEvent(input$prevBtn, {
set_nr(-1)
})
ro <- reactive({
nrow(dat())
})
output$rows <- renderPrint({
print(paste(as.character(ro()), "rows"))
})
vals <- reactiveValues(needThisForLater = 30 * ro())
}
shinyApp(ui = ui, server = server)
Error in .getReactiveEnvironment()$currentContext() :
Operation not allowed without an active reactive context. (You tried to do something that can only be done from inside a reactive expression or observer.)
I think you want
vals <- reactiveValues(needThisForLater = reactive(30 * ro()))
Not everything in a reactiveValues list is assumed to be reactive. It's also a good place to store constant values. So since it's trying to evaluate the parameter you are passing at run time and you are not calling that line in a reactive environment, you get that error. So by just wrapping it in a call to reactive(), you provide a reactive environment for ro() to be called in.

Is it possible to create a user-defined function that takes reactive objects as input? How do I do it?

So, I've been on google for hours with no answer.
I want to create a user-defined function inside the server side that takes inputs that I already know to wrap reactive({input$feature)} but the issue is how to incorporate reactive values as inputs too.
The reason why I want to do this is because I have a navbarPage with multiple tabs that shares elements such as same plots. So I want a user defined function that creates all the similar filtering and not have to create multiple of the same reactive expression with different input and reactive variable names which take up 2000+ lines of code.
server <- function(input, output) {
filtered_JointKSA <- reactiveVal(0)
create_filtered_data <- function(df, input_specialtya, filtered_JointKSA) {
if (input_specialtya == 'manual') {
data <- filter(data, SPECIALTY %in% input_specialtyb)
}
if (filtered_JointKSA != 0) {
data <- filter(data, SPECIALTY %in% filtered_JointKSA)
}
reactive({return(data)})
}
filtered_data <- create_filtered_data(df,
reactive({input$specialty1}),
filtered_JointKSA())
observeEvent(
eventExpr = input$clickJointKSA,
handlerExpr = {
A <- filtered_JointKSA(levels(fct_drop(filtered_data()$`Joint KSA Grouping`))[round(input$clickJointKSA$y)])
A
}
)
This gets me an error:
"Error in match(x, table, nomatch = 0L) :
'match' requires vector arguments"
The error is gone if I comment out where I try to create filtered_data but none of my plots are created because filtered_data() is not found.
What is the correct approach for this?
Ideally, I would like my observeEvents to be inside user defined functions as well if that has a different method.
This example may provide some help, but it's hard to tell without a working example. The change is to wrap the call to your function in reactive({}) rather than the inputs to that function, so that the inputs are all responsive to user input and the function will update.
library(shiny)
ui <- fluidPage(
numericInput("num", "Number", value = NULL),
verbatimTextOutput("out")
)
server <- function(input, output){
## User-defined function, taking a reactive input
rvals <- function(x){
req(input$num)
if(x > 5){x * 10} else {x*1}
}
# Call to the function, wrapped in a reactive
n <- reactive({ rvals(input$num) })
# Using output of the function, which is reactive and needs to be resolved with '()'
output$out <- renderText({ n() })
}
shinyApp(ui, server)

R - Difference between calling value vs value()

Why should you call df() instead of df in the code below? Is this the correct syntax to use with the reactive function?
function(input, output, session){
df <- reactive({
head(cars, input$nrows)
})
output$plot <- renderPlot({
plot(df()) #Why call df() instead of df?
})
output$table <- renderTable({
df() #Why call df() instead of df?
})
}
You've set the value of df to equal the return value from a call to reactive.
From ?reactive:
Value
a function, wrapped in a S3 class "reactive"
df, therefore, is a function which, when called, will evaluate the saved expression and return the current value (and also trigger updates reactively).

Resources