【问题标题】:How to update row-wise filter in Shiny datatable如何更新闪亮数据表中的逐行过滤器
【发布时间】:2022-01-05 13:08:54
【问题描述】:

我正在尝试根据我们在每一行从用户收到的输入更新数据表中的逐行过滤器,以便只能选择后续输入中的相关值。

我尝试使用以下代码复制我的场景,如果用户选择“setosa”作为“spieces_selector”,则“New_Data_selector”中应该只出现“1-50”值。同样,如果用户在第二行选择“versicolor”,那么对于第二行,“New_Data_selector”的值应该是“51-100”。

非常感谢您对此的帮助。

library(shiny)
library(DT)

iris$New_Data <- c(1:150)

ui <- fluidPage(
  title = 'Selectinput column in a table',
  h3("Source:", tags$a("Yihui Xie", href = "https://yihui.shinyapps.io/DT-radio/")),
  numericInput('num', "enter a number", value = 5, min = 1, max = 10, step = 1),
  DT::dataTableOutput('foo'),
  verbatimTextOutput('sel'),
  actionButton(
    "saveBtn",
    "Submit Request",
    style = "color: #fff; background-color: #282364;
                                     border-color: #2e6da4",
    class = "btn btn-primary"
  )
)

server <- function(input, output, session) {
  data <- reactive({
    df <- head(iris, input$num)
    
    for (i in 1:nrow(df)) {
      df$species_selector[i] <- as.character(selectInput(paste0("sel1", i),
                                                         "",
                                                         choices = unique(iris$Species),
                                                         width = "100px"))
      
      df$New_Data_selector[i] <- as.character(selectInput(paste0("sel2", i),
                                                         "",
                                                         choices = unique(iris$New_Data),
                                                         width = "100px"))
    }
    df
  })
  
  output$foo = DT::renderDataTable(
    data(), escape = FALSE, selection = 'none', server = FALSE,
    options = list(dom = 't', paging = FALSE, ordering = FALSE),
    callback = JS("table.rows().every(function(i, tab, row) {
        var $this = $(this.node());
        $this.attr('id', this.data()[0]);
        $this.addClass('shiny-input-container');
      });
      Shiny.unbindAll(table.table().node());
      Shiny.bindAll(table.table().node());")
  )
  output$sel = renderPrint({
    str(sapply(1:nrow(data()), function(i) input[[paste0("sel", i)]]))
  })
  
  observeEvent(input$saveBtn, {
    
    Test_Data <- sapply(1:nrow(data()), function(i) input[[paste0("sel", i)]])
    Test_Data <- as.data.frame(Test_Data)
    print(Test_Data)})
  
}

shinyApp(ui, server)

【问题讨论】:

  • 我认为应该有类似的方式:stackoverflow.com/questions/42745432/…。但是不知道如何在闪亮中实现它
  • @ismirsehregal:这对使用 sapply 更新值非常有帮助,我发现了您提供的多种解决方案,但它们都与更新第二个下拉列表无关,如果我们有超过 5 个数据表中的下拉列表,什么是理想的解决方案,如果您可以通过一些示例分享,将非常感谢您的帮助。你是希望!!!
  • @ismirsehregal 别担心,我们将等待您的指导......

标签: r shiny datatable


【解决方案1】:

以下工作(基于我的earlier answer) - 但它很慢。需要进一步调查。

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

myIris <- copy(iris)
setDT(myIris)

myIris[, Index := seq_len(.N)]

selectInputIDs_A <- paste0("sel_A", myIris$Index)
selectInputIDs_B <- paste0("sel_B", myIris$Index)

myIris[, selectInputs_A := sapply(selectInputIDs_A, function(x){as.character(selectInput(inputId = x, label = "", choices = unique(myIris$Species), selected = "setosa"))})]
myIris[, selectInputs_B := sapply(selectInputIDs_B, function(x){as.character(selectInput(inputId = x, label = "", choices = unique(myIris[Species == "setosa"]$Index), selected = "setosa"))})]

initTbl <- copy(myIris)

ui <- fluidPage(
  DT::dataTableOutput(outputId = 'my_table')
)

server <- function(input, output, session) {
  
  displayTbl <- reactive({
    myIris[, selectInputs_A := sapply(selectInputIDs_A, function(x){as.character(selectInput(inputId = x, label = "", choices = unique(Species), selected = input[[x]]))}),]
    myIris[, selectInputs_B := sapply(seq_along(selectInputs_B), function(x){as.character(selectInput(inputId = selectInputIDs_B[x], label = "", choices = unique(myIris[Species == input[[selectInputIDs_A[x]]]]$Index), selected = input[[selectInputIDs_A[x]]]))})]
  })
  
  output$my_table = DT::renderDataTable({
    DT::datatable(
      initTbl, escape = FALSE, selection = 'none', rownames = FALSE,
      options = list(paging = FALSE, ordering = FALSE, scrollx = TRUE, dom = "t",
                     preDrawCallback = JS('function() { Shiny.unbindAll(this.api().table().node()); }'),
                     drawCallback = JS('function() { Shiny.bindAll(this.api().table().node()); } ')
      )
    )
  }, server = TRUE)
  
  my_table_proxy <- dataTableProxy(outputId = "my_table", session = session)
  
  observeEvent({sapply(selectInputIDs_A, function(x){input[[x]]})}, {
    replaceData(proxy = my_table_proxy, data = displayTbl(), rownames = FALSE) # must repeat rownames = FALSE see ?replaceData and ?dataTableAjax
  }, ignoreInit = TRUE)
  
}

shinyApp(ui = ui, server = server)

【讨论】:

  • 感谢您的努力,但是看起来这可能真的很慢,因为我们正在初始化并为所有数据点分配 ID。当你有大数据时,这可能会很慢。(虽然我还没有测试过。)但在提到的例子中,SO希望动态选择所需的行数,并希望创建动态 ID 以避免覆盖因此我们可能需要考虑在服务器内部编写初始数据帧代码以使其更快。你有什么意见?
  • 是否有其他解决方案,因为它需要几秒钟来更新看起来不太好的表格。
  • 另外,在这种情况下,结果将被覆盖,但是我们确实希望将所有更改存储为单独的条目
  • 我猜你需要一个 JS 解决方案。关于动态编号。我认为最好首先保持简单。这是解决下拉问题后要处理的事情。
  • 那是正确的,关于动态行数我们已经实现了相同。不幸的是,无法在此处共享完整的代码,该代码根据要求可以完美运行。我们只是在努力更新表中的过滤器,因为每行中有 4 个不同的过滤器,并且必须根据第一个过滤器输入的选择进行更新......我很惊讶在闪亮的数据表中我们没有任何解决方案。
猜你喜欢
  • 2019-07-04
  • 2018-10-04
  • 2021-02-13
  • 2017-05-05
  • 2020-10-30
  • 1970-01-01
  • 1970-01-01
  • 2020-01-12
  • 2017-11-18
相关资源
最近更新 更多