2017-09-11 55 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并摆脱生成按钮。 –

相关问题