在更新多个反应依赖项后控制执行流程

时间:2014-11-27 01:40:28

标签: r shiny

这是一个简单而先进的问题。这是一个演练:

我有三个输入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)
  ...
)}

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

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


我尝试等待onFlushed事件:

  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)之类的东西有点工作(我试过了)但不健全。不可能指定一个总是能够在没有超调的情况下捕获不同交易所的时间,从而暂停执行太长时间。

2 个答案:

答案 0 :(得分:2)

这个问题本身并没有我所知道的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项目,以获取更多信息。

答案 1 :(得分:0)

以下内容最有可能解决您的问题。我没有测试过,但是

设置

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