| name | seurat |
| description | Single-cell RNA-seq analysis in R with Seurat v5 — QC, normalization (LogNormalize or SCTransform), dimensionality reduction, clustering, marker detection, integration of multiple samples, and interconversion with AnnData/scanpy. Use when single-cell work must stay in R/Bioconductor, when collaborators expect a Seurat object, or when following an R-based tutorial. For Python single-cell workflows use scanpy/anndata instead. |
Seurat (R) — single-cell RNA-seq
Overview
Seurat (Satija lab) is the dominant R toolkit for single-cell/spatial analysis. Use it
when the analysis must live in R (Bioconductor downstream, R-based collaborators, lab
convention) — otherwise [[scanpy]]/[[anndata]] in Python is the equivalent and is already
well covered in this vault. Seurat v5 introduced the layered Assay5 object and a
BPCells-backed on-disk path for very large datasets.
When to use vs scanpy
- Seurat — R/tidyverse/Bioconductor downstream, integration with
DESeq2/edgeR
pseudobulk, SingleR annotation, established lab pipelines.
- scanpy — Python ecosystem, scVI/deep models ([[scvi-tools]]), very large atlases,
AnnData-native tooling.
Convert between them rather than re-running: use sceasy, zellkonverter
(SingleCellExperiment ↔ AnnData), or SeuratDisk (.h5Seurat ↔ .h5ad).
Standard workflow
library(Seurat)
counts <- Read10X(data.dir = "filtered_feature_bc_matrix/")
obj <- CreateSeuratObject(counts, min.cells = 3, min.features = 200)
obj[["percent.mt"]] <- PercentageFeatureSet(obj, pattern = "^MT-")
VlnPlot(obj, c("nFeature_RNA", "nCount_RNA", "percent.mt"), ncol = 3)
obj <- subset(obj, nFeature_RNA > 200 & nFeature_RNA < 6000 & percent.mt < 15)
obj <- NormalizeData(obj)
obj <- FindVariableFeatures(obj, nfeatures = 2000)
obj <- ScaleData(obj)
obj <- RunPCA(obj)
ElbowPlot(obj)
obj <- FindNeighbors(obj, dims = 1:30)
obj <- FindClusters(obj, resolution = 0.5)
obj <- RunUMAP(obj, dims = 1:30)
DimPlot(obj, reduction = "umap", label = TRUE)
markers <- FindAllMarkers(obj, only.pos = TRUE, min.pct = 0.25, logfc.threshold = 0.25)
FeaturePlot(obj, c("CD3D", "MS4A1", "LYZ"))
saveRDS(obj, "obj.rds")
Integration (multiple samples / batch correction)
Seurat v5 unifies integration under IntegrateLayers. Split layers by batch first:
obj[["RNA"]] <- split(obj[["RNA"]], f = obj$sample)
obj <- NormalizeData(obj) |> FindVariableFeatures() |> ScaleData() |> RunPCA()
obj <- IntegrateLayers(obj, method = CCAIntegration,
orig.reduction = "pca",
new.reduction = "integrated.cca")
obj <- FindNeighbors(obj, reduction = "integrated.cca", dims = 1:30)
obj <- FindClusters(obj); obj RunUMAPobj reduction dims
obj JoinLayersobj
HarmonyIntegration mirrors [[harmonypy]]; RPCA is faster/more conservative than CCA
for large or weakly-overlapping datasets.
Gotchas
- v5 layers: counts/data/scale.data are now layers. After integration, call
JoinLayers() before differential expression or pseudobulk, or you'll operate per-batch.
- SCTransform + markers: run
PrepSCTFindMarkers() before FindMarkers on SCT data.
- Species mito pattern:
^MT- (human) vs ^mt- (mouse); a wrong pattern silently
yields percent.mt == 0 and bad QC.
- Pseudobulk DE beats single-cell Wilcoxon for condition contrasts: aggregate with
AggregateExpression()/Seurat::PseudobulkExpression() then hand off to [[pydeseq2]] or
edgeR. See [[de-summary]] for interpreting results.
- Memory: for >500k cells use the
BPCells on-disk backend or switch to [[scanpy]].
Related
R counterpart to [[scanpy]]/[[anndata]]; integrate with [[harmonypy]], [[scvi-tools]]
(via scVIIntegration), [[bioconductor-bridge]], and pseudobulk DE via [[pydeseq2]].