【问题标题】:One Action Button for Multiple Dependent Events in ShinyShiny 中多个相关事件的一个操作按钮
【发布时间】:2018-05-02 03:26:55
【问题描述】:

我开发了一个 Shiny 应用程序,它允许用户有条件地选择一些相关事件。下面是一个非常简化的玩具示例,以帮助说明我的问题/问题。

在我的实际问题中,服务器代码包含多个计算成本高昂的过程,这些过程是可选的。有一个“基线”函数必须运行以产生输出,然后 firstObject 或 secondObject 将其作为输入并在用户选择时产生更多输出。

每个函数可能需要 30 到 40 分钟。因此,我编写了代码以允许用户使用 checkInputBox 选择他们想要运行的功能,然后在选择它们之后,有一个操作按钮可以运行它们,允许用户离开并让流程结束很长时间。这比为每个可能的事件关联一个 actionButton 更方便。

下面的代码成功地产生了所有期望的输出。但是,从设计的角度来看,我不确定它是否“正确”。在我的玩具示例中,代码很简单,但假设 baseObject 的代码需要 30 分钟才能运行。当 baseObject 运行时,firstObject 和 secondObject 的代码也被执行,因为它们依赖于相同的操作按钮。但是,在 baseObject 的函数完成之前,他们不能做任何事情。同样,在 firstObject 完成之前, secondObject 无法执行任何操作。

同样,这一切都有效并产生了正确的输出(在我的真实代码和玩具代码中)。但是,有没有办法维护单个操作按钮,但 firstObject 不做任何事情,直到基线 Object 产生其输出,然后 secondObject 将等待 firstObject 产生其输出(如果用户选择它)。

我担心的是我在 firstObject 中创建了额外的计算开销,它试图做一些在 baseObject 完成之前它不能做的事情,并且它会一遍又一遍地循环直到它可以正确执行。

我知道我可以创建不同的操作按钮。例如,我可以为基线创建一个操作按钮,然后用户可以等到它完成,然后单击 firstObject 的操作按钮等等。但是,从功能上讲,这不起作用,因为在实际问题中,这允许整个选定的进程运行,这可能需要几个小时,而且用户不需要在他们的机器前。

谢谢,我希望这段代码有助于说明我所描述的问题。

ui <- {
  fluidPage(
    h3('Run Stuff'),
    checkboxInput("runModel1", "Model 1"),
    checkboxInput("runModel2", "Model 2"),
    actionButton('runAll', 'Run Models'),
    verbatimTextOutput("out1"),
    verbatimTextOutput("out2")
    )
}

    server <- function(input, output, session) {

baseObject <- eventReactive(input$runAll, {
    if(input$runModel1){
        runif(100)
    }
})

firstObject <- eventReactive(input$runAll, {
    if(input$runModel1){
        runif(100) + baseObject()
    }
})

secondObject <- eventReactive(input$runAll, {
    if(input$runModel2){
        runif(100) + firstObject()
    }
})

output$out1 <- renderPrint({
if (input$runModel1)
    firstObject()
})

output$out2 <- renderPrint({
if (input$runModel2)
    secondObject()
})
} # end server


shinyApp(ui, server) #run 

【问题讨论】:

    标签: r shiny


    【解决方案1】:

    关于反应式表达式要记住两点:

    1. 反应式表达式是惰性的,只有在被其他东西调用时才会执行。这与观察者不同,观察者在其依赖关系发生变化时立即执行。

    2. 响应式表达式结果被缓存。只要它们的依赖关系没有改变,后续调用就不会导致表达式重新执行,而是取回缓存的值。

    基于这两点,我认为您没有问题,并且您的示例符合您的要求。勾选两个复选框后,每个响应式表达式只会在每次操作按钮单击时运行一次。

    虽然我可以建议删除 eventReactives 中不必要的 if 语句。这将允许用户只检查runModel2 并使其所有依赖项正常运行。下面的修改示例 - 我还添加了一些 message(...) 语句,以便您可以在 R 控制台中看到执行流程。

    library(shiny)
    
    ui <- fluidPage(
      h3('Run Stuff'),
      checkboxInput("runModel1", "Model 1"),
      checkboxInput("runModel2", "Model 2"),
      actionButton('runAll', 'Run Models'),
      verbatimTextOutput("out1"),
      verbatimTextOutput("out2")
    )
    
    server <- function(input, output, session) {
    
      baseObject <- eventReactive(input$runAll, {
        message("calculating baseObject...")
        result <- runif(100)
        message("...baseObject done")
        return(result)
      })
    
      firstObject <- eventReactive(input$runAll, {
        message("calculating firstObject...")
        result <- runif(100) + baseObject()
        message("...firstObject done")
        return(result)
      })
    
      secondObject <- eventReactive(input$runAll, {
        message("calculating secondObject...")
        result <- runif(100) + firstObject()
        message("...secondObject done")
        return(result)
      })
    
      output$out1 <- renderPrint({
        if (input$runModel1)
          firstObject()
      })
    
      output$out2 <- renderPrint({
        if (input$runModel2)
          secondObject()
      })
    }
    
    shinyApp(ui, server)
    

    【讨论】:

      猜你喜欢
      • 2017-02-04
      • 1970-01-01
      • 1970-01-01
      • 2017-05-03
      • 2021-03-02
      • 2016-05-29
      • 2016-12-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多