Skip to contents

Normalize, find variable features, scale, reduce dimensions, and cluster a Seurat object. workflow = "spatial" adds spot QC, spatial variable features, optional BayesSpace clustering, and optional deconvolution. It is not a multi-slice integration orchestrator.

Objects that also contain a ChromatinAssay are preprocessed sequentially (default assay, then chromatin).

Usage

RunStandardWorkflow(
  srt,
  prefix = "Standard",
  workflow = c("single_cell", "spatial"),
  assay = NULL,
  image = NULL,
  coord.cols = c("x", "y"),
  do_spot_qc = TRUE,
  spot_qc_params = list(),
  do_spatial_variable_features = TRUE,
  spatial_variable_features_params = list(),
  do_spatial_cluster = FALSE,
  spatial_cluster_method = "BayesSpace",
  spatial_q = NULL,
  bayesspace_params = list(),
  reference = NULL,
  reference_label = NULL,
  reference_assay = NULL,
  do_deconvolution = !is.null(reference),
  deconvolution_method = "RCTD",
  deconvolution_params = list(),
  do_normalization = NULL,
  normalization_method = "LogNormalize",
  do_HVF_finding = TRUE,
  HVF_method = "vst",
  nHVF = 2000,
  HVF = NULL,
  do_scaling = TRUE,
  vars_to_regress = NULL,
  regression_model = "linear",
  linear_reduction = "pca",
  linear_reduction_dims = 50,
  linear_reduction_dims_use = NULL,
  linear_reduction_params = list(),
  force_linear_reduction = FALSE,
  nonlinear_reduction = "umap",
  nonlinear_reduction_dims = 2,
  nonlinear_reduction_params = list(),
  force_nonlinear_reduction = TRUE,
  neighbor_metric = "euclidean",
  neighbor_k = 20L,
  cluster_algorithm = "louvain",
  cluster_resolution = 0.6,
  cores = 1L,
  verbose = TRUE,
  seed = 11,
  ...
)

Arguments

srt

A Seurat object.

prefix

Prefix for intermediate object names.

workflow

"single_cell" or "spatial" (basic single-image Visium-style).

assay

Assay to use. NULL uses the default assay.

image

Spatial image name. Required when multiple images are present; a single image is selected automatically when NULL.

coord.cols

Metadata coordinate columns used when no image is available.

do_spot_qc, spot_qc_params

Run RunSpotQC() and extra arguments.

do_spatial_variable_features, spatial_variable_features_params

Run RunSpatialVariableFeatures(). The workflow defaults set_variable_features = FALSE so expression HVFs are kept.

do_spatial_cluster, spatial_cluster_method, spatial_q, bayesspace_params

Spatial clustering. Only "BayesSpace" is supported. spatial_q = NULL uses the number of ordinary spot clusters.

reference, reference_label, reference_assay

Optional single-cell reference for deconvolution.

do_deconvolution, deconvolution_method, deconvolution_params

Deconvolution ("RCTD", "SPOTlight", or "Cell2location"). NULL runs when reference or cell2location signatures are provided.

do_normalization, normalization_method

Normalize if the assay has no scaled data (NULL). One of "LogNormalize", "SCT", "TFIDF", "scran". "SCT" switches downstream steps to the "SCT" assay.

do_HVF_finding, HVF_method, nHVF, HVF

Highly variable features. HVF_method is "vst", "mvp", "disp", or "scran".

do_scaling

Force scaling via ScaleData.

vars_to_regress

Regressors used in scaling. NULL uses none.

regression_model

"linear", "poisson", or "negativebinomial".

linear_reduction, linear_reduction_dims, linear_reduction_dims_use, linear_reduction_params, force_linear_reduction

Linear reduction ("pca", "svd", "ica", "nmf", "mds", "glmpca"). linear_reduction_dims_use = NULL uses estimated dimensions, else the first 50.

nonlinear_reduction, nonlinear_reduction_dims, nonlinear_reduction_params, force_nonlinear_reduction

Nonlinear reduction ("umap", "umap-naive", "tsne", "dm", "phate", "pacmap", "trimap", "largevis", "fr").

neighbor_metric, neighbor_k

Neighbor graph ("euclidean", "cosine", "manhattan", "hamming").

cluster_algorithm, cluster_resolution

Clustering ("louvain", "slm", "leiden"). Larger cluster_resolution yields fewer clusters.

cores

Number of CPU cores.

verbose

Whether to print the message. Default is TRUE.

seed

Random seed.

...

Additional arguments passed to reduction methods.

Value

A Seurat object. Spatial workflows store per-stage state in srt@tools[["run_standard_spatial_workflow"]], including the effective set_variable_features value. A failed stage signals an error with the same table in attribute standard_spatial_stages.

Examples

library(Matrix)
data(pancreas_sub)
pancreas_sub <- RunStandardWorkflow(pancreas_sub)
#>  [2026-08-30 05:43:11] Start standard processing workflow...
#>  [2026-08-30 05:43:11] Checking a list of <Seurat>...
#> ! [2026-08-30 05:43:11] Data 1/1 of the `srt_list` is "unknown"
#> Warning: Data 1/1 of the `srt_list` is "unknown"
#>  [2026-08-30 05:43:11] Perform `NormalizeData()` with `normalization.method = 'LogNormalize'` on 1/1 of `srt_list`...
#>  [2026-08-30 05:43:11] Perform `FindVariableFeatures()` on 1/1 of `srt_list`...
#>  [2026-08-30 05:43:12] Use the separate HVF from `srt_list`
#>  [2026-08-30 05:43:12] Number of available HVF: 2000
#>  [2026-08-30 05:43:12] Finished check
#>  [2026-08-30 05:43:12] Perform `ScaleData()`
#>  [2026-08-30 05:43:12] Perform pca linear dimension reduction
#>  [2026-08-30 05:43:12] Use stored estimated dimensions 1:23 for Standardpca
#>  [2026-08-30 05:43:13] Perform `Seurat::FindClusters()` with `cluster_algorithm = 'louvain'` and `cluster_resolution = 0.6`
#>  [2026-08-30 05:43:13] Reorder clusters...
#>  [2026-08-30 05:43:13] Skip `log1p()` because `layer = data` is not "counts"
#>  [2026-08-30 05:43:13] Perform umap nonlinear dimension reduction
#>  [2026-08-30 05:43:22] Standard processing workflow completed
CellDimPlot(
  pancreas_sub,
  group.by = "SubCellType"
)


# Use a combination of different linear
# or nonlinear dimension reduction methods
linear_reductions <- c(
  "pca", "nmf", "mds"
)
pancreas_sub <- RunStandardWorkflow(
  pancreas_sub,
  linear_reduction = linear_reductions,
  nonlinear_reduction = "umap"
)
#>  [2026-08-30 05:43:22] Start standard processing workflow...
#>  [2026-08-30 05:43:22] Checking a list of <Seurat>...
#>  [2026-08-30 05:43:23] Data 1/1 of the `srt_list` has been log-normalized
#>  [2026-08-30 05:43:23] Perform `FindVariableFeatures()` on 1/1 of `srt_list`...
#>  [2026-08-30 05:43:23] Use the separate HVF from `srt_list`
#>  [2026-08-30 05:43:23] Number of available HVF: 2000
#>  [2026-08-30 05:43:23] Finished check
#>  [2026-08-30 05:43:23] Perform `ScaleData()`
#>  [2026-08-30 05:43:23] Perform pca linear dimension reduction
#>  [2026-08-30 05:43:23] Use stored estimated dimensions 1:23 for Standardpca
#>  [2026-08-30 05:43:24] Perform `Seurat::FindClusters()` with `cluster_algorithm = 'louvain'` and `cluster_resolution = 0.6`
#>  [2026-08-30 05:43:24] Reorder clusters...
#>  [2026-08-30 05:43:24] Skip `log1p()` because `layer = data` is not "counts"
#>  [2026-08-30 05:43:24] Perform umap nonlinear dimension reduction
#> Warning: Key ‘StandardpcaUMAP2D_’ taken, using ‘standardpcaumap2d_’ instead
#>  [2026-08-30 05:43:33] Perform nmf linear dimension reduction
#>  [2026-08-30 05:43:33] Running NMF...
#>  StandardBE_ 1 
#>  Positive:  Ccnd1, Spp1, Eno1, Rps2, Mdk, Ldha, Pebp1, Mif, Gapdh, Prdx1 
#>  	   Cd24a, Krt8, Dbi, Aldoa, Cldn10, Rplp1, Mgst1, Npm1, Ybx1, Tkt 
#>  	   Hspe1, Ptma, Rpl12, Clu, Wfdc2, Sox9, Vim, Rpl22l1, Krt18, Tmsb10 
#>  Negative:  Tmem108, Poc1a, Epn3, Wipi1, Tmcc3, Fgf12, Tecpr2, Zbtb4, Plekho1, Slc25a10 
#>  	   Gm10941, Trf, Man1c1, Hmgcs1, Nipal1, Jam3, Pgap1, Alpl, Tnr, Kcnip3 
#>  	   Gm15915, Rbp2, Cbfa2t2, Sh2d4a, Megf6, Prkcb, Naaladl2, Fam46d, Hist2h2ac, Tox2 
#>  StandardBE_ 2 
#>  Positive:  Spp1, Atp1b1, Id2, Vim, Sparc, Dbi, Rps2, Mgst1, Gsta3, Rpl22l1 
#>  	   Acot1, Anxa2, 1700011H14Rik, Sox9, Rplp1, Bicc1, Adamts1, Rps12, Nudt19, Cldn3 
#>  	   Pdzk1ip1, Ppp1r1b, Rpl36a, Rpl12, Ifitm2, Jun, Ptn, S100a10, Mdk, Mt1 
#>  Negative:  Aacs, Tmem108, Poc1a, Epn3, B830012L14Rik, Tmcc3, Rfc1, Wsb1, Tecpr2, Zbtb4 
#>  	   Plekho1, Ppp2r2b, Haus8, Trf, Gm5420, Man1c1, Hmgcs1, Nipal1, Jam3, Tcerg1 
#>  	   Pgap1, Alpl, Larp1b, Tnr, Kcnip3, Lsm12, Ptbp3, Gm15915, Cntln, Rbp2 
#>  StandardBE_ 3 
#>  Positive:  Clu, Mt1, Spp1, Krt18, Mt2, Muc1, Gsta3, Cldn3, Mgst1, Sparc 
#>  	   Ttr, Serpinh1, Aldoa, Tpi1, H19, Dbi, Epcam, Mif, Pdzk1ip1, Gapdh 
#>  	   Prdx1, Cat, Ambp, Ldha, Ifitm2, Krt8, Csrp2, Anxa2, Rps2, Tmsb10 
#>  Negative:  Rpa3, Aacs, Tmem108, Poc1a, Nop56, Wipi1, Tmcc3, Trib1, Rrp15, Fgfrl1 
#>  	   Nhsl1, Fgf12, Lama1, Slc20a1, Tecpr2, Zbtb4, Plekho1, Ppp2r2b, Haus8, Gm10941 
#>  	   Trf, Gm5420, Man1c1, Hmgcs1, Nipal1, Jam3, Tcerg1, Snrpa1, Alpl, Larp1b 
#>  StandardBE_ 4 
#>  Positive:  Cck, Tmsb4x, Mdk, Gadd45a, Selm, Ppp1r14a, Sox4, Btbd17, Cotl1, Ppp3ca 
#>  	   Sh3bgrl3, Jun, Ifitm2, Rps2, Tubb3, Rplp1, Igfbpl1, Ptma, Calr, Sult2b1 
#>  	   Hn1, Lrpap1, Rps12, Smarcd2, Nkx6-1, Rpl36a, Neurog3, Neurod2, Gnas, Rpl12 
#>  Negative:  Elovl6, Tmem108, Poc1a, Epn3, Nop56, Wipi1, B830012L14Rik, Atic, Rrp15, Rfc1 
#>  	   Fgf12, Lama1, Slc20a1, Tecpr2, Ppp2r2b, Eif1ax, Slc25a10, Fam162a, P4ha3, Gm10941 
#>  	   Tenm4, Pde4b, Gm5420, Man1c1, Hmgcs1, Pgap1, Mgst2, Larp1b, Tnr, Kcnip3 
#>  StandardBE_ 5 
#>  Positive:  Spp1, Tmsb4x, Cyr61, Krt18, Tpm1, Krt8, Myl12a, Anxa5, Csrp1, Tnfrsf12a 
#>  	   Vim, Krt19, Jun, Anxa2, Tagln2, Nudt19, Sparc, Cldn7, Tmsb10, Clu 
#>  	   Myl12b, S100a10, Cd24a, Rps2, Myl9, Klf6, Cldn3, Lurap1l, Dbi, Rplp1 
#>  Negative:  Elovl6, Aacs, Tmem108, Poc1a, Tmcc3, Rfc1, Nhsl1, Fgf12, Lama1, Slc20a1 
#>  	   Tecpr2, Plekho1, Ppp2r2b, Slc25a10, Fam162a, Gm10941, Tenm4, Man1c1, Nipal1, Jam3 
#>  	   Pgap1, Alpl, Tnr, Kcnip3, Ptbp3, Gm15915, Cntln, Ocln, Blvrb, Fras1 
#>  [2026-08-30 05:43:50] NMF compute completed
#>  [2026-08-30 05:43:50] Use stored estimated dimensions 1:50 for Standardnmf
#>  [2026-08-30 05:43:50] Perform `Seurat::FindClusters()` with `cluster_algorithm = 'louvain'` and `cluster_resolution = 0.6`
#>  [2026-08-30 05:43:50] Reorder clusters...
#>  [2026-08-30 05:43:50] Skip `log1p()` because `layer = data` is not "counts"
#>  [2026-08-30 05:43:50] Perform umap nonlinear dimension reduction
#>  [2026-08-30 05:43:59] Perform mds linear dimension reduction
#> Error in RunDimsEstimate(srt = srt, reduction = paste0(prefix, linear_reduction),     reduction_method = linear_reduction, use_stored = FALSE,     verbose = FALSE): No valid dimensions can be estimated for Standardmds
plist1 <- lapply(
  linear_reductions, function(lr) {
    CellDimPlot(
      pancreas_sub,
      group.by = "SubCellType",
      reduction = paste0(
        "Standard", lr, "UMAP2D"
      ),
      xlab = "", ylab = "",
      title = paste0(lr, "_umap"),
      legend.position = "none",
      theme_use = "theme_blank"
    )
  }
)
patchwork::wrap_plots(plist1)


nonlinear_reductions <- c(
  "umap", "tsne", "fr"
)
pancreas_sub <- RunStandardWorkflow(
  pancreas_sub,
  linear_reduction = "pca",
  nonlinear_reduction = nonlinear_reductions
)
#>  [2026-08-30 05:44:00] Start standard processing workflow...
#>  [2026-08-30 05:44:00] Checking a list of <Seurat>...
#>  [2026-08-30 05:44:01] Data 1/1 of the `srt_list` has been log-normalized
#>  [2026-08-30 05:44:01] Perform `FindVariableFeatures()` on 1/1 of `srt_list`...
#>  [2026-08-30 05:44:01] Use the separate HVF from `srt_list`
#>  [2026-08-30 05:44:01] Number of available HVF: 2000
#>  [2026-08-30 05:44:01] Finished check
#>  [2026-08-30 05:44:01] Perform `ScaleData()`
#>  [2026-08-30 05:44:01] Perform pca linear dimension reduction
#>  [2026-08-30 05:44:01] Use stored estimated dimensions 1:23 for Standardpca
#>  [2026-08-30 05:44:02] Perform `Seurat::FindClusters()` with `cluster_algorithm = 'louvain'` and `cluster_resolution = 0.6`
#>  [2026-08-30 05:44:02] Reorder clusters...
#>  [2026-08-30 05:44:02] Skip `log1p()` because `layer = data` is not "counts"
#>  [2026-08-30 05:44:02] Perform umap nonlinear dimension reduction
#> Warning: Key ‘StandardpcaUMAP2D_’ taken, using ‘standardpcaumap2d_’ instead
#>  [2026-08-30 05:44:11] Perform tsne nonlinear dimension reduction
#>  [2026-08-30 05:44:11] Perform tsne nonlinear dimension reduction using Standardpca (1:23)
#>  [2026-08-30 05:44:13] Perform fr nonlinear dimension reduction
#>  [2026-08-30 05:44:13] Perform fr nonlinear dimension reduction using Standardpca_SNN
#>  [2026-08-30 05:44:14] Standard processing workflow completed
plist2 <- lapply(
  nonlinear_reductions, function(nr) {
    CellDimPlot(
      pancreas_sub,
      group.by = "SubCellType",
      reduction = paste0(
        "Standardpca", nr, "2D"
      ),
      xlab = "", ylab = "",
      title = paste0("pca_", nr),
      legend.position = "none",
      theme_use = "theme_blank"
    )
  }
)
patchwork::wrap_plots(plist2)


data(visium_human_pancreas_sub)
spatial <- RunStandardWorkflow(
  visium_human_pancreas_sub,
  workflow = "spatial",
  assay = "Spatial",
  do_spatial_cluster = FALSE,
  spatial_cluster_method = "BayesSpace",
  do_deconvolution = FALSE,
  deconvolution_method = "RCTD",
  linear_reduction_dims = 10,
  linear_reduction_dims_use = 1:5,
  nonlinear_reduction_dims = 2,
  spatial_variable_features_params = list(nfeatures = 50)
)
#>  [2026-08-30 05:44:15] Start standard spot-level spatial workflow...
#>  [2026-08-30 05:44:15] Running spot-level quality control
#>  [2026-08-30 05:44:15] 1907 spots passed QC and 79 spots failed QC
#>  [2026-08-30 05:44:15] Start standard processing workflow...
#>  [2026-08-30 05:44:15] Checking a list of <Seurat>...
#> ! [2026-08-30 05:44:15] Data 1/1 of the `srt_list` is "unknown"
#> Warning: Data 1/1 of the `srt_list` is "unknown"
#>  [2026-08-30 05:44:15] Perform `NormalizeData()` with `normalization.method = 'LogNormalize'` on 1/1 of `srt_list`...
#>  [2026-08-30 05:44:15] Perform `FindVariableFeatures()` on 1/1 of `srt_list`...
#>  [2026-08-30 05:44:15] Use the separate HVF from `srt_list`
#>  [2026-08-30 05:44:15] Number of available HVF: 2000
#>  [2026-08-30 05:44:15] Finished check
#>  [2026-08-30 05:44:15] Perform `ScaleData()`
#>  [2026-08-30 05:44:15] Perform pca linear dimension reduction
#>  [2026-08-30 05:44:17] Perform `Seurat::FindClusters()` with `cluster_algorithm = 'louvain'` and `cluster_resolution = 0.6`
#>  [2026-08-30 05:44:17] Reorder clusters...
#>  [2026-08-30 05:44:17] Skip `log1p()` because `layer = data` is not "counts"
#>  [2026-08-30 05:44:17] Perform umap nonlinear dimension reduction
#>  [2026-08-30 05:44:27] Standard processing workflow completed
#>  [2026-08-30 05:44:27] Running spatial variable feature detection
#>  [2026-08-30 05:44:27] Stored 50 spatial variable features
#>  [2026-08-30 05:44:27] Standard spot-level spatial workflow completed
SpatialSpotPlot(spatial, group.by = "SpotQC")

SpatialSpotPlot(
  spatial,
  features = spatial@tools[["SpatialVariableFeatures"]]$summary$top_features[1:2]
)


spatial_bayes <- RunStandardWorkflow(
  visium_human_pancreas_sub,
  workflow = "spatial",
  assay = "Spatial",
  do_spatial_cluster = TRUE,
  spatial_cluster_method = "BayesSpace",
  spatial_q = 3,
  do_deconvolution = FALSE,
  deconvolution_method = "RCTD",
  bayesspace_params = list(
    n.PCs = 5,
    n.HVGs = 200,
    store_sce = FALSE,
    spatial_cluster_params = list(
      nrep = 200,
      burn.in = 50,
      thin = 10,
      save.chain = FALSE
    )
  )
)
#>  [2026-08-30 05:44:28] Start standard spot-level spatial workflow...
#>  [2026-08-30 05:44:28] Running spot-level quality control
#>  [2026-08-30 05:44:28] 1907 spots passed QC and 79 spots failed QC
#>  [2026-08-30 05:44:28] Start standard processing workflow...
#>  [2026-08-30 05:44:28] Checking a list of <Seurat>...
#> ! [2026-08-30 05:44:28] Data 1/1 of the `srt_list` is "unknown"
#> Warning: Data 1/1 of the `srt_list` is "unknown"
#>  [2026-08-30 05:44:28] Perform `NormalizeData()` with `normalization.method = 'LogNormalize'` on 1/1 of `srt_list`...
#>  [2026-08-30 05:44:28] Perform `FindVariableFeatures()` on 1/1 of `srt_list`...
#>  [2026-08-30 05:44:28] Use the separate HVF from `srt_list`
#>  [2026-08-30 05:44:28] Number of available HVF: 2000
#>  [2026-08-30 05:44:28] Finished check
#>  [2026-08-30 05:44:28] Perform `ScaleData()`
#>  [2026-08-30 05:44:28] Perform pca linear dimension reduction
#>  [2026-08-30 05:44:29] Use stored estimated dimensions 1:30 for Standardpca
#>  [2026-08-30 05:44:30] Perform `Seurat::FindClusters()` with `cluster_algorithm = 'louvain'` and `cluster_resolution = 0.6`
#>  [2026-08-30 05:44:30] Reorder clusters...
#>  [2026-08-30 05:44:30] Skip `log1p()` because `layer = data` is not "counts"
#>  [2026-08-30 05:44:31] Perform umap nonlinear dimension reduction
#>  [2026-08-30 05:44:40] Standard processing workflow completed
#>  [2026-08-30 05:44:40] Running spatial variable feature detection
#>  [2026-08-30 05:44:41] Stored 2000 spatial variable features
#>  [2026-08-30 05:44:41] Convert <Seurat> to <SingleCellExperiment> for BayesSpace
#>  [2026-08-30 05:44:41] Run BayesSpace spatial clustering with `q = 3`
#> Neighbors were identified for 1962 out of 1986 spots.
#> Fitting model...
#> Calculating labels using iterations 51 through 200.
#>  [2026-08-30 05:44:47] BayesSpace clusters stored in metadata column "BayesSpace_cluster"
#>  [2026-08-30 05:44:47] Standard spot-level spatial workflow completed
SpatialSpotPlot(spatial_bayes, group.by = "BayesSpace_cluster")