【问题标题】:selectizeInput filter all other menus based on the selection from another menu (every time a selection is made)selectizeInput 根据从另一个菜单中的选择过滤所有其他菜单(每次进行选择时)
【发布时间】:2019-01-08 01:50:50
【问题描述】:

我的数据类似于 Orange 数据集,其中有可能包含重复值的列,但是,每一行都是唯一的。
我的代码:

library(shiny)
library(DT)
library(data.table)

d <- copy(Orange)
col_names <- names(Orange)
user_friendly_names <- c('TreeNumber', 'TreeAge', 'Circumference')


ui <- fluidPage(  
  sidebarLayout(
    sidebarPanel(
      h3("Filters:"),
      uiOutput("filters"),

      # Plot button
      fluidRow(column(2, align = "right",
                      actionButton("plot_graph_button", "Plot")))
    ),
    mainPanel(tableOutput("summary"))
  )
)

server <- function(input, output) {
  #### Create the filter lists for UI ####
  output$filters <- renderUI({
    if(is.null(col_names)) return(NULL)
    lapply(1:length(col_names), function(i) {
      col <- paste0(col_names[i])
      alias <- user_friendly_names[i]
      # Populate input with unique values from column
      selectizeInput(inputId = alias, label = paste(alias,':'),
                     choices = c('All', unique(d[[col]])), selected = 'All', multiple = T)
    })
  })

  output$summary <- renderTable({
    # Do not show a plot when the page first loads
    # Wait until the user clicks "Plot" button
    if (input$plot_graph_button == 0){
      return()
    }
    # Update code below everytime the "Plot" button is clicked
    input$plot_graph_button

    isolate({
      # Fresh copy of the full data set every time "Plot" button is clicked
      d <- copy(Orange)

      # Filter data based on UI
      for(f in 1:length(col_names)){
        print(paste("This is loop # ", f))

        if(eval(parse(text = paste0('is.null(input$',user_friendly_names[f],')')))){
          # If the user deleted "All" but failed to pick anything else default to "All" - do not filter
          break
        }else{
          if(eval(parse(text = paste0('input$',user_friendly_names[f]))) != "All"){
            print("FALSE -- Input is not == ALL")

            d <- d[d[[col_names[f]]] == unlist(eval(parse(text = paste0('input$',user_friendly_names[f])))), ]
          }else{
            print("TRUE -- Input is defaulted to ALL")
          }
        }
      }
      final_summary_table <<- d
    })
  })
}

shinyApp(ui = ui, server = server)

我的问题是这些列表能够选择多个输入(我想要的),但是,我想最初在所有菜单中显示所有可用的选项(它目前这样做)但我需要改变的是我需要让它根据提供的唯一行数据集在做出选择后立即开始过滤其他列表(无论用户首先进入哪个列表)。
因此,如果用户转到第二个列表并选择 1004 的树龄,则 TreeNumber 菜单应更改为 c(1, 2, 3, 4, 5) - 在这种情况下没有变化,但 Circumference 菜单应更改为 c(115, 156, 108, 167, 125),然后如果他们选择TreeAge,现在菜单会被TreeAge 和TreeNumber 等过滤掉。

现在代码的工作方式是在您单击“绘图”之前它不会过滤任何内容,因此用户可能认为搜索会产生一堆结果,而实际上可能不存在组合。

这是一个很好的搜索示例,您可能期望它会产生很多结果,但它只产生 1 行:

请注意:如果您不删除“全部”,即使您选择了其他选项,它也会返回“全部”,这是我计划单独解决的代码中的一个缺陷以及一些其他小调整。

我还想提一下,我发现这篇帖子 Filter one selectInput based on selection from another selectInput? 与我的类似,但是,他们正在以自上而下的方式处理菜单,而我的将更加灵活地决定用户转到哪个菜单首先(我的也允许多选)。

【问题讨论】:

    标签: r shiny


    【解决方案1】:
    server <- function(input, output, session) {
    
      output$filters <- renderUI({
        # ...
      })
    
      lapply(seq_along(d), function(i) {
        observeEvent(input[[user_friendly_names[i]]], {
          for (j in seq_along(d)[-i]) {
            choices <- if ("All" %in% input[[user_friendly_names[i]]]) 
              unique(d[[j]]) else 
              unique(d[[j]][d[[i]] %in% input[[user_friendly_names[i]]]])
            choices <- c("All", choices)
            selected <- intersect(choices, input[[user_friendly_names[j]]])
            updateSelectInput(session = session, inputId = user_friendly_names[j], 
                              choices = choices, selected = selected)
          }
        })
      })
    
      observeEvent(input$plot_graph_button, {
        for (j in seq_along(d)) {
          updateSelectInput(session = session, inputId = user_friendly_names[j], 
                            choices = c("All", unique(d[[j]])), selected = "All")
        }
      })
    
      output$summary <- renderTable({
         # ...          
      })
    }
    

    【讨论】:

    • 我发现的唯一问题是,如果用户在单击一次绘图后重新选择输入,它会继续从过滤列表中过滤,而不是获得一个干净的副本并重新开始。
    • "All" 现在立即消失,因为它不在数据集中作为选项。有没有办法保留它作为一种选择?
    • 它已关闭,但现在当我看到当您单击“绘图”时,它会立即删除用户选择的内容。
    • 抱歉造成误会。我以为你的意思是点击“绘图”应该给出“一个干净的副本并重新开始”
    猜你喜欢
    • 1970-01-01
    • 2013-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-31
    • 1970-01-01
    相关资源
    最近更新 更多