【问题标题】:Multiple dynamic filter updates in shiny闪亮的多个动态过滤器更新
【发布时间】:2020-10-30 19:00:08
【问题描述】:

我希望能够在闪亮的 UI 输入中根据用户之前的选择进行自我更新。所以在下面的例子中,预期的行为是用户从cylvscarb中选择

  1. 过滤数据集mtcars用于创建绘图,即用户将绘图调整为过滤条件和
  2. 更新其他过滤器中的剩余输入选项,以便与基于现有过滤器的剩余选项相对应。

这是我尝试过的:

library(shiny)
library(dplyr)
library(plotly)

data("mtcars")

# create ui
ui <- fluidPage(
  fluidRow(
    box(
      title = "Filter",
      uiOutput(outputId = "cyl_dynamic_input"),
      uiOutput(outputId = "vs_dynamic_input"),
      uiOutput(outputId = "carb_dynamic_input")
    ),
    box(
      title = "Plot of mtcars",
      plotlyOutput("carplot")
    )
  ),
)

# create server
server <- function(input, output, session) {
  # create reactive filters of the mtcars table
  mtcars.reactive <- 
    reactive({
      mtcars %>%
        filter(mpg %in% input$cyl_input_rendered &
                 vs %in% input$vs_input_rendered &
                 carb %in% input$carb_input_rendered
        )})
  ## create rendered inputs
  # for cyl
  output$cyl_dynamic_input <- renderUI({
    pickerInput(inputId = "cyl_input_rendered",
                label = "CYL",
                choices = unique(mtcars$cyl),
                multiple = T,
                selected = mtcars.reactive()$cyl,
                options = list(
                  `actions-box` = TRUE,
                  `selected-text-format`= "count",
                  `count-selected-text` = "{0} out of {1} cyl selected"
                ))
  })
  # for vs
  output$vs_dynamic_input <- renderUI({
    pickerInput(inputId = "vs_input_rendered",
                label = "VS",
                choices = unique(mtcars$vs),
                multiple = T,
                selected = mtcars.reactive()$vs,
                options = list(
                  `actions-box` = TRUE,
                  `selected-text-format`= "count",
                  `count-selected-text` = "{0} out of {1} vs selected"
                ))
  })
  # for carb
  output$carb_dynamic_input <- renderUI({
    pickerInput(inputId = "carb_input_rendered",
                label = "CARB",
                choices = unique(mtcars$carb),
                multiple = T,
                selected = mtcars.reactive()$carb,
                options = list(
                  `actions-box` = TRUE,
                  `selected-text-format`= "count",
                  `count-selected-text` = "{0} out of {1} carb selected"
                ))
  })
  ## create the plot output
  # Start Barplot Emissionen here 
  output$carplot<-
    renderPlotly({
    # create plot
    plot<-ggplot(mtcars.reactive(), aes(wt, mpg))+
      geom_point()
    # convert to plotly
    ggplotly(plot)
  })
  
  
  
}

shinyApp(ui, server)

我的猜测是这不起作用,因为mtcarstable 的过滤器引用了渲染的输入,反之亦然,这会以某种方式创建一个空的信息循环

我已经看过official Shiny documentation,它也提供了一些background information,但整个主题对于初学者来说并不是很直观。这是一个similar question,但它不是完全可重现的。

【问题讨论】:

  • 要根据另一个 pickerInput 的选定值更改选定的值,您需要在响应于定义pickerInput。没有必要使用uiOutput/renderUI
  • 您还必须确保逻辑不会互锁:如果用户取消选择所有内容,则可能无法返回,因为 mtcars.reactive() 将是空的,因此所有唯一的( ...) 选择可能性也将变为空
  • 谢谢你们两位的cmets。我可以解决第一个问题,它想稍后再提供答案。但是@Waldi 关于联锁的第二条评论不是。您会建议如何解决空 mtcars 取消选择所有的问题?
  • 您可能需要在 pickerInputs 之间保持层次结构:第一个完全免费,第二个取决于第一个,第三个取决于第一个和第二个。不像你最初的愿望那样开放,但更容易理解/处理

标签: r shiny reactive


【解决方案1】:

以下内容在没有层次结构的情况下执行您想要的操作,但在 observeEvent 语句中使用 pickerInput 和条件语句。一开始它看起来很复杂,但它做了它应该做的事情。

library(shiny)
library(dplyr)
library(plotly)

data("mtcars")

# create ui
ui <- fluidPage(fluidRow(
  box(
    title = "Filter",
    pickerInput(
      inputId = "cyl_pickerinput",
      label = "CYL",
      choices = levels(as.factor(mtcars$cyl)),
      multiple = T,
      selected = levels(as.factor(mtcars$cyl)),
      options = list(
        `live-search` = TRUE,
        #`actions-box` = TRUE,
        `selected-text-format` = "count",
        `count-selected-text` = "{0} out of {1} cyl selected"
      )
    ),
    pickerInput(
      inputId = "vs_pickerinput",
      label = "VS",
      choices = levels(as.factor(mtcars$vs)),
      multiple = T,
      selected = levels(as.factor(mtcars$vs)),
      options = list(
        `live-search` = TRUE,
        #`actions-box` = TRUE,
        `selected-text-format` = "count",
        `count-selected-text` = "{0} out of {1} vs selected"
      )
    ),
    pickerInput(
      inputId = "carb_pickerinput",
      label = "CARB",
      choices = levels(as.factor(mtcars$carb)),
      multiple = T,
      selected = levels(as.factor(mtcars$carb)),
      options = list(
        `live-search` = TRUE,
        #`actions-box` = TRUE,
        `selected-text-format` = "count",
        `count-selected-text` = "{0} out of {1} carb selected"
      )
    ),
  ),
  box(title = "Plot of mtcars",
      plotlyOutput("carplot"))
),)

# create server
server <- function(input, output, session) {
  #(1) Create PickerInput Updates
  observeEvent(
    # define pickerinputs to be observed
    c(
      input$vs_pickerinput,
      input$carb_pickerinput,
      input$cyl_pickerinput
    ),
    {
      ## filter the data based on the pickerinputs
      # include an ifelse condition first to check wheter at least one value is choosen in all of the filters.
      mtcars2 <-
        if (!is.null(input$cyl_pickerinput) &
            !is.null(input$vs_pickerinput) &
            !is.null(input$carb_pickerinput)) {
          mtcars %>%
            filter(cyl %in% input$cyl_pickerinput) %>% # filters
            filter(vs %in% input$vs_pickerinput) %>%
            filter(carb %in% input$carb_pickerinput)
        } 
      else{
           mtcars
         }

      ## update PickerInput based on a condition that requires the user to choose at least one input, else reset all filters
      # for cyl 
      if (!is.null(input$cyl_pickerinput)) {
        updatePickerInput(
          session,
          "cyl_pickerinput",
          choices = levels(factor(mtcars$cyl)),
          selected = unique(mtcars2$cyl))
      } else{
      }
      # for carb
      if (!is.null(input$carb_pickerinput)) {
        updatePickerInput(
          session,
          "carb_pickerinput",
          choices = levels(factor(mtcars$carb)),
          selected = unique(mtcars2$carb)
        )
      } 
      # for vs 
      if (!is.null(input$vs_pickerinput)) {
        updatePickerInput(
          session,
          "vs_pickerinput",
          choices = levels(factor(mtcars$vs)),
          selected  = unique(mtcars2$vs)
        )
      } 
    },
    ignoreInit = TRUE,
    ignoreNULL = F
  )
  
  # (2) Create reactive object with filtered data
  # update mtcars table based on filters
  mtcars.reactive <-
    reactive({
      if (!is.null(input$vs_pickerinput))
        # one condition should be enough.
      {
        mtcars %>% # filters
          filter(
            cyl %in% input$cyl_pickerinput &
              vs %in% input$vs_pickerinput &
              carb %in% input$carb_pickerinput
          )
      } else
      {
        mtcars
      }
    })
  
  # (3) create the plot output
  output$carplot <-
    renderPlotly({
      # create plot
      plot <- ggplot(mtcars.reactive()) +
        geom_point(aes(wt, mpg, color = factor(vs)))
      # convert to plotly
      ggplotly(plot)
    })
  
  
  
}

shinyApp(ui, server)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-11-15
    • 2017-11-18
    • 2020-02-05
    • 1970-01-01
    • 2021-11-25
    • 1970-01-01
    • 2018-02-13
    相关资源
    最近更新 更多