【问题标题】:How can I ensure that observe is called before renderPlot in my shiny app如何确保在我闪亮的应用程序中的 renderPlot 之前调用观察
【发布时间】:2014-10-04 14:22:49
【问题描述】:

我有一个闪亮的应用程序,带有两个 selectInputs(L1 和 L2),观察者使用 updateSelectInput 根据 L1 的选择更新 L2。我还有一个取决于这两种选择的 renderPlot 输出。我面临的问题是,每当我更改 L1 时,renderPlot 都会被调用两次,一次使用 L2 的旧值,一次使用新值(在 updateSelectInput 中设置)。我的代码如下:

ui.R
shinyUI(
    fluidPage(
        titlePanel("Nested Selects Problem"),
        sidebarLayout(
            sidebarPanel(
                selectInput(
                    "L1",
                    label = "L1",
                    choices = c("red", "blue")
                    ),
                selectInput(
                    "L2",
                    label = "L2",
                    choices = ""
                    )
                ),
            mainPanel(
                plotOutput("plot")
                )
            )
        )
    )

server.R
shinyServer(
    function(input,output,session) {
        observe({
            if (input$L1 == "red") {
                choices <- c(1000000,2000000,3000000)
            }
            else {
                choices <- c(10,20,30)
            }
            updateSelectInput(session,"L2",choices=choices,selected=choices[1])
        })

        output$plot <- renderPlot({
            if (input$L2 != "") {
                plot(runif(as.numeric(input$L2)),col=input$L1)
            }
        })
    })

如何避免第一次调用 renderPlot?在我看来,如果我可以安排在第一个 renderPlot 之前调用 observe(),我会得到想要的效果。

感谢您的帮助。

【问题讨论】:

  • 创建一个将在观察者中更新的反应值怎么样?在 renderPlot 中,您还可以检查反应值的状态(如果不满足,则不绘制任何内容)。而且由于它是一个反应值,一旦它被改变,它将使renderPlot失效,从而触发重绘。

标签: r shiny observers


【解决方案1】:

您可以在renderPlot 内的input$L1 调用中使用isolate。以这种方式,只有在 input$L1 发生更改时,更改才会从您的 updateSelectInput 调用传播:

library(shiny)
runApp(list(
  ui = fluidPage(
    titlePanel("Nested Selects Problem"),
    sidebarLayout(
      sidebarPanel(
        selectInput("L1",label = "L1",choices = c("red", "blue")),
        selectInput("L2",label = "L2",choices = "")
      ),
      mainPanel(
        plotOutput("plot")
      )
    )
  )


  , server = function(input,output,session) {
    observe({
      if (input$L1 == "red") {
        choices <- c(100,200,300)
      }
      else {
        choices <- c(10,20,30)
      }
      updateSelectInput(session,"L2",choices=choices,selected=choices[1])
    })

    output$plot <- renderPlot({
      if (input$L2 != "") {
        plot(runif(as.numeric(input$L2)),col=isolate(input$L1))
      }
    })
  })
)

【讨论】:

  • 这行得通,但这只是因为我的示例中可用的 L1 和 L2 选项的值。但是,如果蓝色 L1 有选择 (10,20,30,100) 并且用户选择了 100,则当 L1 更改为红色时将没有效果,因为“新”L2 值(红色默认值为 100)是与其当前值 100 相同。
【解决方案2】:

那么,怎么样:

shinyServer(
  function(input,output,session) {
    L1_selected <- reactiveValues(triggered=-1)

    observe({
      if (input$L1 == "red") {
        choices <- c(10, 100,200,300)
      }
      else {
        choices <- c(10,20,30)
      }

      old_L2 <- isolate(input$L2)
      updateSelectInput(session,"L2",choices=choices,selected=choices[1])
      isolate(L1_selected$triggered <- L1_selected$triggered + as.numeric(old_L2 != choices[1]))
    })

    output$plot <- renderPlot({
      if (input$L2 != "") {
        if (isolate(L1_selected$triggered)) {
          isolate(L1_selected$triggered <- L1_selected$triggered - 1)
          return()
        } else {
          plot(runif(as.numeric(input$L2)),col=input$L1)
        }
      }
    })
  })

【讨论】:

    猜你喜欢
    • 2021-11-07
    • 1970-01-01
    • 2014-02-12
    • 1970-01-01
    • 2021-08-27
    • 1970-01-01
    • 2015-10-01
    • 2021-03-09
    相关资源
    最近更新 更多