RunKNNPredict() fails with dgCMatrix on BiocNeighbors 2.0.x
Nobody has claimed this yet.
Assessment
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Newbie friendliness
- 72/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- r
- Domain
- machine-learning
Research direction
Run the supplied RunReferenceMapping reproducer under R 4.4.3 with BiocNeighbors 2.0.0. Inspect sclet_extract_cell_feature_matrix() in R/matrix-utils.R and the queryKNN() calls in R/annotation.R, then verify that KNN reference mapping works with the older BiocNeighbors input requirements without breaking the current path.
Written by the indexing model from the issue text.
Description
I am not very familiar with the overall design of this project, so please correct me if I misunderstand anything.
And this time, I encountered an error when using KNN reference mapping:
obj.knn <- RunReferenceMapping(
object = obj,
ref = hpca,
labels = "label.main",
method = "KNN",
layer = "logcounts",
k = 5,
name = "hpca_knn"
)
The error is:
Error: unable to find an inherited method for function ‘queryKNN’ for signature ‘X = "dgCMatrix"’
Traceback:
1. RunKNNPredict(object = object, ref = ref, labels = labels, features = features,
. layer = layer, k = k, name = name, ...)
2. BiocNeighbors::queryKNN(X = ref_mat, query = query_mat, k = k)
3. (function (classes, fdef, mtable)
. {
. methods <- .findInheritedMethods(classes, fdef, mtable)
. if (length(methods) == 1L)
. return(methods[[1L]])
. else if (length(methods) == 0L) {
. cnames <- paste0(fdef@signature[seq_along(classes)],
. " = \"", vapply(classes, as.character, ""), "\"",
. collapse = ", ")
. stop(gettextf("unable to find an inherited method for function %s for signature %s",
. sQuote(fdef@generic), sQuote(cnames)), call. = FALSE,
. domain = NA)
. }
. else stop("Internal error in finding inherited methods; didn't return a unique method",
. domain = NA)
. })(list(structure("dgCMatrix", package = "Matrix")), new("nonstandardGenericFunction",
. .Data = function (X, query, k, get.index = TRUE, get.distance = TRUE,
. num.threads = 1, subset = NULL, transposed = FALSE, ...,
. BNPARAM = NULL)
. {
. standardGeneric("queryKNN")
. }, generic = structure("queryKNN", package = "BiocNeighbors"),
. package = "BiocNeighbors", group = list(), valueClass = character(0),
. signature = c("X", "BNPARAM"), default = NULL, skeleton = (function (X,
. query, k, get.index = TRUE, get.distance = TRUE, num.threads = 1,
. subset = NULL, transposed = FALSE, ..., BNPARAM = NULL)
. stop(gettextf("invalid call in method dispatch to '%s' (no default method)",
. "queryKNN"), domain = NA))(X, query, k, get.index, get.distance,
. num.threads, subset, transposed, ..., BNPARAM = BNPARAM)),
. <environment>)
4. stop(gettextf("unable to find an inherited method for function %s for signature %s",
. sQuote(fdef@generic), sQuote(cnames)), call. = FALSE, domain = NA)
5. .handleSimpleError(function (cnd)
. {
. watcher$capture_plot_and_output()
. cnd <- sanitize_call(cnd)
. watcher$push(cnd)
. switch(on_error, continue = invokeRestart("eval_continue"),
. stop = invokeRestart("eval_stop"), error = NULL)
. }, "unable to find an inherited method for function ‘queryKNN’ for signature ‘X = \"dgCMatrix\"’",
. base::quote(NULL))
My environment is:
R 4.4.3
Bioconductor 3.20
BiocNeighbors 2.0.0
It appears that RunKNNPredict() converts the reference and query matrices to dgCMatrix, and then passes them directly to BiocNeighbors::queryKNN().
In the current implementation, sclet_extract_cell_feature_matrix() returns a dgCMatrix:
In R/matrix-utils.R, around line 65:
sclet_extract_cell_feature_matrix <- function(object, assay_name, features = NULL) {
mat <- SummarizedExperiment::assay(object, assay_name)
if (!is.null(features)) {
features <- intersect(features, rownames(object))
if (length(features) == 0) {
stop("No overlapping features found in assay '", assay_name, "'.")
}
mat <- mat[features, , drop = FALSE]
}
sclet_as_dgCMatrix(Matrix::t(mat))
}
RunKNNPredict() then constructs both the query and reference matrices using this helper:
In R/annotation.R, around line 260:
query_mat <- sclet_extract_cell_feature_matrix(
object = object,
assay_name = source$assay,
features = features
)
and around line 271:
ref_mat <- sclet_extract_cell_feature_matrix(
object = ref,
assay_name = ref_assay,
features = features
)
and passes them directly to:
knn_res <- BiocNeighbors::queryKNN(X = ref_mat, query = query_mat, k = k)
This appears to cause a compatibility issue with BiocNeighbors 2.0.0, where queryKNN() does not accept this dgCMatrix input in this code path.
The BiocNeighbors release notes for Bioconductor 3.20 state that functions no longer automatically coerce X to an ordinary matrix and that users should perform the conversion themselves:
All functions (findKNN(), queryNeighbors(), etc.) will no longer coerce X to a matrix, to avoid the headache of S4 dispatch ambiguity. Users should coerce their data into matrix format before supplying it to these functions.
Reference:
https://bioconductor.org/news/bioc_3_20_release
Support for non-ordinary matrices in both X and query was later added in BiocNeighbors 2.6.0:
Accept non-ordinary matrices in X= and query= arguments for all functions. This requires beachmat to be installed.
Reference:
https://bioconductor.org/news/bioc_3_23_release
So my concern is that, BiocNeighbors 2.6.0 is provided with Bioconductor 3.23, which requires R 4.6. Therefore, users on R 4.4 / Bioconductor 3.20 cannot simply upgrade to BiocNeighbors 2.6.0 without upgrading their R/Bioconductor environment. So as R 4.5.
Would it be possible to add compatibility for older BiocNeighbors versions, for example by converting the matrices to ordinary matrices when required, or by handling this condition according to the installed BiocNeighbors version?
Thanks!
- Dominant language
- R
- Stars
- 24
- Forks
- 8
- PR merge metrics
- No merged PRs in 30d
Getting set up
This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Similar issues
-
bug triage
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
easystats/parameters#1290 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
corybrunson/ordr#91 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
pharmaverse/admiralonco#366 ·
-
Difficulty 1/5 Under an hour Newbie friendliness 85/100
HelenaLC/spatialdataR#289 · 1 comment ·
Maintainers usually reply within 1 day