Shiny:如何在获取数据后或在给定时间停止处理invalidateLater()

Lea*_*210 2 r shiny

我想继续刷新直到10:05,10:05之后我得到了tplus0_dt并停止处理invalidaterLater()。

10:00之前,tplus0_dt不存在,所以我需要不断刷新直到10:05。10:05之后,不需要重新刷新,当tplus0_dt变得非常大时,invalidaterLater()会影响table1的显示,屏幕和绘图每隔1秒就会变成灰色,所以看起来更新时页面已经死了发生。

那么我该如何停止处理 invalidateLater() 并在 10:05 之后继续显示数据呢?感谢帮助!我的示例代码如下。

require(shiny)
require(data.table)
app <- shinyApp(
    server = function(input, output, session){
            get_tplus0_data <- reactive({
                    time <- substr(as.character(Sys.time()), 12, 16)
                    invalidateLater(1000)
                    if(time >= "10:05"){
                            # tplus0_dt<-data.table(read.csv("/data/df_highest_after_signal.csv",header = T, sep = ",", stringsAsFactors = F)) 
                            tplus0_dt<- data.table(a = c(1, 2, 3, 4), b = c(3, 4, 5, 8)) 
                            return(tplus0_dt)
                    }

            })
            output$table1 <- renderTable({get_tplus0_data()})
    },
    ui = fluidPage( tableOutput("table1")  )
)

runApp(app)
Run Code Online (Sandbox Code Playgroud)

3D0*_*D0G 8

尽管你永远不会从 Shiny 文档中意识到这一点,但invalidateLater()实际上只返回到你的反应一次。它似乎重复返回的原因是在每次行程中该invalidateLater()函数都会再次运行。

因此,解决方案是在函数周围使用条件,这样您就不会重复调用它:

if(runMeAgain) {
   invalidateLater(n)
}

runMeAgain = TRUE   # your reactive re-runs every n milliseconds
runMeAgain = FALSE  # your reactive does not re-run
Run Code Online (Sandbox Code Playgroud)

另请注意:

  • invalidateLater()是非阻塞的(等待时其他代码可以运行)
  • invalidateLater()不会阻止其余反应的运行。如果您想在代码中的该点停止反应,请在return()后面添加一个invalidateLater()
  • invalidateLater()进入orisolated()内部,因此不起作用;你必须使用或。它也可能在渲染函数中工作,但我还没有理由尝试这样做。observeEvent()eventReactive()observe()reactive()

就原始问题而言,反应式应该如下所示:

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()
    }
})
Run Code Online (Sandbox Code Playgroud)


Big*_*ist 5

您根据需要重写该功能怎么样?

invalidateLaterNew如果在控制台中输入,将会打印该函数的代码。

要覆盖包中的函数,这篇文章将有所帮助:覆盖命名空间中导入的函数

然后您将不得不考虑函数.getReactiveEnvironment()timerCallbacks()无法在命名空间之外访问。但你可以这样称呼它们:shiny:::.getReactiveEnvironment()

把它放在一起:

您添加一个附加参数(例如),这将使您能够随时update停止。invalideLater()

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")
Run Code Online (Sandbox Code Playgroud)

例子:

我使用 中给出的示例?invalidateLater来演示效果:(当大于 800invalidateLater时将停止。因此您可以根据您的时间限制调整此示例)。input$n我决定不使用您的时间限制示例,因为测试起来不太方便;)

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)
Run Code Online (Sandbox Code Playgroud)