Skip to content
Back to skills

Seurat

ASecurity

scRNA-seq analysis with Seurat v5 (R) — the standard R-based pipeline. Covers QC, normalization (LogNormalize + SCTransform), HVG selection, scaling, PCA, neighbors, leiden/Louvain clustering, UMAP/t-SNE, marker gene identification (FindMarkers / FindAllMarkers), and visualization (DimPlot / FeaturePlot / VlnPlot / DotPlot / DoHeatmap). Multi-sample integration via Seurat v5's IntegrateLayers — CCA, RPCA, Harmony, FastMNN, or scVI. Optional dependencies (presto, BPCells, glmGamPoi) substantia...

  • 97 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 6, 2026
devopspythongoexpressgitapibackendperformance

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 6 files and shows the line behind each finding

Scanned September 6, 2026

npx -y skills add swaruplab/operon --skill seurat --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Seurat?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Seurat
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/swaruplab-seurat/badge)](https://www.skillsdirectory.com/skills/swaruplab-seurat)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: seurat
description: scRNA-seq analysis with Seurat v5 (R) — the standard R-based pipeline. Covers QC, normalization (LogNormalize + SCTransform), HVG selection, scaling, PCA, neighbors, leiden/Louvain clustering, UMAP/t-SNE, marker gene identification (FindMarkers / FindAllMarkers), and visualization (DimPlot / FeaturePlot / VlnPlot / DotPlot / DoHeatmap). Multi-sample integration via Seurat v5's IntegrateLayers — CCA, RPCA, Harmony, FastMNN, or scVI. Optional dependencies (presto, BPCells, glmGamPoi) substantially speed up large datasets.
license: MIT
metadata:
---

# Seurat v5: scRNA-seq Analysis in R

## Overview

[Seurat](https://satijalab.org/seurat/) is the de facto R-based scRNA-seq pipeline from the Satija Lab. It handles the full workflow from filtered count matrices through clustering and marker analysis, plus multi-sample integration, multimodal data (CITE-seq), and integration with downstream tools like Azimuth (label transfer), Signac (chromatin), and SeuratWrappers (additional integration methods).

**Seurat v5** (released 2023, current as of v5.x) introduces a few important architectural shifts from v4:

1. **Layers** — assays are split into named layers (e.g. `counts`, `data`, `scale.data`), and integration happens across layers rather than across separate objects.
2. **`IntegrateLayers()`** — one call replaces the v4 `SelectIntegrationFeatures → FindIntegrationAnchors → IntegrateData` chain. Supports CCA, RPCA, Harmony, FastMNN, and scVI through a single API.
3. **BPCells backend** — out-of-memory matrices for atlas-scale datasets (millions of cells on modest RAM).
4. **`presto`** — accelerated `FindAllMarkers` (10-100× faster).

## When to Use This Skill

- Standard R-based scRNA-seq analysis from filtered 10X matrices, h5, or count tables
- Multi-sample / multi-condition integration where you want canonical anchor-based or Harmony/scVI integration in R
- CITE-seq / multimodal analysis (Seurat's WNN — weighted nearest neighbors)
- Cell-type annotation via Azimuth (Satija Lab's reference atlas) or manual markers
- Workflows that need to integrate with the broader R/Bioconductor ecosystem (deseq2, hdwgcna, cellchat)

**Not for**:
- Pure Python ecosystems — use `scanpy`
- ATAC-seq — use `archr` or `snapatac2`
- Spatial transcriptomics — use `spatial-transcriptomics` protocol
- Atlas-scale (≥ 5M cells) with limited RAM — even with BPCells, scVI / scanpy in Python tend to scale better

## Prerequisites

- R ≥ 4.0 (R ≥ 4.3 recommended)
- ~32 GB RAM for ~100k cells; ~64-128 GB for ~500k+ (lower with BPCells)
- Linux / macOS preferred for performance; Windows works for analysis

### Installation

```r
# Core Seurat
install.packages('Seurat')
library(Seurat)
packageVersion('Seurat')   # check you're on v5.x

# Strongly-recommended performance dependencies
setRepositories(ind = 1:3, addURLs = c(
  'https://satijalab.r-universe.dev',
  'https://bnprks.r-universe.dev/'
))
install.packages(c("BPCells", "presto", "glmGamPoi"))

# Optional companion packages
install.packages('Signac')                                       # chromatin
remotes::install_github("satijalab/seurat-data",    quiet = TRUE)
remotes::install_github("satijalab/azimuth",        quiet = TRUE)
remotes::install_github("satijalab/seurat-wrappers", quiet = TRUE)

# Integration backends used by IntegrateLayers
install.packages('harmony')
BiocManager::install('batchelor')                                # FastMNN
# scVI integration needs a separate conda env — see Integration section
```

## Quick Start — Standard Single-Sample Pipeline

This is the PBMC 3K tutorial in compressed form. Substitute your own data path.

```r
library(Seurat)
library(dplyr)
library(patchwork)
set.seed(1)

# ── 1. Load data ────────────────────────────────────────────────────────────
# From cellranger (10X) — directory of barcodes/features/matrix.mtx.gz
pbmc.data <- Read10X(data.dir = "/path/to/filtered_feature_bc_matrix/")
# Or from h5: Read10X_h5("filtered_feature_bc_matrix.h5")

pbmc <- CreateSeuratObject(
  counts       = pbmc.data,
  project      = "pbmc3k",
  min.cells    = 3,         # gene must be in ≥ 3 cells
  min.features = 200        # cell must have ≥ 200 features
)

# ── 2. QC ───────────────────────────────────────────────────────────────────
pbmc[["percent.mt"]] <- PercentageFeatureSet(pbmc, pattern = "^MT-")
# (For mouse: pattern = "^mt-"; for nuclei: include ribosomal too with "^Rp[ls]")

VlnPlot(pbmc, features = c("nFeature_RNA", "nCount_RNA", "percent.mt"), ncol = 3)
FeatureScatter(pbmc, feature1 = "nCount_RNA", feature2 = "percent.mt")
FeatureScatter(pbmc, feature1 = "nCount_RNA", feature2 = "nFeature_RNA")

pbmc <- subset(pbmc, subset = nFeature_RNA > 200 &
                              nFeature_RNA < 2500 &
                              percent.mt   < 5)

# ── 3. Normalization + HVG ─────────────────────────────────────────────────
pbmc <- NormalizeData(pbmc, normalization.method = "LogNormalize", scale.factor = 10000)
pbmc <- FindVariableFeatures(pbmc, selection.method = "vst", nfeatures = 2000)

# Alternative: SCTransform (better for low-depth / variable-depth data)
# pbmc <- SCTransform(pbmc, vars.to.regress = "percent.mt", verbose = FALSE)

# ── 4. Scale + PCA ─────────────────────────────────────────────────────────
pbmc <- ScaleData(pbmc, features = rownames(pbmc))
pbmc <- RunPCA(pbmc, features = VariableFeatures(object = pbmc))

ElbowPlot(pbmc, ndims = 50)     # pick n_pcs from the elbow

# ── 5. Neighbors + clusters + UMAP ─────────────────────────────────────────
pbmc <- FindNeighbors(pbmc, dims = 1:10)
pbmc <- FindClusters(pbmc, resolution = 0.5)
pbmc <- RunUMAP(pbmc, dims = 1:10)

DimPlot(pbmc, reduction = "umap", label = TRUE)

# ── 6. Marker genes ─────────────────────────────────────────────────────────
# All clusters at once — fast with presto installed
markers <- FindAllMarkers(pbmc, only.pos = TRUE,
                           min.pct = 0.25,
                           logfc.threshold = 0.25)

# Top 5 markers per cluster
markers %>% group_by(cluster) %>% slice_max(n = 5, order_by = avg_log2FC)

# Specific pairwise comparison
clust5_vs_03 <- FindMarkers(pbmc, ident.1 = 5, ident.2 = c(0, 3))

# ── 7. Visualize markers ───────────────────────────────────────────────────
VlnPlot(pbmc, features = c("MS4A1", "CD79A"))                       # B-cell markers
FeaturePlot(pbmc, features = c("CD3D", "MS4A1", "CD14", "LYZ"))     # canonical PBMC
DoHeatmap(pbmc, features = markers %>% group_by(cluster) %>%
                            slice_max(n = 10, order_by = avg_log2FC) %>%
                            pull(gene)) + NoLegend()

# ── 8. Cell-type annotation ────────────────────────────────────────────────
new.cluster.ids <- c("Naive CD4 T", "CD14+ Mono", "Memory CD4 T", "B", "CD8 T",
                      "FCGR3A+ Mono", "NK", "DC", "Platelet")
names(new.cluster.ids) <- levels(pbmc)
pbmc <- RenameIdents(pbmc, new.cluster.ids)
DimPlot(pbmc, reduction = "umap", label = TRUE, pt.size = 0.5) + NoLegend()

# ── 9. Save ─────────────────────────────────────────────────────────────────
saveRDS(pbmc, "pbmc3k_final.rds")
```

Convenience: `Rscript scripts/build_seurat.R --input data/filtered_feature_bc_matrix --out pbmc.rds`.

Source: [PBMC 3K tutorial](https://satijalab.org/seurat/articles/pbmc3k_tutorial).

---

## Multi-Sample Integration — Seurat v5

The v5 way: keep everything in one Seurat object, split the RNA assay into per-sample layers, run preprocessing on the joined object, then `IntegrateLayers()`.

```r
library(Seurat)

# Assume `obj` is a Seurat object with sample membership in obj$Method (or any column)
obj[["RNA"]] <- split(obj[["RNA"]], f = obj$Method)

# Standard preprocessing on the now-layered object
obj <- NormalizeData(obj)
obj <- FindVariableFeatures(obj)
obj <- ScaleData(obj)
obj <- RunPCA(obj)

# Single-line integration — pick a method
obj <- IntegrateLayers(
  object         = obj,
  method         = CCAIntegration,         # one of: CCAIntegration | RPCAIntegration | HarmonyIntegration | FastMNNIntegration | scVIIntegration
  orig.reduction = "pca",
  new.reduction  = "integrated.cca",
  verbose        = FALSE
)

# Re-cluster / re-UMAP on the integrated embedding
obj <- FindNeighbors(obj, reduction = "integrated.cca", dims = 1:30)
obj <- FindClusters (obj, resolution = 1)
obj <- RunUMAP     (obj, dims = 1:30, reduction = "integrated.cca")

# Rejoin layers for downstream (DE on the integrated object)
obj[["RNA"]] <- JoinLayers(obj[["RNA"]])
```

### Choosing an integration method

| Method | When |
|---|---|
| `CCAIntegration` | Default, well-tested. Good for balanced batches. |
| `RPCAIntegration` | Faster than CCA, recommended when batches are very different. |
| `HarmonyIntegration` | Fast, scalable. Most popular for large cohorts. |
| `FastMNNIntegration` | When you need mutual-nearest-neighbor logic. |
| `scVIIntegration` | Deep VAE; best for very heterogeneous / large datasets. Needs a separate conda environment. |

### SCTransform path

```r
obj[["RNA"]] <- split(obj[["RNA"]], f = obj$Method)
obj <- SCTransform(obj)
obj <- RunPCA(obj)

obj <- IntegrateLayers(
  object               = obj,
  method               = CCAIntegration,
  normalization.method = "SCT",
  verbose              = FALSE
)

obj <- FindNeighbors(obj, reduction = "integrated.dr", dims = 1:30)
obj <- FindClusters (obj, resolution = 0.6)
obj <- RunUMAP     (obj, dims = 1:30, reduction = "integrated.dr")

# IMPORTANT: SCT residuals are per-sample; recompute before DE
obj <- PrepSCTFindMarkers(obj)
```

Source: [v5 integration](https://satijalab.org/seurat/articles/seurat5_integration). For the v4 anchor-based workflow + when each style applies, see [references/integration.md](references/integration.md).

---

## Visualization Cookbook

The 7 core plotting functions and when to use each:

```r
# DimPlot — UMAP / t-SNE / PCA scatter (cluster colors)
DimPlot(pbmc, reduction = "umap", label = TRUE, group.by = "seurat_clusters")
DimPlot(pbmc, reduction = "umap", split.by = "condition")    # side-by-side per condition

# FeaturePlot — gene expression on UMAP
FeaturePlot(pbmc, features = c("CD3D", "MS4A1"),
             min.cutoff = "q10", max.cutoff = "q90")          # clip outliers via quantile
FeaturePlot(pbmc, features = c("CD4", "CD8A"), blend = TRUE)   # co-expression

# VlnPlot — per-cluster violin distributions
VlnPlot(pbmc, features = c("MS4A1", "CD79A"))
VlnPlot(pbmc, features = "MS4A1", split.by = "condition")     # per-cluster × per-condition

# RidgePlot — same content as VlnPlot, ridge style
RidgePlot(pbmc, features = c("CD3D", "MS4A1"), ncol = 2)

# DotPlot — many markers × many clusters
DotPlot(pbmc, features = c("CD3D", "MS4A1", "CD14", "NKG7")) + RotatedAxis()

# DoHeatmap — single-cell heatmap, downsampled for speed
DoHeatmap(subset(pbmc, downsample = 100), features = top10_markers, size = 3) + NoLegend()

# FeatureScatter — two features against each other
FeatureScatter(pbmc, feature1 = "LYZ", feature2 = "CCL5")

# Helpers
NoLegend()                                            # remove legend
NoAxes()                                              # remove axes
DarkTheme()                                           # dark background
LabelClusters(plot = p, id = "ident")                 # label clusters in-place
LabelPoints(plot = plot1, points = top10, repel = TRUE)
HoverLocator(plot = p)                                # interactive tooltips
```

Combine with patchwork:
```r
plot1 + plot2                              # side by side
plot1 / plot2                              # stacked
(plot1 + plot2) & NoLegend()               # apply NoLegend to both
```

See [references/visualization.md](references/visualization.md) for cookbook patterns: multi-panel figures, custom palettes, publication-ready output.

Source: [visualization vignette](https://satijalab.org/seurat/articles/visualization_vignette).

---

## Key Parameters to Adjust

### QC subset thresholds
- `nFeature_RNA > 200` (cells with too few genes are doublets / empty)
- `nFeature_RNA < 2500` (heuristic doublet cap; raise for nuclei or rich tissues)
- `percent.mt < 5` (PBMC); raise to 15-20% for nuclei / tumor tissue

### `FindVariableFeatures`
- `nfeatures = 2000` (default); 3000-5000 if your tissue is heterogeneous

### PCA / `dims`
- Pick `dims` from `ElbowPlot()` — usually 10-30. Don't over-pick (noise dimensions).

### `FindClusters(resolution = ...)`
- 0.5 → coarse clusters (cell types)
- 1.0-1.5 → finer sub-clusters (cell states)
- For DE / marker analysis, start coarser; for trajectory / niche, go finer.

### `IntegrateLayers(method = ...)`
- See the table above. Try Harmony first (fast); fall back to CCA/RPCA if Harmony over-corrects.

---

## Best Practices

- **Use Seurat v5 layers, not v4 separate objects.** Splitting via `split(obj[["RNA"]], f = ...)` is the new idiom.
- **Install `presto` immediately.** `FindAllMarkers` is the slow step in most analyses; presto speeds it up 10-100×.
- **Use `BPCells` for atlas-scale.** Out-of-memory matrices let you analyze millions of cells on 32 GB.
- **Run `JoinLayers()` before downstream DE.** After integration, the RNA assay still has per-sample layers; some functions expect a single joined layer.
- **`PrepSCTFindMarkers()` is mandatory before DE on SCT-integrated data.** Without it, `FindMarkers` produces wrong results.
- **`percent.mt` cutoff varies by tissue.** PBMC: 5%. Nuclei: 1% (nuclei have no mito RNA). Tumor: 15-20% (lytic cells).
- **Save intermediate `.rds` files** between major stages — Seurat objects can be large and re-running clusters can change cluster IDs if `set.seed` isn't pinned.

---

## End-to-End Template

`assets/seurat_template.R` — single parameterized script for single-sample OR multi-sample (via INPUT_MODE toggle) through to integration, clusters, markers, and annotated output.

## Convenience Scripts

- `scripts/build_seurat.R` — single-sample standard pipeline (10X / h5 / Read10X) → annotated RDS
- `scripts/integrate_seurat.R` — multi-sample v5 IntegrateLayers (any of the 5 methods)

---

## References

- [Seurat home](https://satijalab.org/seurat/) — Satija Lab
- [Installation v5](https://satijalab.org/seurat/articles/install_v5)
- [PBMC 3K tutorial](https://satijalab.org/seurat/articles/pbmc3k_tutorial) — the canonical entry point
- [v5 integration](https://satijalab.org/seurat/articles/seurat5_integration) — `IntegrateLayers`
- [v4 integration](https://satijalab.org/seurat/articles/integration_introduction.html) — anchor-based, still supported
- [Visualization vignette](https://satijalab.org/seurat/articles/visualization_vignette)
- Hao et al. (2024), *Dictionary learning for integrative, multimodal and scalable single-cell analysis*, *Nature Biotechnology* (Seurat v5 paper)
- Related Operon protocols: [`hdwgcna`](../hdwgcna/SKILL.md), [`cellchat`](../cellchat/SKILL.md), [`singlecellexperiment`](../singlecellexperiment/SKILL.md)

Files in this skill

  • SKILL.md15.7 KB
  • assets/seurat_template.R7.4 KB
  • references/integration.md8.1 KB
  • references/visualization.md7.5 KB
  • scripts/build_seurat.R7.2 KB
  • scripts/integrate_seurat.R6.8 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…