在保持位置的同时更新 Shiny DataTable 的行

Posted

技术标签:

【中文标题】在保持位置的同时更新 Shiny DataTable 的行【英文标题】:Update row(s) of a Shiny DataTable while maintaining position 【发布时间】:2016-11-13 22:27:54 【问题描述】:

我正在创建一个闪亮的应用程序,它在屏幕顶部显示 data.frame 信息,在底部显示特定变量统计信息。用户可以通过与DT::datatable 对象交互来导航 data.frame 列。

当用户单击变量时,会显示可以编辑的详细信息。我希望这些信息能够更新并反映在数据表中。我的问题是,当我更新表格时,它会从一开始就被渲染和显示。 如何在编辑后保留数据表的页面和行选择?

这是一个最小的工作示例,它显示了 DT::datatable 中的 mtcars 数据集。我有一些更新字段的控件。请注意,数据表被重新渲染回第一页。

library(shiny)

runApp(shinyApp(

  ui = fluidPage(
    title = "minimal-working-example",
    fluidRow(
      column(3, inputPanel(
        selectInput("field", "Field", choices = names(mtcars)),
        numericInput("value", "Value", 0),
        actionButton("submit", "Submit")
      )),

      column(9,
        DT::dataTableOutput("table")
      )
    )
  ),

  server = function(input, output) 

    v <- reactiveValues(mtcars=mtcars)

    observeEvent(input$submit, 
      v$mtcars[input$field] <- input$value
    )

    output$table <- DT::renderDataTable(
      DT::datatable(
        v$mtcars,
        selection = "single",
        options = list(pageLength = 5))
    )
  
))

会话信息:

Session info --------------------------
 setting  value                       
 version  R version 3.3.0 (2016-05-03)
 system   x86_64, mingw32             
 ui       RStudio (0.99.902)          
 language (EN)                        
 collate  English_United States.1252  
 tz       America/Chicago             
 date     2016-07-11                  

Packages -------------------------------
 package     * version     date       source                        
 DT            0.1.45      2016-02-09 Github (rstudio/DT@a63e9ac)   
 shiny       * 0.13.0.9000 2016-02-08 Github (rstudio/shiny@e871934)

【问题讨论】:

这很棘手,但可行。本质上需要发生的是需要响应地保存表的当前页面,这可以在javascript中使用Shiny.onInputChange来完成。然后,当您渲染表格时,您会回调以在之前的页码处打开它。有机会我会写一个完整的答案。 【参考方案1】:

这可以在 R 内部完成,而无需通过 JS 或类似的东西进入 datatable 的结构。

我们利用从DT 包中获得的各种表状态信息来呈现新更新的datatable,就像以前一样。我们使用的一切都在this DT documentation 中描述。

项目一:选择。您可以通过在数据表的selection 参数中添加selected = ... 来预先选择行。这可以与变量input$table_rows_selected 结合使用以保存先前选择的行并在重新渲染时预先选择该确切行。

第二项:页面。 datatable 包有一个选项 displayStart 指定在呈现表格时应该首先显示哪一行。 Documentation here. 所以,如果每页有 5 行,displayStart = 9 将在第 3 页开始显示。(JavaScript 数组从 0 开始,所以总是减去 1。)这可以与 input$table_rows_current 结合使用,它是当前可见的行号。如果我们存储第一个条目(减 1),我们就知道从哪里开始显示。

下面的完整代码示例:

library(shiny)

runApp(shinyApp(

  ui = fluidPage(
    title = "minimal-working-example",
    fluidRow(
      column(3, inputPanel(
        selectInput("field", "Field", choices = names(mtcars)),
        numericInput("value", "Value", 0),
        actionButton("submit", "Submit")
      )),

      column(9,
        DT::dataTableOutput("table")
      )
    )
  ),

  server = function(input, output) 

    v <- reactiveValues(mtcars=mtcars)
    previousSelection <- NULL
    previousPage <- NULL

    observeEvent(input$submit, 
      previousSelection <<- input$table_rows_selected
      previousPage <<- input$table_rows_current[1] - 1

      v$mtcars[input$field] <- input$value
    )

    output$table <- DT::renderDataTable(
      DT::datatable(
        v$mtcars,
        selection = list(mode = "single", target = "row", selected = previousSelection),
        options = list(pageLength = 5, displayStart = previousPage))
    )
  
))

【讨论】:

感谢您的详细回复。我偶然发现了您在解决方案中突出显示的 DT API 中的功能。我将奖励你赏金,因为你回答了我提出的问题。但是,在实施此解决方案时,我发现它在对表格进行排序时会中断。您对如何解决这方面有任何想法吗? @Zelazny7 有datatable 选项order,如果设置datatable 选项stateSave = TRUE,可以通过input$table_state$order 检索当前表顺序。但是该集合是在displayStart 之后排序的,因此这将导致错误的页面选择。我将使用排序(临时)对数据集进行排序并检索将显示previousPage 行号的实际页面(排序后的行号)。然后我会使用这个(模数页面长度)作为你的previousPage arg。如果排序列是已被覆盖的列,则加上例外规则。

以上是关于在保持位置的同时更新 Shiny DataTable 的行的主要内容,如果未能解决你的问题,请参考以下文章

R Shiny CSS:删除特定行之间的空间,同时保持所有其他间距不变

更新后如何连续刷新datagridview

如何在R / Shiny中将相机方向固定在交互式3D绘图中

XCode:无缝保持位置更新

更新 mongoDB 中的单个项目,同时保持其余项目相同

如何在保持圆周围位置的同时缩放多边形