2017-09-11 57 views
0

UPDATE:改變到例如(希望)少一個抽象ř閃亮:observeEvent()的行爲不同基於什麼選項卡打開

我有光澤的應用程序使用所述數據集mtcars兩個標籤。 「位移」包含顯示disp與mpg的散點圖,「馬力」包含顯示hp與mpg的散點圖。兩個選項卡都包含一個複選框組輸入,允許用戶根據柱面數量篩選結果。 「生成」按鈕會生成圖形,以便在輸入更改後不會立即更改。

每個選項卡有兩個附加按鈕。 「比較」是一個切換按鈕,用於將一個選項卡的複選框輸入中的值複製到另一個選項卡的輸入並生成結果圖,以便您可以輕鬆比較兩個選項卡如何查找相同的輸入。 「恢復默認值」將複選框輸入重置爲其初始值。

這兩個按鈕都以相同的方式工作。每個按鈕都有自己的觀察者,一旦按下按鈕,就會觸發更新功能。該功能首先更新輸入,然後通過更新爲此目的創建的反應值來生成繪圖,然後切換到包含該繪圖的選項卡。

但是,只有比較按鈕才能正常工作,只需單擊一次即可更新輸入並生成圖形。另一方面,恢復默認按鈕僅更新輸入。您需要按兩次以更新繪圖。

我試圖從一個選項卡移動恢復默認值按鈕到另一個,然後確實更新在第一次點擊的情節,所以基於是否將影響情節的行爲變化是在同一個選項卡,該按鈕(應用程序在下面提供,所以你可以自己嘗試這個)。我對此行爲感到困惑,因爲連接按鈕和更新函數的observeEvent()函數編碼相同。它不應該在按鈕位於哪個標籤中。

任何人都可以解釋是什麼導致這一點,我應該改變,使兩個按鈕更新複選框輸入和繪圖輸出在一個單一的點擊?

library(shiny) 
library(ggplot2) 

ui <- fluidPage(
    tabsetPanel(id="App", 
    tabPanel(
     "displacement", 
     checkboxGroupInput("cyl1", "Number of cylinders", choices=c("4","6","8"), selected="4"), 
     actionButton("genDisp", "Generate"), 
     actionButton("switchToHp", "Compare"), 
     actionButton("resDefDisp", "Restore Default"), 
     plotOutput("disp") 
    ), 
    tabPanel(
     "horsepower", 
     checkboxGroupInput("cyl2", "Number of cylinders", choices=c("4","6","8"), selected="8"), 
     actionButton("genHp", "Generate"), 
     actionButton("switchToDisp", "Compare"), 
     actionButton("resDefHp", "Restore Default"), 
     plotOutput("hp") 
    ) 
) 
) 

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

    # reactive values used to trigger plot generation 
    generateDisp <- reactiveVal(0) 
    generateHp <- reactiveVal(0) 

    # "Generate" Buttons 
    observeEvent({ 
    input$genDisp 
    }, 
    { 
    generateDisp(generateDisp()+1) 
    }) 
    observeEvent({ 
    input$genHp 
    }, 
    { 
    generateHp(generateHp()+1) 
    }) 

    # "Compare"/"Restore Defaults" buttons 
    observeEvent({ 
    input$switchToHp 
    },{ 
    updateHp(cyl=input$cyl1) 
    }) 
    observeEvent({ 
    input$resDefDisp 
    },{ 
    updateDisp(cyl="4") 
    }) 
    observeEvent({ 
    input$switchToDisp 
    },{ 
    updateDisp(cyl=input$cyl2) 
    }) 
    observeEvent({ 
    input$resDefHp 
    },{ 
    updateHp(cyl="8") 
    }) 

    # Functions updating graphs 
    updateDisp <- function(cyl=NULL) 
    { 
    updateCheckboxGroupInput(session, "cyl1", "Number of cylinders", selected = cyl) 
    generateDisp(generateDisp()+1) 
    updateTabsetPanel(session, "App", selected = "displacement") 
    } 
    updateHp <- function(cyl=NULL) 
    { 
    updateCheckboxGroupInput(session, "cyl2", "Number of cylinders", selected = cyl) 
    generateHp(generateHp()+1) 
    updateTabsetPanel(session, "App", selected = "horsepower") 
    } 

    # output plots 
    output$disp <- renderPlot({ 
    generateDisp() 
    isolate({ 
     data <- filter(mtcars, cyl %in% input$cyl1) %>% 
     mutate(cyl=as.factor(cyl)) 
     ggplot(data, aes(x=mpg, y=disp, color=cyl)) + 
     geom_point() 
    }) 
    }) 
    output$hp <- renderPlot({ 
    generateHp() 
    isolate({ 
     data <- filter(mtcars, cyl %in% input$cyl2) %>% 
     mutate(cyl=as.factor(cyl)) 
     ggplot(data, aes(x=mpg, y=hp, color=cyl)) + 
     geom_point() 
    }) 
    }) 

} 


shinyApp(ui, server) 

回答

0

如果你改變你的代碼,以這樣的:你更新generateTalk的價值

,甚至後
observeEvent({ 
    c(input$updateTalk1, input$updateTalk2) 
}, { 
    updateNumericInput(session, "talkNumber", "Choose number", value = 2) 
    print(input$talkNumber) 
    generateTalk(generateTalk() + 1) 
    print(input$talkNumber) 

    updateTabsetPanel(session, "App", selected = "talk") 
}) 

你的數字輸入值更新爲2後,您會發現,輸入$ talkNumber是仍然是觸發函數時的值,在你的情況下是3,而不是2.所以當renderPrint函數運行時,它仍然使用舊值。我不確定底層的工作流程,但我想它只會在當前功能(反應式呼叫)完成時更改爲新值。

但是,當第一個選項卡不可見時,它將被強制重新呈現,因此它將更新所有UI元素,因此設置爲數字輸入的新值由renderPrint函數讀取。順便說一句,我覺得你的例子有點太抽象了,我想如果你能告訴我們你實際上想要做什麼,那麼你現在的方式會有更好的解決方案。

編輯:

我發現this後可能會有所幫助。基本上,update * Input函數只會在observeEvent結束後更改UI,因此generateDisp觸發的renderPlot將使用舊的輸入值。

+0

謝謝您的回覆。我把我的問題中的例子改爲了一個不太抽象的例子。我想要的是讓按鈕允許用戶在選項卡之間「切換」,從一個選項卡複製輸入值並將它們粘貼到另一個選項卡,以便他可以輕鬆比較不同圖形的相同輸入。我也想要按鈕將輸入更改爲某些預定義的值。這第二種按鈕通常位於與情節相同的選項卡中,這是我遇到此問題的原因。 –

+0

@FrankvanDorp如果您添加一個瀏覽器()語句作爲renderPlot的第一行並開始調試您的應用程序。您會注意到恢復默認按鈕實際上以某種方式觸發renderPlot運行兩次。這很奇怪,你可能想嘗試不使用reactiveVal。我會嘗試使用reactiveValues來查看是否有差異 –

+0

@FrankvanDorp當我在帖子中更新時,它是導致延遲的更新*輸入函數。在我看來更自然的是,當用戶點擊恢復默認按鈕時,只需更新selectInput,然後讓您的繪圖完全依賴selectInput並擺脫生成按鈕。 –

相關問題