【问题标题】:How to access/remember unchecked values in Shiny?如何访问/记住 Shiny 中未检查的值?
【发布时间】:2017-06-11 09:55:18
【问题描述】:

我在 R 中摆弄一个闪亮的应用程序。该应用程序有

  • 一个选择列表输入A(主要组)与可能的值A,B 和/或 C
  • 一组复选框输入b(子组),它们是 由 Input A 列表中的选择动态填充:chkb a 和 chkb b 代表 A,c,d 代表 B,和/或 e,f 代表 C
  • 带有映射的数据框df

它是这样的:

我的问题是 Input b 忘记了之前未选中的复选框。所以 - 关于屏幕录制 - 值 b 必须在列表 Input A 中的每个新选择中再次取消选中。

问:如何更改以下代码,以便

  1. 输入 A 中的新添加列表项仍会在 输入 b自动检查,并且
  2. 之前输入 b未选中的值被记住;至少只要 Input A 中的相应类别没有被取消选择

代码如下:

library(shiny)
df <- data.frame(
  a = rep(LETTERS[1:3], each = 2), 
  b = letters[1:6]
)

ui <- fluidPage(
  column(6, selectInput("selectinput", "Input A", levels(df$a), multiple = T)),
  column(6, checkboxGroupInput("checkinput", "Input b", NULL))
)

server <- function(input, output, session) {
  observe({
    allPossibleB <- df$b[df$a %in% input$selectinput]
    updateCheckboxGroupInput(session, 
      "checkinput", "Input b",
      choices = allPossibleB,
      selected = setdiff(allPossibleB, NULL), # <=== previously unchecked instead NULL?
      inline = TRUE
    )
  })
}

shinyApp(ui, server)

我尝试了几件事,但我认为不值得一提,因为我对 Shiny 和基本概念没有太多经验。也许有一种简单的方法不仅可以访问输入小部件的检查值吗?

提前感谢任何提示和帮助!

【问题讨论】:

    标签: r shiny


    【解决方案1】:

    您可以使用reactiveValues() 来记住检查的值。

    我对命名列表进行了编辑以存储选中框的信息。如果您打算按字母顺序选择input A,这是必要的,..

    checked <- as.list(rep(T, length(df$b)))
    names(checked) <- df$b
    

    在应用程序内部,您必须使用 isolate(),因为由于某种原因,input$selectinput 的更新速度比 input$checkinput 快,这会导致选择逻辑出现问题。所以我们只想在input$checkinput 有变化时更新。是的,我使用 for 循环来更新(未)检查值的列表:)。

      global <- reactiveValues(checked = checked)
    
      observe({
        input$checkinput
        isolate({
          if(!is.null(input$checkinput)){
            possible <- as.character(df$b[df$a %in% input$selectinput])
            for(nr in 1:length(possible)){
              global$checked[[possible[nr]]] <- (possible %in% input$checkinput)[nr]
            }
          }
        })
      })
    

    完整的应用程序是:

    library(shiny)
    
    df <- data.frame(
      a = rep(LETTERS[1:3], each = 2), 
      b = letters[1:6]
    )
    
    checked <- as.list(rep(T, length(df$b)))
    names(checked) <- df$b
    
    
    ui <- fluidPage(
      column(6, selectInput("selectinput", "Input A", levels(df$a), multiple = T)),
      column(6, checkboxGroupInput("checkinput", "Input b", NULL))
    )
    
    server <- function(input, output, session) {
      global <- reactiveValues(checked = checked)
    
      observe({
        input$checkinput
        isolate({
          if(!is.null(input$checkinput)){
            possible <- as.character(df$b[df$a %in% input$selectinput])
            for(nr in 1:length(possible)){
              global$checked[[possible[nr]]] <- (possible %in% input$checkinput)[nr]
            }
          }
        })
      })
    
      observe({
        allPossibleB <- df$b[df$a %in% input$selectinput]
        updateCheckboxGroupInput(session, 
                                 "checkinput", "Input b",
                                 choices = allPossibleB,
                                 selected = df$b[unlist(global$checked)], # <=== previously unchecked instead NULL?
                                 inline = TRUE
        )
      })
    }
    
    shinyApp(ui, server)
    

    【讨论】:

    • 这正是我刚才所说的。大声笑,不得不跑去和 gf 吃饭,还没有发布代码。
    • 实际上让我从想法到代码有点花样,不像预期的那么简单,...我也意识到它只有在您按字母顺序选择input A 时才有效,.. .otherwise它分配不同。但它显示了总体思路足够好,...
    • @BigDataScientist 太好了,这行得通 - 谢谢。 observe({ 和`isolate({` 之间的input$checkinput 有什么作用?似乎很关键,但我不明白那里的意思。:-?
    • @BigDataScientist 最后但并非最不重要的一点是:选择列表是个人喜好问题,对吧?矢量爱好者可能想在第一次观察中将其更改为global &lt;- reactiveValues(checked = setNames(rep(F, length(df$b)), df$b))if(!is.null(input$checkinput)){possible &lt;- df$b[df$a %in% input$selectinput];global$checked[possible] &lt;- possible %in% input$checkinput}
    • @lukeA:见句子“所以我们只想在input$checkinput有变化时更新。”这就是我对输入和隔离所做的事情,...您也可以改用observeEvent()。命名向量当然也可以工作,...实际上是我认为的更好的选择。后续代码看起来不错,但如果没有测试就很难说:)
    【解决方案2】:
    column(6, updateCheckboxGroupInput("checkinput", "Input b", NULL, selected = input$checkinput))
    

    或者如果您有“无”选项:

    column(6, updateCheckboxGroupInput("checkinput", "Input b", NULL, selected = if(is.null(input$checkinput)){"none"}else{input$checkinput}))
    

    为了将它们与 A、B、C 分组,您可以创建响应值来存储每个组的选择,并使用观察者来更改输入中的活动组。我会尽快发布代码 这是承诺的代码,我的 BigData 回答的版本

    library(shiny)
    df <- data.frame(
    a = rep(LETTERS[1:3], each = 2), 
    b = letters[1:6]
    )
    
    ui <- fluidPage(
     column(6, selectInput("selectinput", "Input A", levels(df$a), multiple =  TRUE)),
     column(6, checkboxGroupInput("checkinput", "Input b", NULL))
     )
    
    server <- function(input, output, session) {
    checkin <- reactiveValues(A = NULL,B = NULL, C = NULL,puts = NULL)
    observeEvent(input$selectinput,{
      if("A" %in% input$selectinput){
        checkin$A <- input$checkinput[which(input$checkinput %in% df$b[which(df$a[df$b] == "A")])]
      }
      if("B" %in% input$selectinput){
        checkin$B <- input$checkinput[which(input$checkinput %in% df$b[which(df$a[df$b] == "B")])]
      }
      if("C" %in% input$selectinput){
        checkin$C <- input$checkinput[which(input$checkinput %in% df$b[which(df$a[df$b] == "C")])]
      }
        checkin$puts <- c(if(!is.null(checkin$A)){checkin$A},if(!is.null(checkin$B)){checkin$B},if(!is.null(checkin$C)){checkin$C})
      })
    observe({
     allPossibleB <- df$b[df$a %in% input$selectinput]
     updateCheckboxGroupInput(session, 
                             "checkinput", "Input b",
                             choices = allPossibleB,
                             selected = checkin$puts ,
                             inline = TRUE
     )
     })
     }
    
     shinyApp(ui, server)
    

    【讨论】:

    • 感谢您的意见。使用selected = input$checkinput 时行为没有改变,还是我弄错了?我也玩过 reactiveValues。但是,没有一个选项同时满足条件 1.(自动检查新的)和 2.(记住旧的)。
    • 抱歉,您应该在updateCheckboxGroupInput中使用了 selected = input$checkinput
    • 它似乎仍然不能解决问题,但是在 reactiveValues 对象中存储一种查找表是个好主意。但我想如果不花几个小时我永远不会让它工作 - 它不是太直观......
    • 感谢您的建议。结果与只是做checkin &lt;- reactiveValues(puts = NULL); observeEvent(input$selectinput, checkin$puts &lt;- input$checkinput) 不一样吗?我以前有过(记住选择的要点),但是这不会自动选择新的复选框,这就是问题所在。 checked 字典通过在默认情况下将所有内容自动设置为“选中”来解决这个问题。至少在最初。
    • 更改reactiveValues(A=c("a","b")... 也可以实现这一点。它是其他六个中的六个,就像 R 的大多数事情一样。我没有将我的答案的附录作为更好的答案发布,就像如果我留给我自己的设备我会做的那样。本质上,在组中设置值状态的能力是两者之间的唯一区别。您可以将一组设置为关闭,一组设置为打开,另一组设置为打开。仅使用 input$selectinput 并不能做到这一点
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-18
    • 1970-01-01
    • 2015-05-28
    • 2022-06-22
    相关资源
    最近更新 更多