#' @title Function to detect patches containing defined cell types
#'
#' @description Function to detect spatial clusters of defined types of cells.
#' By defining a certain distance threshold, all cells within the vicinity
#' of these clusters are detected as well.
#'
#' @param object a \code{SingleCellExperiment} or \code{SpatialExperiment}
#' object
#' @param patch_cells logical vector of length equal to the number of cells
#' contained in \code{object}. \code{TRUE} entries define the cells to consider
#' for patch detection (see Details).
#' @param colPairName single character indicating the \code{colPair(object)}
#' entry containing the neighbor information.
#' @param min_patch_size single integer indicating the minimum number of
#' connected cells that make up a patch before expansion.
#' @param name single character specifying the \code{colData} entry storing
#' the patch IDs in the returned object.
#' @param expand_by single numeric indicating in which vicinity range cells
#' should be considered as belonging to the patch (see Details).
#' @param coords character vector of length 2 specifying the names of the
#' \code{colData} (for a \code{SingleCellExperiment} object) or the
#' \code{spatialCoords} entries of the cells' x and y locations.
#' @param convex should the convex hull be computed before expansion? Default:
#' the concave hull is computed.
#' @param img_id single character indicating the \code{colData(object)} entry
#' containing the unique image identifiers.
#' @param BPPARAM a \code{\link[BiocParallel]{BiocParallelParam-class}} object
#' defining how to parallelize computations.
#'
#' @section Detecting patches of defined cell types:
#' This function works as follows:
#'
#' 1. Only cells defined by \code{patch_cells} are considered for patch
#' detection.
#'
#' 2. Patches of connected cells are detected. Here, cell-to-cell connections
#' are defined by the interaction graph stored in
#' \code{colPair(object, colPairName)}. At this point, patches that contain
#' fewer than \code{min_patch_size} cells are removed.
#'
#' 3. If \code{expand_by > 0}, a concave (default) or convex hull is constructed
#' around each patch. This is is then expanded by \code{expand_by} and cells
#' within the expanded hull are detected and assigned to the patch. This
#' expansion only works if a patch contains at least 3 cells.
#'
#' The returned object contains an additional entry
#' \code{colData(object)[[name]]}, which stores the patch ID per cell. \code{NA}
#' indicate cells that are not part of a patch.
#'
#' @section Ordering of the output object:
#' If \code{expand_by > 0}, the \code{patchDetection} function operates on individual images.
#' Therefore the returned object is grouped by entries in \code{img_id}.
#' This means all cells of a given image are grouped together in the object.
#' The ordering of cells within each individual image is the same as the ordering
#' of these cells in the input object.
#'
#' If \code{expand_by = 0}, the ordering of cells in the output object is the same as
#' in the input object.
#'
#' @return An object of \code{class(object)} containing a patch ID for each
#' cell in \code{colData(object)[[name]]}. If \code{expand_by > 0}, cells in the
#' output object are grouped by entries in \code{img_id}.
#'
#' @examples
#' library(cytomapper)
#' data(pancreasSCE)
#'
#' # Visualize cell types
#' plotSpatial(pancreasSCE,
#' img_id = "ImageNb",
#' node_color_by = "CellType",
#' scales = "free")
#'
#' # Build interaction graph
#' pancreasSCE <- buildSpatialGraph(pancreasSCE, img_id = "ImageNb",
#' type = "expansion", threshold = 20)
#'
#' # Detect patches of "celltype_B" cells
#' pancreasSCE <- patchDetection(pancreasSCE,
#' patch_cells = pancreasSCE$CellType == "celltype_B",
#' colPairName = "expansion_interaction_graph")
#'
#' plotSpatial(pancreasSCE,
#' img_id = "ImageNb",
#' node_color_by = "patch_id",
#' scales = "free")
#'
#' # Include cells in vicinity
#' pancreasSCE <- patchDetection(pancreasSCE,
#' patch_cells = pancreasSCE$CellType == "celltype_B",
#' colPairName = "expansion_interaction_graph",
#' expand_by = 20,
#' img_id = "ImageNb")
#'
#' plotSpatial(pancreasSCE,
#' img_id = "ImageNb",
#' node_color_by = "patch_id",
#' scales = "free")
#'
#' @author Tobias Hoch
#' @author adapted by Nils Eling (\email{nils.eling@@dqbm.uzh.ch})
#'
#' @references
#' \href{https://www.biorxiv.org/content/10.1101/2021.07.29.454093v1}{
#' Hoch, T. et al., Multiplexed Imaging Mass Cytometry of Chemokine Milieus in
#' Metastatic Melanoma Characterizes Features of Response to Immunotherapy.,
#' bioRxiv 2021}
#'
#' @importFrom igraph graph_from_data_frame components
#' @export
patchDetection <- function(object,
patch_cells,
colPairName,
min_patch_size = 1,
name = "patch_id",
expand_by = 0,
coords = c("Pos_X", "Pos_Y"),
convex = FALSE,
img_id = NULL,
BPPARAM = SerialParam()){
.valid.patchDetection.input(object, patch_cells, colPairName,
min_patch_size, name, expand_by, coords,
convex, img_id)
node_id <- seq_len(sum(patch_cells))
cur_graph <- graph_from_data_frame(colPair(object[,patch_cells],
colPairName),
vertices = data.frame(row.names = node_id,
id = node_id))
cur_components <- components(cur_graph)
if (length(cur_components$membership) == 0) {
stop("No connected components found.")
}
cur_clusters <- cur_components$membership
if (min_patch_size > 1) {
cur_clusters[!(cur_clusters %in%
which(cur_components$csize >= min_patch_size))] <- NA
}
cur_out <- vector(mode = "character", length = ncol(object))
cur_out[!patch_cells] <- NA
cur_out[patch_cells] <- cur_clusters
colData(object)[[name]] <- cur_out
if (expand_by > 0) {
object <- .expand_patch(object, name = name,
expand_by = expand_by,
coords = coords,
convex = convex,
img_id = img_id,
BPPARAM = BPPARAM)
message("The returned object is ordered by the '", img_id, "' entry.")
}
return(object)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.