Как видно из ?replaceData
:
Когда вы заменяете данные в существующей таблице, убедитесь, что новые данные имеют то же количество столбцов, что и текущие данные.Когда вы включили фильтры столбцов, вы также должны убедиться, что атрибуты каждого столбца остаются одинаковыми, например, столбцы фактора должны иметь одинаковый или меньший уровень, а числовые столбцы должны иметь одинаковый или меньший диапазон, иначе фильтры могут быть недоступны.чтобы достичь определенных строк в данных.
Это означает, что вы можете получить только меньшие фильтры, но не больше.
Ну, это не чисто, а подвох:
Если вы используете trace(datatable, edit=T)
, вы можете изменить функцию datatable
, поэтому, если вы замените исходный код следующим образом:
function (data, options = list(), class = "display", callback = JS("return table;"),
rownames, colnames, container, caption = NULL, filter = c("none",
"bottom", "top"), escape = TRUE, style = "default",
width = NULL, height = NULL, elementId = NULL, fillContainer = getOption("DT.fillContainer",
NULL), autoHideNavigation = getOption("DT.autoHideNavigation",
NULL), selection = c("multiple", "single", "none"),
extensions = list(), plugins = NULL, editable = FALSE)
{
datafull = data[[2]]
data = data[[1]]
oop = base::options(stringsAsFactors = FALSE)
on.exit(base::options(oop), add = TRUE)
options = modifyList(getOption("DT.options", list()), if (is.function(options))
options()
else options)
params = list()
if (crosstalk::is.SharedData(data)) {
params$crosstalkOptions = list(key = data$key(), group = data$groupName())
data = data$data(withSelection = FALSE, withFilter = TRUE,
withKey = FALSE)
datafull = data$data(withSelection = FALSE, withFilter = TRUE,
withKey = FALSE)
}
rn = if (missing(rownames) || isTRUE(rownames))
base::rownames(data)
else {
if (is.character(rownames))
rownames
}
hideDataTable = FALSE
if (is.null(data) || identical(ncol(data), 0L)) {
data = matrix(ncol = 0, nrow = NROW(data))
datafull = matrix(ncol = 0, nrow = NROW(datafull))
hideDataTable = TRUE
}
else if (length(dim(data)) != 2) {
str(data)
stop("'data' must be 2-dimensional (e.g. data frame or matrix)")
}
if (is.data.frame(data)) {
data = as.data.frame(data)
numc = unname(which(vapply(data, is.numeric, logical(1))))
}
else {
if (!is.matrix(data))
stop("'data' must be either a matrix or a data frame, and cannot be ",
classes(data), " (you may need to coerce it to matrix or data frame)")
numc = if (is.numeric(data))
seq_len(ncol(data))
data = as.data.frame(data)
}
if (!is.null(rn)) {
data = cbind(` ` = rn, data)
datafull = cbind(` ` = rn, datafull)
numc = numc + 1
}
if (length(numc)) {
undefined_numc = setdiff(numc - 1, classNameDefinedColumns(options))
if (length(undefined_numc))
options = appendColumnDefs(options, list(className = "dt-right",
targets = undefined_numc))
}
if (is.null(options[["order"]]))
options$order = list()
if (is.null(options[["autoWidth"]]))
options$autoWidth = FALSE
if (is.null(options[["orderClasses"]]))
options$orderClasses = FALSE
cn = base::colnames(data)
if (missing(colnames)) {
colnames = cn
}
else if (!is.null(names(colnames))) {
i = convertIdx(colnames, cn)
cn[i] = names(colnames)
colnames = cn
}
if (ncol(data) - length(colnames) == 1)
colnames = c(" ", colnames)
if (length(colnames) && colnames[1] == " ")
options = appendColumnDefs(options, list(orderable = FALSE,
targets = 0))
style = match.arg(tolower(style), DTStyles())
if (style == "bootstrap")
class = DT2BSClass(class)
if (style != "default")
params$style = style
if (isTRUE(fillContainer))
class = paste(class, "fill-container")
if (is.character(filter))
filter = list(position = match.arg(filter))
filter = modifyList(list(position = "none", clear = TRUE,
plain = FALSE), filter)
filterHTML = as.character(filterRow(datafull, !is.null(rn) &&
colnames[1] == " ", filter))
if (filter$position == "top")
options$orderCellsTop = TRUE
params$filter = filter$position
if (filter$position != "none")
params$filterHTML = filterHTML
if (missing(container)) {
container = tags$table(tableHeader(colnames, escape),
class = class)
}
else {
params$class = class
}
attr(options, "escapeIdx") = escapeToConfig(escape, colnames)
if (is.list(extensions)) {
extensions = names(extensions)
}
else if (!is.character(extensions)) {
stop("'extensions' must be either a character vector or a named list")
}
params$extensions = if (length(extensions))
as.list(extensions)
if ("Responsive" %in% extensions)
options$responsive = TRUE
params$caption = captionString(caption)
if (editable)
params$editable = editable
if (!identical(class(callback), class(JS(""))))
stop("The 'callback' argument only accept a value returned from JS()")
if (length(options$pageLength) && length(options$lengthMenu) ==
0) {
if (!isFALSE(options$lengthChange))
options$lengthMenu = sort(unique(c(options$pageLength,
10, 25, 50, 100)))
if (identical(options$lengthMenu, c(10, 25, 50, 100)))
options$lengthMenu = NULL
}
if (!is.null(fillContainer))
params$fillContainer = fillContainer
if (!is.null(autoHideNavigation))
params$autoHideNavigation = autoHideNavigation
params = structure(modifyList(params, list(data = data,
container = as.character(container), options = options,
callback = if (!missing(callback)) JS("function(table) {",
callback, "}"))), colnames = cn, rownames = length(rn) >
0)
if (inShiny() || length(params$crosstalkOptions)) {
if (is.character(selection)) {
selection = list(mode = match.arg(selection))
}
selection = modifyList(list(mode = "multiple", selected = NULL,
target = "row"), selection)
if (grepl("^row", selection$target) && is.character(selection$selected) &&
length(rn)) {
selection$selected = match(selection$selected, rn)
}
params$selection = selection
}
deps = list(DTDependency(style))
deps = c(deps, unlist(lapply(extensions, extDependency,
style, options), recursive = FALSE))
if (params$filter != "none")
deps = c(deps, filterDependencies())
if (isTRUE(options$searchHighlight))
deps = c(deps, list(pluginDependency("searchHighlight")))
if (length(plugins))
deps = c(deps, lapply(plugins, pluginDependency))
deps = c(deps, crosstalk::crosstalkLibs())
if (isTRUE(fillContainer)) {
width = NULL
height = NULL
}
htmlwidgets::createWidget("datatables", if (hideDataTable)
NULL
else params, package = "DT", width = width, height = height,
elementId = elementId, sizingPolicy = htmlwidgets::sizingPolicy(knitr.figure = FALSE,
knitr.defaultWidth = "100%", knitr.defaultHeight = "auto"),
dependencies = deps, preRenderHook = function(instance) {
data = instance[["x"]][["data"]]
if (object.size(data) > 1500000 && getOption("DT.warn.size",
TRUE))
warning("It seems your data is too big for client-side DataTables. You may ",
"consider server-side processing: https://rstudio.github.io/DT/server.html")
data = escapeData(data, escape, colnames)
data = unname(data)
instance$x$data = data
instance
})
}
И, сохранив его, вы увидите, что делаете это:
library(shiny)
library(data.table)
library(DT)
ui <- fluidPage(
fluidRow(DTOutput("table")),
fluidRow(actionButton("replace", "Replace Data"))
)
server <- function(input, output, session) {
output$table <- renderDT({
data <- data.table(NUMERIC = c(1, 2, 3), FACTOR = as.factor(c("A", "B", "C")), TEXT = c("A1", "B2", "C3"), stringsAsFactors = FALSE)
datafull <- data.table(NUMERIC = c(1, 2, 3, 4), FACTOR = as.factor(c("A", "B", "C", "D")), TEXT = c("A1", "B2", "C3", "D4"), stringsAsFactors = FALSE)
datatable(list(data,datafull), filter = list(position = "top"))
})
observeEvent(input$replace, {
data <- data.frame(NUMERIC = c(1, 2, 3, 4), FACTOR = as.factor(c("A", "B", "C", "D")), TEXT = c("A1", "B2", "C3", "D4"), stringsAsFactors = FALSE)
replaceData(proxy = dataTableProxy("table"), data = data)
})
}
shinyApp(ui = ui, server = server)
Вы видите, что можете фильтровать D
и 4
с самого начала.Это хитрый кусок дерьма, я знаю.Пожалуйста, не судите меня очень строго ...