Shiny: How to stop processing invalidateLater() after data was abtained or at the given time

后端 未结 2 493
日久生厌
日久生厌 2020-12-11 12:14

I want to keep reflashing until 10:05, after 10:05 I got the tplus0_dt and stop to processing invalidaterLater().

Before 10:00, tplus0_dt doesn\'t exist, so I need

相关标签:
2条回答
  • 2020-12-11 12:36

    How about you override the function to your needs?

    If you enter invalidateLaterNew in the console, the code of the function will be printed.

    To overwrite a function within a package this post will help: Override a function that is imported in a namespace

    Then you will have to consider that the functions .getReactiveEnvironment() and timerCallbacks() are not accessible outside the namespace. But you can call them like this: shiny:::.getReactiveEnvironment()

    Bring it together:

    You add an additional parameter (e.g. update), which will enable you to stop the invalideLater() whenever you want.

    invalidateLaterNew <- function (millis, session = getDefaultReactiveDomain(), update = TRUE) 
    {
      if(update){
        ctx <- shiny:::.getReactiveEnvironment()$currentContext()
        shiny:::timerCallbacks$schedule(millis, function() {
          if (!is.null(session) && session$isClosed()) {
            return(invisible())
          }
          ctx$invalidate()
        })
        invisible()
      }
    }
    
    unlockBinding("invalidateLater", as.environment("package:shiny"))
    assign("invalidateLater", invalidateLaterNew, "package:shiny")
    

    Example:

    I used the example given in ?invalidateLater to demonstrate the effect: (invalidateLater will stop when input$nis bigger than 800. So you can adapt this example to your time restriction). I decided not to use your time restriction example as it wouldnt be that handy to test ;)

    ui <- fluidPage(
      sliderInput("n", "Number of observations", 2, 1000, 500),
      plotOutput("plot")
    )
    
    server <- function(input, output, session) {
    
      observe({
        # Re-execute this reactive expression after 1000 milliseconds
        invalidateLater(1000, session, input$n < 800)
        # Do something each time this is invalidated.
        # The isolate() makes this observer _not_ get invalidated and re-executed
        # when input$n changes.
        print(paste("The value of input$n is", isolate(input$n)))
      })
    
      # Generate a new histogram at timed intervals, but not when
      # input$n changes.
      output$plot <- renderPlot({
        # Re-execute this reactive expression after 2000 milliseconds
        invalidateLater(2000, session, input$n < 800)
        hist(rnorm(isolate(input$n)))
      })
    }
    
    shinyApp(ui, server)
    
    0 讨论(0)
  • 2020-12-11 12:53

    Although you'd never realize it from the Shiny documentation, invalidateLater() actually only returns to your reactive once. The reason it seems to return repeatedly is that on each trip the invalidateLater() function gets run again.

    So the solution is to use a conditional around the function so that you don't keep repeatedly calling it:

    if(runMeAgain) {
       invalidateLater(n)
    }
    
    runMeAgain = TRUE   # your reactive re-runs every n milliseconds
    runMeAgain = FALSE  # your reactive does not re-run
    

    Also note that:

    • invalidateLater() is non-blocking (other code can run while you wait)
    • invalidateLater() doesn't stop the rest of the reactive from running. If you want to stop the reactive at that point in the code, put a return() after invalidateLater()
    • invalidateLater() gets isolated() inside an observeEvent() or eventReactive() and consequently doesn't work; you have to use observe() or reactive(). It might also work inside a render function, but I haven't ever had a reason to try that.

    In terms of the original question, the reactive should look like this:

    get_tplus0_data <- reactive({
        time <- substr(as.character(Sys.time()), 12, 16)
        if(time >= "10:05"){
            tplus0_dt<- data.table(a = c(1, 2, 3, 4), b = c(3, 4, 5, 8)) 
            return(tplus0_dt)
        } else {
            invalidateLater(1000)
            return()
        }
    })
    
    0 讨论(0)
提交回复
热议问题