This vignette will introduce the reason for creating method wrappers and conventions to follow. Method wrappers are a way to subtlely alter the behaviour of functions from other libraries. CellBench requires that all methods within a step accept the same type of input and produce the same type of output, this is often not the case for functions of different libraries which perform the same task, therefore it is necessary to write code that “wraps” these methods to conform to our requirements.
Examples of wrappers can be found at the following Github repositories
There are some requirements for wrappers used in CellBench:
class()
, also be careful of methods that
return raw counts compared to normalised counts.To ensure flexibility and compatibility of wrappers, the following conventions are recommended:
Wrappers should only require a single argument, additional arguments should be set to sensible defaults, if more arguments non-defaultable are absolutely necessary then wrappers should take a list as its first argument.
# generic skeleton for a wrapper
wrapper <- function(sce, ...) {
stopifnot(is(sce, "SingleCellExperiment"))
res <- method_function(sce, ...)
return(res)
}
We can write a simple wrapper for DrImpute()
:
# one possible wrapper implmentation
drimpute_wrapper <- function(sce, ...) {
# wrapper only accepts SingleCellExperiment or matrix type objects
stopifnot(is(sce, "SingleCellExperiment"))
expr <- SingleCellExperiment::normcounts(sce)
expr_processed <- DrImpute::preprocessSC(expr)
logcounts(sce) <- DrImpute::DrImpute(expr_processed, ...)
return(sce)
}
Any argument passed into ...
will be passed onto
DrImpute()
. Sometimes it helps to explicitly name the
arguments we may want to change, or limit what we allow to be changed in
order to guarantee better consistency.
# another possible implementation
# DrImpute's default ks is 10:15, we can use 5:15 for robustness
drimpute_wrapper <- function(sce, ks = 5:15, method = c("mean", "med")) {
stopifnot(is(sce, "SingleCellExperiment"))
expr <- SingleCellExperiment::normcounts(sce)
expr_processed <- DrImpute::preprocessSC(expr)
method <- match.arg(method)
logcounts(sce) <- DrImpute::DrImpute(expr_processed, ks = ks, method = method)
return(sce)
}
Then we can alter these wrappers on-the-fly using
purrr::partial()
Wrappers for methods should take SingleCellExperiment
and return SingleCellExperiments
with results stored in the
the appropriate slots of assays
, colData
or
rowData
. If the computational results don’t fit nicely into
these slots the they should be placed in an appropriate property in
metadata
.