r语言 - 在更新多个反应式依赖项后控制执行流


这是一个

简单而高级的问题。下面是一个演练:

我有三个输入i_1、i_2、i_3,它们导致三个用于不同函数的反应值:

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

具体来说,这三个值用于将图形绘制为反应性端点:

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

闪亮的魔法奏效了,一切正常,直到我想加载一些数据并修改三个i_X值:

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

更新本身工作正常,变量的三个新值将发送到客户端。

问题:然后更新值并逐个发送回服务器,服务器每次都会不必要地重新计算图形。当所有值都更新时,我只想更新一次图表。可能吗?


我试图等待刷新事件:

  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)
    ...
  )}

但它不起作用,因为每次将三个更新版本中的一个发送回服务器时都会刷新会话......(激活跟踪后我在控制台上检查了)


什么将无法正常工作:

  • 正如 @jdharrison 所建议的那样,对事件进行计数可能是一个很好的技巧,但在这里不起作用,因为如果带有 updateSelectInput() 的加载值与以前相同,则该值不会发回。
  • 稍等片刻,类似的东西invalidateLater(2000, session)有点有效(我试过了),但并不强大。不可能指定一个时间,该时间将始终捕获不同的交换而不会过度跳动,从而暂停执行太长时间。

这个问题本身并没有答案,从我对Shiny现状的了解来看。尽管如此,使用很棒的reactive()表达式,我已经能够重构值流并仅更新一次图形。在行动上

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()
)}

+ 对f()的小重写.

在这里,User()反应表达式扮演缓冲区的角色。它将等待推送所有以前的更改,然后再将自己的值发送到f()

我已经在Github上分享了我的完整Shiny项目,以获取更多信息。

类似以下内容很可能会解决您的问题。我还没有测试过,但是

设置

values <- reactiveValues(loadingProfile = 0)

renderPlot

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

删除对session$onFlushed的呼叫,并将observe中的分配更改为:

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

举个例子:

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")
        }
      })
    }
  )
)

最新更新