多个反应过滤器和更新选择输入的问题 - 奇怪的行为

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多个反应过滤器和更新选择输入的问题 - 奇怪的行为相关的知识,希望对你有一定的参考价值。

我正在努力解决连续传递多个过滤器的问题,有时结果不符合预期。在下面的例子中,有7只鹿,2只熊,1只美洲狮,1只海狸,1只臭鼬,1只驼鹿和3只麋鹿。当您选择一个或多个物种时,有时通过过滤器的行数与应该的数量不同。

例如。当我选择Bear,Beaver和Cougar时,它应该产生4行数据集,但是,在显示行数的textoutput中,显示nrow = 3。添加更多选择有时会通过剩余的过滤器,有时不会。有时候在选择Deer时,你会期望7行数据,只传递3行。

看看下面的可重现的例子。

服务器:

library(shiny)
library(dplyr)

shinyServer(function(input, output, session, clientData) {


  Accident.Date <- as.Date(c("2018-06-04", "2018-06-05", "2018-06-06", "2018-06-07", "2018-06-08", "2018-06-09", "2018-06-10", "2018-06-11", "2018-06-12", "2018-06-13", "2018-06-14", "2018-06-15", "2018-06-16", "2018-06-17", "2018-06-18", "2018-07-18"))
  Time.of.Kill <- as.character(c("DAWN", "DAY", "DARK", "UNKNOWN", "DUSK", "DAY", "DAY", "DAWN", "DAY", "DARK", "UNKNOWN", "DUSK", "DARK", "DUSK", "DARK", "DAY"))
  Sex <- as.character(c("MALE", "MALE", "FEMALE", "MALE", "FEMALE", "FEMALE", "MALE", "MALE", "FEMALE", "FEMALE", "MALE", "FEMALE", "MALE", "FEMALE", "FEMALE", "FEMALE"))
  Age <- as.character(c("ADULT", "YOUNG", "UNKNOWN", "ADULT", "UNKNOWN", "ADULT", "YOUNG", "YOUNG", "ADULT", "ADULT", "ADULT", "YOUNG", "ADULT", "YOUNG", "YOUNG", "ADULT"))
  Species <- as.character(c("Deer", "Deer", "Deer", "Bear", "Deer", "Cougar", "Bear", "Beaver", "Deer", "Skunk", "Moose", "Deer", "Deer", "Elk", "Elk", "Elk"))
  Year <- as.numeric(c("0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"))


  data <- data.frame(Accident.Date, Time.of.Kill, Sex, Age, Species, stringsAsFactors = FALSE)
  data <- data %>% mutate(Data.Set = "Current")

  #A set of reactive filters. Only data that has passed all filters is passed to the map, graph, datatable etc. **Order goes datacheck > yearcheck > speccheck > sexcheck > timecheck > agecheck > indaterange


  bindata <- reactive({
    filter(data, Data.Set %in% input$datacheck)
  })

  yrdata <- reactive({
    filter(bindata(), Year %in% input$yearcheck)
  })

  specdata <- reactive({
    subset(yrdata(), Species %in% input$speccheck)
  })

  sexdata <- reactive({
    filter(specdata(), Sex %in% input$sexcheck)
  })

  timedata <- reactive({
    filter(sexdata(), Time.of.Kill %in% input$timecheck)
  })

  agedata <- reactive({
    filter(timedata(), Age %in% input$agecheck)
  })

  #Does the date range filter. Selects min and max from the two inputs of the observed indaterange filter.

  data1 <- reactive({ filter(agedata(),
                             Accident.Date >= input$inDateRange[[1]],
                             Accident.Date <= input$inDateRange[[2]])
  })

  #If statement for choosing between current and historical datasets. If current is selected, year is set to 0 and the selection box is hidden.

  observe({ if (input$datacheck == 'Current')
    updateSelectInput(session, "yearcheck", choices = c("0"), selected = c("0"))
    else
      updateSelectizeInput(session, "yearcheck", choices = sort(unique(bindata()$Year), decreasing = TRUE), server=TRUE)

  })

  observe({

    req((input$datacheck == 'Historical'))

    updateSelectizeInput(session, "speccheck", choices = sort(unique(yrdata()$Species)), server=TRUE)

  })


  #Creates the observed Species

  observeEvent(input$yearcheck, {

    x  <- input$yearcheck
    if (is.null(x))
      x <- character(0)

    updateSelectizeInput(session, "speccheck", choices = sort(unique(yrdata()$Species)), server=TRUE)

  })


  #Creates the observed Sex

  observeEvent(input$speccheck, {

    x  <- input$speccheck
    if (is.null(x))
      x <- character(0)

    updateCheckboxGroupInput(session, inputId = "sexcheck",
                             choices = unique(specdata()$Sex),
                             selected = unique(specdata()$Sex),
                             inline = TRUE)
  })


  #Creates the observed Time

  observeEvent(input$sexcheck,{

    x  <- input$sexcheck
    if (is.null(x))
      x <- character(0)

    updateCheckboxGroupInput(session, inputId = "timecheck",
                             choices = unique(sexdata()$Time.of.Kill),
                             selected = unique(sexdata()$Time.of.Kill),
                             inline = TRUE)
  })

  #Creates the observed Age

  observeEvent(input$timecheck,{

    x  <- input$timecheck
    if (is.null(x))
      x <- character(0)

    updateCheckboxGroupInput(session, inputId = "agecheck",
                             choices = unique(timedata()$Age),
                             selected = unique(timedata()$Age),
                             inline = TRUE)
  })

  #Creates the observed dates and suppresses warnings from the min max

  observeEvent(input$agecheck, {

    x  <- input$agecheck
    if (is.null(x))
      x <- character(0)

    #And update the date range values to match those of the dataset

    updateDateRangeInput(
      session = session,
      inputId = "inDateRange",
      start = min(suppressWarnings(agedata()$Accident.Date)),
      end = max(suppressWarnings(agedata()$Accident.Date))
    )
  })


  output$txt <-  renderText({nrow(data1())})


  })

洋葱:

navbarPage("Test", id="nav",

           tabPanel("Map",

                        absolutePanel(id = "controls", class = "panel panel-default", fixed = TRUE,
                                      draggable = FALSE, top = 200, left = 5, right = "auto", bottom = "auto",
                                      width = "auto", height = "auto",


                                      radioButtons("datacheck", label = tags$div( html("<b>Dataset</b>")),
                                                   choices = c("Current" = "Current", "Historical" = "Historical"),
                                                   selected = c("Current"), inline = TRUE),



                                      conditionalPanel(condition = "input.datacheck != 'Current'",

                                                       #Only displays yearcheck for historical as there is no year column on current dataset. Current dataset has had all year values set to 0.             

                                                       selectizeInput("yearcheck", label = "Select Year (Only Available for Historical)", choices = NULL, options = list(placeholder = 'Select Year:', maxOptions = 40, maxItems = 40))),

                                      selectizeInput("speccheck", h3("Select Species:"), choices = NULL, options = list(placeholder = 'Select Species: (Max 12) ', maxOptions = 36, maxItems = 12)),


                                      conditionalPanel(condition = "input.speccheck >= '1'",
                                                       dateRangeInput("inDateRange", "Date range input:"),

                                                       checkboxGroupInput("sexcheck", label = tags$div( HTML("<b>Sex</b><br>"))),

                                                       checkboxGroupInput("agecheck", label = tags$div( HTML("<b>Age</b><br>"))),

                                                       checkboxGroupInput("timecheck", label = tags$div( HTML("<b>Time of Accident</b><br>")))
                                      ),
                                      verbatimTextOutput("txt")


)))

任何帮助,将不胜感激。我一直在这个问题上摸不着头脑。

答案

该问题与您更新复选框的方式有关。使用你的代码:选择第一个BEAR,输出看起来很棒,是的,但如果添加BEAVER没有任何反应。为什么?因为当你的过滤器通过

   timedata <- reactive({
        filter(sexdata(),(Time.of.Kill %in% input$timecheck))
      })

因为BEAR没有DAWN作为Time.of.Kill,BEAVER没有通过这个过滤器。

这是我的解决方案:

shinyServer(function(input, output, session, clientData) {


  Accident.Date <- as.Date(c("2018-06-04", "2018-06-05", "2018-06-06", "2018-06-07", "2018-06-08", "2018-06-09", "2018-06-10", "2018-06-11", "2018-06-12", "2018-06-13", "2018-06-14", "2018-06-15", "2018-06-16", "2018-06-17", "2018-06-18", "2018-07-18"))
  Time.of.Kill <- as.character(c("DAWN", "DAY", "DARK", "UNKNOWN", "DUSK", "DAY", "DAY", "DAWN", "DAY", "DARK", "UNKNOWN", "DUSK", "DARK", "DUSK", "DARK", "DAY"))
  Sex <- as.character(c("MALE", "MALE", "FEMALE", "MALE", "FEMALE", "FEMALE", "MALE", "MALE", "FEMALE", "FEMALE", "MALE", "FEMALE", "MALE", "FEMALE", "FEMALE", "FEMALE"))
  Age <- as.character(c("ADULT", "YOUNG", "UNKNOWN", "ADULT", "UNKNOWN", "ADULT", "YOUNG", "YOUNG", "ADULT", "ADULT", "ADULT", "YOUNG", "ADULT", "YOUNG", "YOUNG", "ADULT"))
  Species <- as.character(c("Deer", "Deer", "Deer", "Bear", "Deer", "Cougar", "Bear", "Beaver", "Deer", "Skunk", "Moose", "Deer", "Deer", "Elk", "Elk", "Elk"))
  Year <- as.numeric(c("0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"))


  data <- data.frame(Accident.Date, Time.of.Kill, Sex, Age, Species, stringsAsFactors = FALSE)
  data <- data %>% mutate(Data.Set = "Current")

  #A set of reactive filters. Only data that has passed all filters is passed to the map, graph, datatable etc. **Order goes datacheck > yearcheck > speccheck > sexcheck > timecheck > agecheck > indaterange


  bindata <- reactive({
    filter(data, Data.Set %in% input$datacheck)
  })

  yrdata <- reactive({
    filter(bindata(), Year %in% input$yearcheck)
  })

  specdata <- reactive({
    sub <- subset(yrdata(), Species %in% input$speccheck)

  })

  sexdata <- reactive({
    filter(specdata(), Sex %in% input$sexcheck)
  })

  timedata <- reactive({
    filter(sexdata(),(Time.of.Kill %in% input$timecheck))
  })

  agedata <- reactive({
    filter(timedata(), Age %in% input$agecheck)
  })

  #Does the date range filter. Selects min and max from the two inputs of the observed indaterange filter.

  data1 <- reactive({ filter(agedata(),
                             Accident.Date >= input$inDateRange[[1]],
                             Accident.Date <= input$inDateRange[[2]])
  })

  #If statement for choosing between current and historical datasets. If current is selected, year is set to 0 and the selection box is hidden.

  observe({ if (input$datacheck == 'Current')
    updateSelectInput(session, "yearcheck", choices = c("0"), selected = c("0"))
    else
      updateSelectizeInput(session, "yearcheck", choices = sort(unique(bindata()$Year), decreasing = TRUE), server=TRUE)

  })

  observe({

    req((input$datacheck == 'Historical'))

    updateSelectizeInput(session, "speccheck", choices = sort(unique(yrdata()$Species)), server=TRUE)

  })


  #Creates the observed Species

  observeEvent(input$yearcheck, {

    x  <- input$yearcheck
    if (is.null(x))
      x <- character(0)

    updateSelectizeInput(session, "speccheck", choices = sort(unique(yrdata()$Species)), server=TRUE)

  })


  #Creates the observed Sex

  observeEvent(input$speccheck, {

    x  <- input$speccheck
    if (is.null(x))
      x <- character(0)

    updateCheckboxGroupInput(session, inputId = "sexcheck",
                             choices = unique(bindata()$Sex),
                             selected = unique(bindata()$Sex),
                             inline = TRUE)
  })


  #Creates the observed Time

  observeEvent(input$sexcheck,{

    x  <- input$sexcheck
    if (is.null(x))
      x <- character(0)

    updateCheckboxGroupInput(session, inputId = "timecheck",
                             choices = unique(bindata()$Time.of.Kill),
                             selected = unique(bindata()$Time.of.Kill),
                             inline = TRUE)
  })

  #Creates the observed Age

  observeEvent(input$timecheck,{

    x  <- input$timecheck
    if (is.null(x))
      x <- character(0)

    updateCheckboxGroupInput(session, inputId = "agecheck",
                             choices = unique(bindata()$Age),
                             selected = unique(bindata()$Age),
                             inline = TRUE)
  })

  #Creates the observed dates and suppresses warnings from the min max

  observeEvent(input$agecheck, {

    x  <- input$agecheck
    if (is.null(x))
      x <- character(0)

    #And update the date range values to match those of the dataset

    updateDateRangeInput(
      session = session,
      inputId = "inDateRange",
      start = min(suppressWarnings(bindata()$Accident.Date)),
      end = max(suppressWarnings(bindata()$Accident.Date))
    )
  })


  output$txt <-  renderText({nrow(data1())})


})

我唯一的改变是使用bindata()更新复选框,这将强制所有出现,所以没有动物被预过滤。因此,我的解决方案是放弃创建动态检查并从您第一次选择动物时显示所有动态检查。

另一答案

解决方案相当明显。通过将更新输入放在observe()中而不是在它们改变时尝试观察上游输入来获得期望的效果。这适用于所有上游更新输入。

  observe({

    x  <- input$agecheck
    if (is.null(x))
      x <- character(0)

    #And update the date range values to match those of the dataset

    updateDateRangeInput(
      session = session,
      inputId = "inDateRange",
      start = suppressWarnings(min(agedata()$Accident.Date)),
      end = suppressWarnings(max(agedata()$Accident.Date))
    )
  })

这解决了这个问题!

以上是关于多个反应过滤器和更新选择输入的问题 - 奇怪的行为的主要内容,如果未能解决你的问题,请参考以下文章

闪亮的动态/条件过滤选择多个输入(selectizeInput,多个= TRUE)

如何在反应原生中过滤多个选择下拉字段中的数组值

NSFetchedResultsController 对更新没有反应

闪亮的反应式下拉菜单行为不端(带有数字输入)

R闪亮过滤反应输入

多个复选框过滤反应状态