R Shiny - 使用列排序禁用数据表中的特定行
Posted
技术标签:
【中文标题】R Shiny - 使用列排序禁用数据表中的特定行【英文标题】:R Shiny - Disabling specific rows in a datatable with column sorting 【发布时间】:2019-12-21 15:13:03 【问题描述】:下面的应用程序包含一个启用行选择的iris
数据集的数据表。我想专门禁用前 3 行的选择。我可以使用here 发布的解决方案来做到这一点。当表在应用启动时初始化时,该解决方案工作正常:
但是,当您对列上的行进行排序时,例如在Species
上按降序排列,它会禁用观察值 101、102 和 103,因为它们现在是表的前 3 行,因为排序结果:
我猜这是因为 rowCallback
是 displayIndex
来禁用行。因此,在启动时,displayIndex
0、1 和 2 分别对应于 iris 数据集中的观察值 1、2 和 3,并且行回调禁用它们的行选择,因为这些行的 indices.indexOf(displayIndex) > -1
是 true
。但是在对Species
进行排序后,displayIndex
0、1 和 2 分别对应于观察值 101、102 和 103,因此回调会禁用它们。
为了解决这个问题,我尝试通过将rowCallback
函数中的displayIndex
更改为dataIndex
来禁用基于行名的行。但是,这会做一些奇怪的事情,每次我在不同的列上过滤时,额外的行都会被禁用。以下是表格首先按Sepal.Length
排序后的示例,然后是Sepal.Length
,最后是Petal.Length
:
这是重现上述内容的代码:
library(DT)
library(shiny)
disabled_rows = c(1,2,3)
#NOTE: displayIndex changed to dataIndex
rowCallback <- c(
"function(row, data, displayNum, dataIndex)",
sprintf(" var indices = [%s]", toString(disabled_rows - 1)),
" if(indices.indexOf(dataIndex) > -1)",
" $(row).find('td').addClass('notselectable').css('background-color': '#eee', 'color': '#bbb');",
" ",
""
)
get_selected_rows <- c(
"var id = $(table.table().node()).closest('.datatables').attr('id');",
"table.on('click', 'tbody', function()",
" setTimeout(function()",
" var indexes = table.rows(selected:true).indexes();",
" var indices = Array(indexes.length);",
" for(var i = 0; i < indices.length; ++i)",
" indices[i] = indexes[i];",
" ",
" Shiny.setInputValue(id + '_rows_selected', indices);",
" , 0);",
");"
)
drag_selection <- c(
"var dt = table.table().node();",
"$(dt).selectable(",
" distance : 10,",
" selecting: function(evt, ui)",
" $(this).find('tbody tr').each(function(i)",
" if($(this).hasClass('ui-selecting'))",
" table.row(i).select();",
" ",
" );",
" ",
").on('dblclick', function()table.rows().deselect(););"
)
shinyApp(
ui = fluidPage(
tags$head(tags$script(src = "https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js")),
DTOutput('table')
),
server = function(input, output, session)
output$table <- renderDT(
datatable(
iris,
callback = JS(get_selected_rows),
class = 'hover row-border order-column',
options = list(
rowCallback = JS(rowCallback),
select = list(style = "multi", selector = "td:not(.notselectable)")
),
extensions = "Select", selection = 'none'
)
, server = F)
observe(
print(input$table_rows_selected)
)
)
我不知道为什么将 displayIndex
更改为 dataIndex
不起作用,我不知道还能尝试什么。 dataIndex
参数 here 的 DataTables 定义对我来说是模糊的,因为我对 DT 插件不是很熟悉,所以我将不胜感激。
编辑:我也试过直接基于rowname禁用如下:
rowCallback <- c(
"function(row, data, displayNum, displayIndex)",
" var indices = [0, 2, 4, 15]",
" if(indices.indexOf(data[0]) > -1)",
" $(row).find('td').addClass('notselectable');",
" ",
""
)
【问题讨论】:
【参考方案1】:奇怪的是dataIndex
不起作用。
您可以为行使用一些 id。
disabled_rows = paste0("'", paste0("row", c(1,2,3)), "'")
rowCallback <- c(
"function(row, data, displayNum, displayIndex)",
sprintf(" var indices = [%s];", toString(disabled_rows)),
" if(indices.indexOf($(row).attr('id')) > - 1)",
" $(row).find('td').addClass('notselectable').css('background-color': '#eee', 'color': '#bbb');",
" ",
""
)
dat <- iris
dat$ID <- paste0("row", 1:nrow(iris))
rowNames <- TRUE
colIndex <- as.integer(rowNames)
output$table <- renderDT(
datatable(
dat,
rownames = rowNames,
callback = JS(get_selected_rows),
class = 'hover row-border order-column',
options = list(
rowId = JS(sprintf("function(data)return data[%d];",
ncol(dat)-1+colIndex)),
rowCallback = JS(rowCallback),
select = list(style = "multi", selector = "td:not(.notselectable)")
),
extensions = "Select", selection = 'none'
)
, server = TRUE)
【讨论】:
这是一个天才的解决方法,谢谢@Stéphane。您介意我问一下您是如何知道使用rowId
的吗?我找不到它的文档,也没有意识到要使用它。
谢谢,为什么这里需要server = T
?我注意到如果我使用server = F
,那么我遇到的问题与我用dataIndex
替换displayIndex
时遇到的问题相同。
@user51462 嗯,很奇怪,我不明白为什么这会导致差异。
不用担心。此外,input$table_selected_rows
返回所选行的displayIndex
,而不是其实际索引。例如。如果您单击第 150 页上的最后一个观察值,input$table_selected_rows
返回 9 而不是 149。我尝试通过通过 dat$index = rownames(iris)
将 rowId
设置为行名来解决此问题,然后使用 var indexes = table.rows(selected:true).attr('id');"
通过其 ID 识别所选行在@ 987654336的第4行中,回调但没有什么时候被选中行时返回,您是否有任何想法如何? span>
在 get_selected_rows
回调的第 4 行中使用 dat$index = rownames(iris)
和 "var indexes = table.rows(selected:true).ids();"
通过返回正确的索引但以字符形式部分修复它,因为它们是行 ID。 JS 中是否有 as.numeric
等价物?我仍然对为什么 rows(selected:true).index()
和 .indexes()
返回 displayIndex 感到困惑。两种方法都应该根据documentation检索内部索引。以上是关于R Shiny - 使用列排序禁用数据表中的特定行的主要内容,如果未能解决你的问题,请参考以下文章
使用 PyQt/PySide 禁用 QTableWidget 中特定列中的排序箭头