我开发了一个Shiny应用程序,允许用户条件选择一些相关事件。下面是一个非常简化的玩具示例,以帮助说明我的问题/问题。
在我的实际问题中,服务器代码包含多个计算上昂贵的程序,这些程序是可选的运行程序。有一个"基线"必须运行以产生输出的函数,然后firstObject或secondObject将其作为输入,如果用户选择这样做,则产生更多输出。
每个功能最多可能需要30到40分钟。因此,我编写了代码以允许用户使用checkInputBox选择他们想要运行的函数,然后在选择它们之后,有一个操作它们的操作按钮,允许用户离开并让过程完成它的过程很长时间。这比将actionButton与每个可能的事件相关联更方便。
以下代码成功地产生了所有期望的输出。但是,从设计的角度来看,我不确定它是否正确"。在我的玩具示例中,代码很简单,但假设baseObject的代码需要30分钟才能运行。在baseObject运行时,firstObject和secondObject的代码也被执行,因为它们依赖于相同的操作按钮。但是,在完成baseObject的功能之前,他们无法做任何事情。类似地,在firstObject完成之前,secondObject不能执行任何操作。
同样,这一切都有效并产生正确的输出(在我的真实代码和玩具代码中)。但是,是否有一种方法可以维护单个操作按钮,但是对于firstObject不执行任何操作,UNTIL baseline已生成其输出,然后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
答案 0 :(得分:0)
关于反应性表达的两件事要记住:
反应式表达式是惰性的,只有在被其他东西调用时才会执行。这与观察者不同,观察者在其依赖性发生变化时立即执行。
缓存活动表达式结果。只要它们的依赖关系没有改变,后续调用就不会导致表达式重新执行,而是检索缓存的值。
基于这两点,我认为你没有问题,你的例子就是你正在寻找的。勾选两个复选框后,每个响应式表达式只会在每个操作按钮单击时运行一次。
虽然我可以建议删除eventReactive
中不必要的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)