Monitoring flow execution after updating multiple reactive dependencies

This is a simple but complex problem. Here's a walkthrough:

I have three inputs i_1, i_2, i_3, which lead to three reactive values ​​that are used in different functions:

I1 <- reactive({input$i_1}) I2 <- reactive({input$i_2}) I3 <- reactive({input$i_3}) 

In particular, these three values ​​are used to plot as a reactive endpoint:

 output$plot <- renderPlot {( plot( f(I1(), I2(), I3()) ) )} 

Brilliant magic works, and everything works fine until I want to load some data and change the three i_X values:

 observe {( input$b_Load #Load button [...] updateSelectInput(session,"i_1", value = 4) updateSelectInput(session,"i_2", value = 3) updateSelectInput(session,"i_3", value = 5) ... )} 

The update itself works great, and three new values ​​for the variables are sent to the client.

Problem: The values ​​are then updated and sent one by one to the server, which re-schedules the schedule each time unnecessarily. I would like to update the chart only once, when all values ​​are updated. Is it possible?


I tried waiting for the onFlushed event:

  values <- reactiveValues(loadingProfile = FALSE) session$onFlushed(function() { values$loadingProfile <- FALSE cat("##### DEBUG: loading Profile OFF ##############\n", file = stderr()) }, once = FALSE) output$plot <- renderPlot {( if (!values$loadingProfile) { plot( f(I1(), I2(), I3()) ) } )} observe {( input$b_Load #Load button values$loadingProfile <- TRUE #Toggle on the watching value cat("##### DEBUG: loading Profile ON ##############\n", file = stderr()) [...] updateSelectInput(session,"i_1", value = 4) updateSelectInput(session,"i_2", value = 3) updateSelectInput(session,"i_3", value = 5) ... )} 

but this does not work because the session is cleared every time one of the three updated versions is sent back to the server ... (I checked on the console after activating the trace)


What will not work properly:

  • Counting events , as suggested by @jdharrison, can be a good hack, but will not work here, because if the loaded value with updateSelectInput() matches what it was before, this value is not sent back.
  • The wait is a bit , with something like invalidateLater(2000, session) kinda works (I tried), but is not reliable. It is not possible to specify a time that will always capture different exchanges without exceeding and, thus, pause execution for too long.
+5
source share
2 answers

This question has no answer from what I know about the current state of Brilliant. However, using the awesome reactive() expression, I was able to reorganize the stream of values ​​and update the graph only once. In practice

 output$plot <- renderPlot {( plot( f(User()) ) )} observe {( input$b_Load #Load button updateSelectInput(session,"i_1", value = 4) updateSelectInput(session,"i_2", value = 3) updateSelectInput(session,"i_3", value = 5) ... )} User <- reactive({ object <- list() object$i1 <- I1() object$i2 <- I2() object$i3 <- I3() )} 

+ a small correspondence f() .

Here, the reactive expression User() acts as a buffer. It will wait until all previous changes are rolled over before sending its value to f() .

I shared my complete Shiny project on Github , for more information.

+2
source

Something like the following will most likely solve your problem. I have not tested it, but

Set

 values <- reactiveValues(loadingProfile = 0) 

In renderPlot :

 output$plot <- renderPlot {( if (values$loadingProfile %/% 4 == 0) { plot( f(I1(), I2(), I3()) ) }else{ values$loadingProfile <- values$loadingProfile + 1 } )} 

remove the session$onFlushed and change the destination in observe to:

 isolate(values$loadingProfile <- values$loadingProfile + 1) 

As an example:

 library(shiny) runApp( list( ui = fluidPage( selectInput("id1", "select a number", 1:5) , selectInput("id2", "select a small letter", letters[1:5]) , selectInput("id3", "select a BIG letter", LETTERS[1:5]) , textOutput("text") , actionButton("myBtn", "Press me!!!") ) , server = function(input, output, session){ values <- reactiveValues(loadingProfile = 0) I1 <- reactive({input$id1}) I2 <- reactive({input$id2}) I3 <- reactive({input$id3}) output$text <- renderText({ if (values$loadingProfile %/% 4 == 0) { paste(I1(), I2(), I3()) }else{ values$loadingProfile <- values$loadingProfile + 1 } }) observe({ if(input$myBtn > 0){ isolate(values$loadingProfile <- values$loadingProfile + 1) updateSelectInput(session,"id1", "select a number", 1:5, selected = 5) updateSelectInput(session,"id2", "select a small letter", letters[1:5], selected = "e") updateSelectInput(session,"id3", "select a BIG letter", LETTERS[1:5], selected = "E") } }) } ) ) 
0
source

Source: https://habr.com/ru/post/1207773/


All Articles