2017-11-18 98 views
0

我開發了一個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 

回答

0

兩件事情要記住的反應式:

  1. 反應表現是懶惰而且只有當別的東西叫做執行。這與觀察者不同,觀察者在其相關性發生變化時立即執行。

  2. 緩存了活性表達式結果。只要它們的依賴關係沒有改變,後續的調用就不會導致表達式重新執行,而是檢索緩存的值。

基於這兩點,我認爲你沒有問題,你的例子就是你要找的。選中這兩個複選框後,每個動作按鈕點擊只會運行一次。

雖然我可以建議刪除eventReactive s中不必要的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)