#' Run Seurat analysis
#'
#' @name runSeurat
#' @note Updated 2023-09-21.
#'
#' @inheritParams AcidRoxygen::params
#'
#' @param regressCellCycle `character(1)`.
#' - `"s-g2m-diff"`: Calculate the difference between S and G2/M phases and
#' use that to regress. See `CC.Difference` metric in Seurat vignette.
#' - `"yes"`: Regress out any effects of both S and G2/M phase variable.
#' Refer to `"S.Score"` and `"G2M.Score"` metrics in Seurat vignette.
#' - `"no"`: Don't calculate cell-cycle scoring and don't regress.
#'
#' Refer to the Seurat cell-cycle regression vignette for details.
#'
#' @param varsToRegress `character` or `NULL`.
#' Unwanted sources of variance to regress. Note that when `regressCellCycle`
#' is not `"no"`, then the corresponding cell-cycle variables are added
#' automatically. Passes to [Seurat::ScaleData] internally.
#'
#' @param dims `"auto"` or `integer`.
#' Dimensions of reduction to use as input for shared nearest neighbor (SNN)
#' graph construction. When set to "auto" (default), the elbow point is
#' calculated internally. See [plotPcElbow()] for details. Passes to
#' [Seurat::FindNeighbors()] and [Seurat::RunUMAP()] internally.
#'
#' @param resolution `numeric`.
#' Resolutions to calculate for clustering.
#' Passes to [Seurat::FindClusters()] internally.
#'
#' Currently supported:
#' - `"uwot"`, changed to default in Seurat 3.
#' Note that this sets `metric = "cosine"` automatically.
#' - `"umap-learn"`, which requires reticulate.
#' Note that this sets `metric = "correlation"` automatically.
#'
#' @param workers `"auto"`, `integer(1)`, or `NULL`.
#' Disable parallelization with future by setting to `NULL`.
#'
#' @return `Seurat`.
#'
#' @seealso
#' - https://github.com/satijalab/seurat/wiki
#' - https://satijalab.org/seurat/essential_commands.html
#' - https://satijalab.org/seurat/v3.1/cell_cycle_vignette.html
#' https://satijalab.org/seurat/v3.0/future_vignette.html
#' - https://satijalab.org/seurat/v3.1/pbmc3k_tutorial.html
NULL
## Updated 2023-09-21.
`runSeurat,Seurat` <- # nolint
function(object,
regressCellCycle = c("s-g2m-diff", "yes", "no"),
varsToRegress = c("nCount_RNA", "mitoRatio"),
dims = "auto",
resolution = seq(from = 0.2, to = 1.2, by = 0.2),
workers = "auto") {
assert(
requireNamespaces(c("Seurat", "future")),
isCharacter(varsToRegress, nullOk = TRUE),
identical(dims, "auto") || is.numeric(dims),
is.numeric(resolution),
identical(workers, "auto") || isInt(workers, nullOk = TRUE)
)
regressCellCycle <- match.arg(regressCellCycle)
## Parallelization (via future) ----------------------------------------
## Note that Seurat currently uses future package for parallelization.
## Multiprocess is currently unstable in RStudio and disabled.
if (
isTRUE(future::supportsMulticore()) &&
!is.null(workers)
) {
if (identical(workers, "auto")) {
workers <- max(getOption(x = "mc.cores", default = 1L), 1L)
}
assert(isInt(workers))
alert(sprintf(
"Enabling {.pkg %s} multiprocess with %d workers.",
"future", workers
))
future::plan("multiprocess", workers = workers)
}
## Pre-processing ------------------------------------------------------
alert(sprintf(
"{.pkg %s}::{.fun %s}",
"Seurat", "NormalizeData"
))
object <- Seurat::NormalizeData(object)
alert(sprintf(
"{.pkg %s}::{.fun %s}",
"Seurat", "FindVariableFeatures"
))
object <- Seurat::FindVariableFeatures(object)
## Cell-cycle regression -----------------------------------------------
## https://satijalab.org/seurat/v3.1/cell_cycle_vignette.html
if (!identical(regressCellCycle, "no")) {
env <- new.env()
data(
"cellCycleMarkersList",
package = "AcidSingleCell",
envir = env
)
ccm <- env[["cellCycleMarkersList"]]
organism <- camelCase(organism(object), strict = TRUE)
if (!isSubset(organism, names(ccm))) {
abort(sprintf(
fmt = paste(
"Failed to obtain cell-cycle markers.",
"{.val %s} is not currently supported.",
"Please file an issue on GitHub: {.url %s}.",
sep = "\n"
),
organism,
"https://github.com/acidgenomics/pointillism/issues"
))
}
ccm <- ccm[[organism]]
assert(is(ccm, "CellCycleMarkers"))
g2mGenes <- as.character(ccm[["g2m"]][["geneName"]])
sGenes <- as.character(ccm[["s"]][["geneName"]])
alert(sprintf(
"{.pkg %s}::{.fun %s}",
"Seurat", "CellCycleScoring"
))
object <- Seurat::CellCycleScoring(
object = object,
s.features = sGenes,
g2m.features = g2mGenes
)
}
## Update the variables to regress, including cell cycle.
if (identical(regressCellCycle, "s-g2m-diff")) {
## Note that Seurat uses non-standard '$' and '[[' methods.
object$CC.Difference <- object$S.Score - object$G2M.Score # nolint
varsToRegress <- c("CC.Difference", varsToRegress)
} else if (identical(regressCellCycle, "yes")) {
varsToRegress <- c("S.Score", "G2M.Score", varsToRegress)
}
## Scaling and projection ----------------------------------------------
alert(sprintf(
"{.pkg %s}::{.fun %s}",
"Seurat", "ScaleData"
))
dl(c("varsToRegress" = toInlineString(varsToRegress)))
## Scaling all features is very slow for large datasets.
## Current default in Seurat scales variable features only.
## All features:
## > features = rownames(object)
## Variable features only:
## > features = Seurat::VariableFeatures(object)
object <- Seurat::ScaleData(
object = object,
features = rownames(object),
vars.to.regress = varsToRegress
)
alert(sprintf(
"{.pkg %s}::{.fun %s}",
"Seurat", "RunPCA"
))
object <- Seurat::RunPCA(object)
if (identical(dims, "auto")) {
alert(sprintf("{.fun %s}", "plotElbow"))
p <- plotPcElbow(object)
elbow <- attr(p, "elbow")
dims <- seq(from = 1L, to = elbow, by = 1L)
}
## Clustering ----------------------------------------------------------
alert(sprintf(
"{.pkg %s}::{.fun %s}",
"Seurat", "FindNeighbors"
))
alertInfo(sprintf("Using %d dims,", length(dims)))
object <- Seurat::FindNeighbors(object, dims = dims)
alert(sprintf(
"{.pkg %s}::{.fun %s}",
"Seurat", "FindClusters"
))
dl(c("resolution" = as.character(resolution)))
object <- Seurat::FindClusters(object, resolution = resolution)
## tSNE / UMAP ---------------------------------------------------------
alert(sprintf(
"{.pkg %s}::{.fun %s}",
"Seurat", "RunTSNE"
))
object <- Seurat::RunTSNE(
object = object,
tsne.method = "Rtsne"
)
alert(sprintf(
"{.pkg %s}::{.fun %s}",
"Seurat", "RunUMAP"
))
alertInfo(paste("Using", length(dims), "dims."))
object <- Seurat::RunUMAP(
object = object,
umap.method = "uwot",
metric = "cosine",
dims = dims
)
alertSuccess("Seurat run was successful.")
object
}
## Updated 2020-06-26.
`runSeurat,SCE` <- # nolint
function(object, ...) {
object <- as(object, "SingleCellExperiment")
object <- convertGenesToSymbols(object)
object <- as(object, "Seurat")
runSeurat(object, ...)
}
#' @rdname runSeurat
#' @export
setMethod(
f = "runSeurat",
signature = signature(object = "Seurat"),
definition = `runSeurat,Seurat`
)
#' @rdname runSeurat
#' @export
setMethod(
f = "runSeurat",
signature = signature(object = "SingleCellExperiment"),
definition = `runSeurat,SCE`
)
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.