R shiny中的多个动态过滤器更新

R shiny中的多个动态过滤器更新,r,shiny,reactive,R,Shiny,Reactive,我希望能够在shiny中拥有UI输入,这些输入根据用户以前的选择进行自我更新。因此,在下面的示例中,预期的行为将是用户从cyl、vs或carb中进行选择,然后 过滤用于创建绘图的数据集mtcars,即用户根据过滤条件和 更新其他过滤器中的剩余输入选项,以便与基于已就位过滤器的剩余选项相对应 以下是我尝试过的: library(shiny) library(dplyr) library(plotly) data("mtcars") # create ui ui <-

我希望能够在shiny中拥有UI输入,这些输入根据用户以前的选择进行自我更新。因此,在下面的示例中,预期的行为将是用户从
cyl
vs
carb
中进行选择,然后

  • 过滤用于创建绘图的数据集
    mtcars
    ,即用户根据过滤条件和
  • 更新其他过滤器中的剩余输入选项,以便与基于已就位过滤器的剩余选项相对应
  • 以下是我尝试过的:

    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)
    
    库(闪亮)
    图书馆(dplyr)
    图书馆(绘本)
    数据(“mtcars”)
    #创建用户界面
    
    ui以下操作不需要层次结构,而是在
    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)
    
    库(闪亮)
    图书馆(dplyr)
    图书馆(绘本)
    数据(“mtcars”)
    #创建用户界面
    ui%
    过滤器(输入$carb\u pickerinput中的carb%
    } 
    否则{
    地铁车辆
    }
    ##根据要求用户至少选择一个输入的条件更新PickerInput,否则重置所有筛选器
    #共青团
    如果(!为.null(输入$cyl\u pickerinput)){
    更新输入(
    一场
    “共青团皮克林普特”,
    选项=级别(系数(mtcars$cyl)),
    选定=唯一(mtcars2$cyl))
    }否则{
    }
    #碳水化合物
    如果(!is.null(输入$carb\u pickerinput)){
    更新输入(
    一场
    “carb_pickerinput”,
    选项=水平(系数(mtcars$carb)),
    选定=唯一(mtcars2$carb)
    )
    } 
    #对于vs
    如果(!is.null(输入$vs_pickerinput)){
    更新输入(
    一场
    “vs_pickerinput”,
    选项=水平(系数(mtcars$vs)),
    选定=唯一(mtcars2$vs)
    )
    } 
    },
    ignoreInit=TRUE,
    ignoreNULL=F
    )
    #(2)使用过滤后的数据创建反应对象
    #基于过滤器更新mtcars表
    mtcars.reactive%#过滤器
    滤器(
    %input$cyl\u pickerinput中的%cyl%&
    输入$vs\u pickerinput中的%vs%&
    carb%在%input$carb\u pickerinput中
    )
    }否则
    {
    地铁车辆
    }
    })
    #(3)创建打印输出
    
    输出$carplot要根据另一个的选定值更改一个拾取输入的选定值,您需要在响应定义的拾取输入更改的反应(
    observeEvent
    )内使用
    updatePickerInput
    。无需使用
    uiOutput
    /
    renderUI
    。您还必须确保逻辑不会互锁:如果用户取消选择所有内容,则可能无法返回,因为mtcars.reactive()将为空,因此所有唯一(…)选择的可能性也将变为空,谢谢你们的评论。我可以算出第一个答案,然后再提供答案。然而,@Waldi关于互锁的第二条评论并非如此。您建议如何解决mtcars为空而取消全部选择的问题?您可能需要在pickerInputs之间保持层次结构:第一个完全空闲,第二个取决于第一个,第三个取决于第一个和第二个。不像你最初希望的那样开放,但更容易理解/处理