Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

shiny: Update input without reactives getting triggered?

Is there any possibility to update an input without reactives getting triggered?

Below I put a minimal example. The aim is to update the slider without the value in the main panel changing. When the slider is changed again, then it should be forwarded to dependent reactives again.

The question and the underlying use case is similiar to the following questions: R shiny - possible issue with update***Input and reactivity and Update SelectInput without trigger reactive?. Similiar to these questions, there is a reactive that depends on two Inputs in my use case. I want to update one of these input depending on the other, which results in the reactive getting calculated twice. However, both of these questions got around the problem by updating the input only selectively. This is not possible in my use case, since I want to have some information shown to the user by updating the input.

If there is no possibility to update an input without reactives getting triggered, I will ask a follow-up-question focusing on my use case.

Example

library(shiny)

ui <- fluidPage(
   titlePanel("Update Slider - Isolate reaction?"),

   sidebarLayout(
      sidebarPanel(
         sliderInput("bins",
                     "Number of bins:",
                     min = 1,
                     max = 50,
                     value = 30),
         actionButton("set1", "set slider 'bins'$value=20"),
         actionButton("set2", "'ISOLATED' set slider 'bins'$value=20 ")
      ),

      mainPanel(
         textOutput("sliderValue")
      )
   )
)

# Define server logic 
server <- function(input, output, session) {
   output$sliderValue <- renderText(input$bins) 

   observeEvent(input$set1,{
     updateSliderInput(session,"bins",value=20)
   })
   observeEvent(input$set2,{
     ## Is there any possibility to update the slider without 'sliderValue' changing?
     #isolate does not work
     isolate(
       updateSliderInput(session,"bins",value=20 )
       )
   })
}

shinyApp(ui = ui, server = server)
like image 725
Julian Avatar asked Feb 06 '19 18:02

Julian


People also ask

What is reactive programming in shiny?

In Shiny, you express your server logic using reactive programming. Reactive programming is an elegant and powerful programming paradigm, but it can be disorienting at first because it’s a very different paradigm to writing a script.

How does shiny know when to update an output?

This is the big idea in Shiny: you don’t need to tell an output when to update, because Shiny automatically figures it out for you. How does it work? What exactly is going on in the body of the function?

Why doesn’t shiny create a string when we update input$name?

But Shiny performs the action every time we update input$name, so there must be something more going on. The app works because the code doesn’t tell Shiny to create the string and send it to the browser, but instead, it informs Shiny how it could create the string if it needs to. It’s up to Shiny when (and even if!) the code should be run.

What are the 3 parameters of a server function in shiny?

This is why almost all of the reactive programming you’ll do in Shiny will be inside the server function 6 . Server functions take three parameters: input, output, and session . Because you never call the server function yourself, you’ll never create these objects yourself.


1 Answers

Here's a stab, though it feels like there might be side-effects from using stale data. Using the following diff:

 # Define server logic
 server <- function(input, output, session) {
-  output$sliderValue <- renderText(input$bins)
+  output$sliderValue <- renderText({ saved_bins(); })

+  update <- reactiveVal(TRUE)
+  saved_bins <- reactiveVal(30)
+
+  observeEvent(input$bins, {
+    if (update()) saved_bins(input$bins) else update(TRUE)
+  })
   observeEvent(input$set1,{
     updateSliderInput(session,"bins",value=20)
   })
   observeEvent(input$set2,{
     ## Is there any possibility to update the slider without 'sliderValue' changing?
     #isolate does not work
+    update(FALSE)
-    isolate(
       updateSliderInput(session,"bins",value=20 )
-    )
   })
 }

The method: using two new reactive values, one to store the data that (saved_bins) is used in the rendering, and one (update) to store whether that data should be updated. Everything that depends on input$bins should instead depend on saved_bins(). By using an additional observeEvent, the reactivity will always cascade as originally desired except when you explicitly set a one-time "do not cascade" with the prepended update(FALSE).

Full code below:

library(shiny)

ui <- fluidPage(
   titlePanel("Update Slider - Isolate reaction?"),

   sidebarLayout(
      sidebarPanel(
         sliderInput("bins",
                     "Number of bins:",
                     min = 1,
                     max = 50,
                     value = 30),
         actionButton("set1", "set slider 'bins'$value=20"),
         actionButton("set2", "'ISOLATED' set slider 'bins'$value=20 ")
      ),

      mainPanel(
         textOutput("sliderValue")
      )
   )
)

# Define server logic 
server <- function(input, output, session) {
  output$sliderValue <- renderText({ saved_bins(); }) 

  update <- reactiveVal(TRUE)
  saved_bins <- reactiveVal(30)

  observeEvent(input$bins, {
    if (update()) saved_bins(input$bins) else update(TRUE)
  })
  observeEvent(input$set1,{
    updateSliderInput(session,"bins",value=20)
  })
  observeEvent(input$set2,{
    ## Is there any possibility to update the slider without 'sliderValue' changing?
    #isolate does not work
    update(FALSE)
    updateSliderInput(session,"bins",value=20)
 })
}

shinyApp(ui = ui, server = server)
like image 81
r2evans Avatar answered Oct 18 '22 19:10

r2evans