【问题标题】:How to implement eventReactive with multiple reactive eventExpr?如何使用多个反应式 eventExpr 实现 eventReactive?
【发布时间】:2019-05-03 18:33:16
【问题描述】:

在 R 中初始化闪亮的应用程序时遇到问题。我希望 eventReactive 从多个事件中的任何一个触发,这些事件由响应式表达式链接。该应用程序大多按预期工作,但在初始化时不显示,而是要求用户在显示结果之前选择一个 actionButton。这是为什么呢?

我阅读了 eventReactive 的文档,使用了 ignoreNULL 和 ignoreInit 设置,并进行了许多在线搜索。

以下示例。

require(shiny)
require(ggplot2)

ui <- fluidPage(
  titlePanel("Car Weight"),
  br(),
  uiOutput(outputId = "cylinders"),
  sidebarLayout(
    mainPanel(
      # plotOutput(outputId = "trend"),
      # plotOutput(outputId = "hist"),
      tableOutput("table"),
      uiOutput(outputId = "dataFilter"),
      actionButton(inputId = "update1", label = "Apply Filters"),
      width = 9
    ),
    sidebarPanel(
      actionButton(inputId = "update2", label = "Apply Filters"),
      uiOutput(outputId = "modelFilter"),
      actionButton(inputId = "update3", label = "Apply Filters"),
      width = 3
    )
  )
)

server <- function(input, output) {
  # Read data.  Real code will pull from database.
  df <- mtcars
  df$model <- row.names(df)

  # Get cylinders
  output$cylinders <- renderUI(
    selectInput(
      inputId = "cyl",
      label = "Select Cylinders",
      choices = c("", as.character(unique(df$cyl)))
    )
  )

  # Subset data by cyl.
  df2 <-
    reactive(droplevels(df[df$cyl == input$cyl, ]))

  # Filter data.
  df3 <-
    eventReactive({
      ##############################################################
      # Help needed:
      # Why does this block not update upon change in 'input$cyl'?
      ##############################################################
      input$update1
      input$update2
      input$update3
      input$cyl
    },
    {
      req(input$modelFilter)
      modelFilterDf <-
        data.frame(model = input$modelFilter)
      df3a <-
        merge(df2(), modelFilterDf, by = "model")
      df3a[df3a$wt >= input$dataFilter[1] &
             df3a$wt <= input$dataFilter[2],]
    },
    ignoreNULL = FALSE,
    ignoreInit = FALSE)

  # Plot table.
  output$table <- renderTable(df3())

  # Filter by data value.
  output$dataFilter <-
    renderUI({
      req(df2()$wt[1])
      sliderInput(
        inputId = "dataFilter",
        label = "Filter by Weight (1000 lbs)",
        min = floor(min(df2()$wt, na.rm = TRUE)),
        max = ceiling(max(df2()$wt, na.rm = TRUE)),
        value = c(
          min(df2()$wt, na.rm = TRUE),
          max(df2()$wt, na.rm = TRUE)
        ),
        step = round(
          max(df2()$wt, na.rm = TRUE) - min(df2()$wt, na.rm = TRUE)
        ) / 100,
        round = round(log((
          max(df2()$wt, na.rm = TRUE) - min(df2()$wt, na.rm = TRUE)
        ) / 100))
      )
    })

  # Filter by lot / wafer.
  output$modelFilter <- renderUI({
    req(input$cyl)
    checkboxGroupInput(
      inputId = "modelFilter",
      label = "Filter by Model",
      choices = as.character(unique(df2()$model)),
      selected = as.character(unique(df2()$model))
    )
  })
}

# Run shiny.
shinyApp(ui = ui, server = server)

【问题讨论】:

  • eventReactive在启动过程中执行了两次,但在req(input$modelFilter)处停止。
  • 感谢@ismirsehregal。如果我删除req(input$modelFilter),代码将执行,但在执行merge(df2(), modelFilterDf, by = "model") 时将返回错误:'by' 必须指定唯一有效的列,这不是预期的结果。你有什么建议来解决这个问题吗?

标签: r shiny


【解决方案1】:

我找到了解决方案。也许不是最优雅的,但它确实有效。

问题是input$modelFilterinput$modelFilterdf2 后面的一个更新。这在用户选择input$update 时无关紧要,因为df2 没有更新,只是在新创建的df2 期间出现问题,因为过滤器与数据不匹配。

为了解决这个问题,我添加了values &lt;- reactiveValues(update = 0),每次创建df3 时都会增加+1,并在创建新的df2 时重置为0。如果values$update &gt; 0,则过滤数据,否则返回未过滤数据。

可能有用的链接:How can I set up triggers or execution order for eventReactive or ObserveEvent?

require(shiny)
require(ggplot2)

ui <- fluidPage(
  titlePanel("Car Weight"),
  br(),
  uiOutput(outputId = "cylinders"),
  sidebarLayout(
    mainPanel(
      tableOutput("table"),
      uiOutput(outputId = "dataFilter"),
      actionButton(inputId = "update1", label = "Apply Filters"),
      width = 9
    ),
    sidebarPanel(
      actionButton(inputId = "update2", label = "Apply Filters"),
      uiOutput(outputId = "modelFilter"),
      actionButton(inputId = "update3", label = "Apply Filters"),
      width = 3
    )
  )
)

server <- function(input, output) {
  # Read data.  Real code will pull from database.
  df <- mtcars
  df$model <- row.names(df)
  df <- df[order(df$model), c(12,1,2,3,4,5,6,7,8,9,10,11)]

  # Get cylinders
  output$cylinders <- renderUI({
    selectInput(
      inputId = "cyl",
      label = "Select Cylinders",
      choices = c("", as.character(unique(df$cyl)))
    )})

  # Check if data frame has been updated.
  values <- reactiveValues(update = 0)

  # Subset data by cyl.
  df2 <-
    reactive({
      values$update <- 0
      df2 <- droplevels(df[df$cyl == input$cyl,])})

  # Filter data.
  df3 <-
    eventReactive({
      input$update1
      input$update2
      input$update3
      df2()
    },
    {
      if (values$update > 0) {
        req(input$modelFilter)
        modelFilterDf <-
          data.frame(model = input$modelFilter)
        df3a <-
          merge(df2(), modelFilterDf, by = "model")
        df3a <- df3a[df3a$wt >= input$dataFilter[1] &
                       df3a$wt <= input$dataFilter[2], ]
      } else {
        df3a <- df2()
      }

      values$update <- values$update + 1
      df3a
    },
    ignoreNULL = FALSE,
    ignoreInit = TRUE)

  # Plot table.
  output$table <- renderTable(df3())

  # Filter by data value.
  output$dataFilter <-
    renderUI({
      req(df2()$wt[1])
      sliderInput(
        inputId = "dataFilter",
        label = "Filter by Weight (1000 lbs)",
        min = floor(min(df2()$wt, na.rm = TRUE)),
        max = ceiling(max(df2()$wt, na.rm = TRUE)),
        value = c(floor(min(df2()$wt, na.rm = TRUE)),
                  ceiling(max(df2()$wt, na.rm = TRUE))),
        step = round(max(df2()$wt, na.rm = TRUE) - min(df2()$wt, na.rm = TRUE)) / 100,
        round = round(log((
          max(df2()$wt, na.rm = TRUE) - min(df2()$wt, na.rm = TRUE)
        ) / 100))
      )
    })

  # Filter by lot / wafer.
  output$modelFilter <- renderUI({
    req(input$cyl)
    checkboxGroupInput(
      inputId = "modelFilter",
      label = "Filter by Model",
      choices = as.character(unique(df2()$model)),
      selected = as.character(unique(df2()$model))
    )
  })
}

# Run shiny.
shinyApp(ui = ui, server = server)

【讨论】:

    猜你喜欢
    • 2018-08-01
    • 1970-01-01
    • 2019-12-25
    • 2019-10-09
    • 2018-10-30
    • 1970-01-01
    • 1970-01-01
    • 2021-10-06
    • 1970-01-01
    相关资源
    最近更新 更多