Nothing
#' @include zzz.R
#'
NULL
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# Class definitions
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#' A Logical Map
#'
#' A simple container for storing mappings of values using logical matrices.
#' Keeps track of which values (rows) are present in which observations
#' (columns). \code{LogMap} objects can be created with \code{LogMap()};
#' queries can be performed with \code{[[} and observations can be added
#' or removed with \code{[[<-}
#'
#' @slot .Data A logical matrix with at least one row
#'
#' @exportClass LogMap
#'
#' @family logmap
#'
setClass(
Class = 'LogMap',
contains = 'matrix'
)
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# Functions
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#' @rdname LogMap-class
#'
#' @param y A character vector
#'
#' @return \code{LogMap}: A new \code{LogMap} object with zero columns and
#' \code{length(x = x)} rows; rownames are set to \code{x}
#'
#' @export
#'
#' @order 1
#'
#' @examples
#' # Create a LogMap
#' map <- LogMap(letters[1:10])
#' map
#'
#' # Get the names of values in the LogMap
#' map[[NULL]]
#' rownames(map)
#'
#' # Add an observation to the LogMap
#' map[['obs']] <- c(1, 3, 7)
#' map[['entry']] <- c(2, 7, 10)
#' map
#'
#' # Get the names of observations in the LogMap
#' colnames(map)
#'
#' # Fetch an observation from the LogMap
#' map[['obs']]
#'
#' # Get the full logical matrix
#' map[[]]
#'
#' # Remove an observation from the LogMap
#' map[['obs']] <- NULL
#' map[['entry']] <- NULL
#' map
#'
LogMap <- function(y) {
if (!is.character(x = y)) {
y <- as.character(x = y)
}
return(new(
Class = 'LogMap',
.Data = matrix(nrow = length(x = y), ncol = 0, dimnames = list(y, NULL))
))
}
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# Methods for Seurat-defined generics
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# Methods for R-defined generics
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#' Coerce Logical Maps to Matrices
#'
#' Coerce a logical map to a matrix; this removes all
#' \link[=LogMap]{logical map} class capabilities from
#' the object and returns a base-R matrix object
#'
#' @param x A \code{\link{LogMap}} object
#' @template param-dots-ignored
#'
#' @return A base-R matrix created from \code{x}
#'
#' @method as.matrix LogMap
#' @export
#'
#' @family logmap
#'
#' @examples
#' map <- LogMap(letters[1:10])
#' map[['obs']] <- c(1, 3, 7)
#' mat <- as.matrix(map)
#' mat
#' class(mat)
#'
as.matrix.LogMap <- function(x, ...) {
return(as(object = x, Class = 'matrix'))
}
#' Drop Unused Logical Map Values
#'
#' Remove any unused values from a \link[=LogMap]{logical map}
#'
#' @template param-dots-ignored
#' @param x A \code{LogMap} object
#'
#' @return \code{x} with values not present in any
#' observation removed
#'
#' @method droplevels LogMap
#' @export
#'
#' @family logmap
#'
#' @examples
#' map <- LogMap(letters[1:10])
#' map[['obs']] <- c(1, 3, 7)
#' map[['entry']] <- c(2, 7, 10)
#'
#' # Remove unused values
#' map <- droplevels(map)
#' map
#' map[[]]
#'
droplevels.LogMap <- function(x, ...) {
fidx <- which(x = apply(
X = x,
MARGIN = 1L,
FUN = function(row) {
return(all(vapply(
X = row,
FUN = isFALSE,
FUN.VALUE = logical(length = 1L)
)))
}
))
if (length(x = fidx)) {
x <- as(object = x[-fidx, , drop = FALSE], Class = 'LogMap')
}
validObject(object = x)
return(x)
}
#' Find Common Logical Map Values
#'
#' Identify values in a \link[=LogMap]{logical map} that are
#' common to every observation
#'
#' @inheritParams droplevels.LogMap
#' @param y Ignored
#'
#' @return The values of \code{x} that are present in \strong{every} observation
#'
#' @method intersect LogMap
#' @export
#'
#' @family logmap
#'
#' @examples
#' map <- LogMap(letters[1:10])
#' map[['obs']] <- c(1, 3, 7)
#' map[['entry']] <- c(2, 7, 10)
#'
#' # Identify values that are present in every observation
#' intersect(map)
#'
intersect.LogMap <- function(x, y = missing_arg(), ...) {
if (!is_missing(x = y)) {
abort(message = "'y' must not be provided")
}
idx <- which(x = apply(X = x, MARGIN = 1L, FUN = all))
return(rownames(x = x)[idx])
}
#' Find Observations by Value
#'
#' Identify the observations that contain a specific
#' value in a \link[=LogMap]{logical map}
#'
#' @template param-dots-ignored
#' @param object A \code{\link{LogMap}} object
#' @param values A vector of values to find observations for
#' @param select Observation selection method; choose from:
#' \itemize{
#' \item \dQuote{\code{first}}: the first observation the value is found in
#' \item \dQuote{\code{last}}: the last observation the value is found in
#' \item \dQuote{\code{common}}: the first most-common observation the value
#' is found in; most-common is determined by the observation that contains
#' the most of the values requested
#' \item \dQuote{\code{all}}: all observations the value is found in
#' }
#' @param simplify Simplify the resulting list to a vector
#'
#' @return \code{labels}: A list, or vector if \code{simplify} is \code{TRUE},
#' of all values and the observations they're found in, according
#' to the value of \code{select}
#'
#' @method labels LogMap
#' @export
#'
#' @family logmap
#'
#' @examples
#' map <- LogMap(letters[1:10])
#' map[['obs']] <- c(1, 3, 7)
#' map[['entry']] <- c(2, 7, 10)
#'
#' # Find observations for a set of values
#' labels(map, c('a', 'b', 'g'))
#'
labels.LogMap <- function(
object,
values,
select = c('first', 'last', 'common', 'all'),
simplify = TRUE,
...
) {
select <- select[1L]
select <- match.arg(arg = select)
values <- intersect(x = values, y = rownames(x = object))
p <- progressor(along = values)
obs <- sapply(
X = values,
FUN = function(x) {
vals <- colnames(x = object)[which(x = object[x, , drop = TRUE])]
p()
return(vals)
},
simplify = FALSE,
USE.NAMES = TRUE
)
obs <- Filter(f = length, x = obs)
obs <- switch(
EXPR = select,
'first' = lapply(X = obs, FUN = '[[', 1L),
'last' = lapply(
X = obs,
FUN = function(x) {
return(x[[length(x = x)]])
}
),
common = {
counts <- table(unlist(x = obs))
tmp <- obs
obs <- vector(mode = 'character', length = length(x = tmp))
names(x = obs) <- names(x = tmp)
for (i in seq_along(along.with = obs)) {
obs[i] <- names(x = which.max(
x = counts[names(x = counts) %in% tmp[[i]]]
))
}
obs
},
obs
)
if (isTRUE(x = simplify)) {
tmp <- obs
obs <- unlist(x = tmp)
names(x = obs) <- make.unique(names = rep.int(
x = names(x = tmp),
times = vapply(X = tmp, FUN = length, FUN.VALUE = numeric(length = 1L))
))
}
return(obs)
}
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# Internal
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# S4 methods
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#' Matrix-like Subsetting for \link[=LogMap]{Logical Maps}
#'
#' @inheritParams base::`[`
#' @inheritParams LogMap-class
#' @param i,j Vectors of values (\code{i}) and observations (\code{j}) to pull
#' from \code{x}
#' @template param-dots-method
#'
#' @note \code{i} is not reordable; passing a different order for \code{i}
#' will return a subset with rows in the same order as \code{x}
#'
#' @name [,LogMap
#' @rdname sub-LogMap-method
#'
#' @keywords internal
#'
#' @examples
#' map <- LogMap(letters[1:10])
#' map[['obs']] <- c(1, 3, 7)
#' map[['entry']] <- c(2, 7, 10)
#'
#' map[]
#' map[1:5, 2L]
#' map[c("b", "c", "f"), "obs"]
#'
#' # Pass `drop = TRUE` to cast to `matrix`
#' map[1:3, , drop = TRUE]
#'
#' # Note that `i` is non-reordable
#' rownames(map)[1:3]
#' map[c("b", "c", "a"), , drop = TRUE]
#'
NULL
#' @rdname sub-LogMap-method
#'
setMethod(
f = '[',
signature = c(x = 'LogMap', i = 'missing', j = 'missing'),
definition = function(x, i, j, ..., drop = FALSE) {
return(x)
}
)
#' @rdname sub-LogMap-method
#'
setMethod(
f = '[',
signature = c(x = 'LogMap', i = 'character', j = 'character'),
definition = function(x, i, j, ..., drop = FALSE) {
i <- i[MatchCells(new = i, orig = rownames(x = x), ordered = TRUE)]
x <- as.matrix(x = x)[i, j, drop = drop]
if (!isTRUE(x = drop)) {
x <- as(object = x, Class = 'LogMap')
}
return(x)
}
)
#' @rdname sub-LogMap-method
#'
setMethod(
f = '[',
signature = c(x = 'LogMap', i = 'character', j = 'missing'),
definition = function(x, i, j, ..., drop = FALSE) {
i <- i[MatchCells(new = i, orig = rownames(x = x), ordered = TRUE)]
x <- as.matrix(x = x)[i, , drop = drop]
if (!isTRUE(x = drop)) {
x <- as(object = x, Class = 'LogMap')
}
return(x)
}
)
#' @rdname sub-LogMap-method
#'
setMethod(
f = '[',
signature = c(x = 'LogMap', i = 'missing', j = 'character'),
definition = function(x, i, j, ..., drop = FALSE) {
x <- as.matrix(x = x)[, j, drop = drop]
if (!isTRUE(x = drop)) {
x <- as(object = x, Class = 'LogMap')
}
return(x)
}
)
#' @rdname sub-LogMap-method
#'
setMethod(
f = '[',
signature = c(x = 'LogMap', i = 'numeric', j = 'missing'),
definition = function(x, i, j, ..., drop = FALSE) {
stopifnot(is_bare_integerish(x = i))
if (is.unsorted(x = i)) {
i <- sort(x = i)
}
i <- rownames(x = x)[i]
return(callNextMethod(x, i, ..., drop = drop))
}
)
#' @rdname sub-LogMap-method
#'
setMethod(
f = '[',
signature = c(x = 'LogMap', i = 'missing', j = 'numeric'),
definition = function(x, i, j, ..., drop = FALSE) {
stopifnot(is_bare_integerish(x = j))
j <- colnames(x = x)[j]
return(callNextMethod(x, , j, ..., drop = drop))
}
)
#' @rdname sub-LogMap-method
#'
setMethod(
f = '[',
signature = c(x = 'LogMap', i = 'numeric', j = 'numeric'),
definition = function(x, i, j, ..., drop = FALSE) {
stopifnot(is_bare_integerish(x = i), is_bare_integerish(x = j))
if (is.unsorted(x = i)) {
i <- sort(x = i)
}
i <- rownames(x = x)[i]
j <- colnames(x = x)[j]
return(callNextMethod(x, i, j, ..., drop = drop))
}
)
#' @rdname LogMap-class
#'
#' @param x A \code{LogMap} object
#' @param i A character vector of length 1, or \code{NULL}
#' @param j Not used
#' @param ... Ignored
#'
#' @return \code{[[}: if \code{i} is a character vector, the rownames that are
#' mapped to \code{i}; otherwise the rownames of \code{x}
#'
#' @export
#'
#' @order 2
#'
setMethod(
f = '[[',
signature = c(x = 'LogMap', i = 'character', j = 'missing'),
definition = function(x, i, ...) {
i <- i[1]
i <- match.arg(arg = i, choices = colnames(x = x))
return(rownames(x = x)[x[, i, drop = TRUE]])
}
)
#' \code{\link{LogMap}} Interaction Methods
#'
#' Additional methods for using \code{[[} with \code{\link{LogMap}} objects
#'
#' @inheritParams LogMap
#' @param i An integer or numeric vector of length 1
#'
#' @return The rownames that are mapped to \code{i}
#'
#' @rdname sub-sub-LogMap-internal-method
#'
#' @keywords internal
#'
setMethod(
f = '[[',
signature = c(x = 'LogMap', i = 'integer', j = 'missing'),
definition = function(x, i, ...) {
return(x[[colnames(x = x)[i]]])
}
)
#' @rdname LogMap-class
#'
#' @export
#'
#' @order 3
#'
setMethod(
f = '[[',
signature = c(x = 'LogMap', i = 'missing', j = 'missing'),
definition = function(x, ...) {
return(slot(object = x, name = '.Data'))
}
)
#' @rdname sub-sub-LogMap-internal-method
#'
setMethod(
f = '[[',
signature = c(x = 'LogMap', i = 'numeric', j = 'missing'),
definition = function(x, i, ...) {
return(x[[as.integer(x = i)]])
}
)
#' @rdname LogMap-class
#'
#' @export
#'
#' @order 4
#'
setMethod(
f = '[[',
signature = c(x = 'LogMap', i = 'NULL', j = 'missing'),
definition = function(x, i, ...) {
return(rownames(x = x))
}
)
#' @rdname LogMap-class
#'
#' @param value A character or integer vector of values to record in the map
#' for \code{i}, or \code{NULL} to remove the record for \code{i}
#'
#' @return \code{[[<-}: If \code{value} is \code{NULL}, then \code{x} without
#' the observations for \code{i}; otherwise, \code{x} with a new column for
#' \code{i} recording a \code{TRUE} for all values present in \code{value}
#'
#' @export
#'
#' @order 5
#'
setMethod(
f = '[[<-',
signature = c(
x = 'LogMap',
i = 'character',
j = 'missing',
value = 'character'
),
definition = function(x, i, ..., value) {
value <- MatchCells(new = rownames(x = x), orig = value)
x[[i]] <- value
return(x)
}
)
#' @rdname LogMap-class
#'
#' @export
#'
#' @order 6
#'
setMethod(
f = '[[<-',
signature = c(
x = 'LogMap',
i = 'character',
j = 'missing',
value = 'integer'
),
definition = function(x, i, ..., value) {
if (i %in% colnames(x = x)) {
x[[i]] <- NULL
}
value <- MatchCells(new = value, rownames(x = x))
mat <- slot(object = x, name = '.Data')
if (length(x = value)) {
mat <- cbind(
mat,
matrix(data = FALSE, nrow = nrow(x = x), dimnames = list(NULL, i))
)
mat[value, i] <- TRUE
}
slot(object = x, name = '.Data') <- mat
validObject(object = x)
return(x)
}
)
#' @rdname LogMap-class
#'
#' @export
#'
#' @order 7
#'
setMethod(
f = '[[<-',
signature = c(x = 'LogMap', i = 'character', j = 'missing', value = 'NULL'),
definition = function(x, i, ..., value) {
mat <- slot(object = x, name = '.Data')
for (name in i) {
idx <- which(x = colnames(x = mat) == name)
if (length(x = idx)) {
mat <- mat[, -idx, drop = FALSE]
}
}
slot(object = x, name = '.Data') <- mat
validObject(object = x)
return(x)
}
)
#' @rdname LogMap-class
#'
#' @export
#'
#' @order 8
#'
setMethod(
f = '[[<-',
signature = c(
x = 'LogMap',
i = 'character',
j = 'missing',
value = 'numeric'
),
definition = function(x, i, ..., value) {
value <- as.integer(x = value)
x[[i]] <- value
return(x)
}
)
#' \code{\link{LogMap}} Object Overview
#'
#' Overview of a \code{\link{LogMap}} object
#'
#' @param object A \code{\link{LogMap}} object
#'
#' @template return-show
#'
#' @concept logmap
#'
setMethod(
f = 'show',
signature = 'LogMap',
definition = function(object) {
cat(
"A logical map for",
nrow(x = object),
"values across",
ncol(x = object),
"observations"
)
return(invisible(x = NULL))
}
)
#' Logical Map Validity
#'
#' @templateVar cls LogMap
#' @template desc-validity
#'
#' @section Data Validation:
#' Logical maps must be a logical matrix containing only TRUE or FALSE values
#'
#' @section Value Validation:
#' All values must be named within the rownames of the object. Duplicate or
#' empty (\code{""}) values are not allowed
#'
#' @section Observation Validation:
#' All observations must be named within the column names of the object.
#' Duplicate or empty (\code{""}) observations are not allowed
#'
#' @name LogMap-validity
#'
#' @family logmap
#' @seealso \code{\link[methods]{validObject}}
#'
#' @examples
#' map <- LogMap(letters[1:10])
#' map[['obs']] <- c(1, 3, 7)
#' map[['entry']] <- c(2, 7, 10)
#' validObject(map)
#'
setValidity(
Class = 'LogMap',
method = function(object) {
if (isFALSE(x = getOption(x = "Seurat.object.validate", default = TRUE))) {
warn(
message = paste("Not validating", class(x = object)[1L], "objects"),
class = 'validationWarning'
)
return(TRUE)
}
valid <- NULL
# Ensure we have a logical matrix
if (!is.logical(x = object)) {
valid <- c(valid, "The map must be a logical matrix")
}
if (any(is.na(x = object))) {
valid <- c(valid, "The may may not contain NAs")
}
# Check rownames
if (is.null(x = rownames(x = object))) {
valid <- c(valid, "Rownames must be supplied")
}
if (any(!nzchar(x = rownames(x = object)))) {
valid <- c(valid, "Rownames cannot be empty strings")
}
if (anyDuplicated(x = rownames(x = object))) {
valid <- c(valid, "Duplicate rownames not allowed")
}
# Check colnames
if (!is.null(x = colnames(x = object))) {
if (any(!nzchar(x = colnames(x = object)))) {
valid <- c(valid, "Columnn names cannot be empty strings")
}
if (anyDuplicated(x = colnames(x = object))) {
valid <- c(valid, "Duplicate colnames not allowed")
}
} else if (ncol(x = object)) {
valid <- c(valid, "Colnames must be supplied")
}
return(valid %||% TRUE)
}
)
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.