---
title: Scanpy on the platform
description: >-
  Single-cell RNA-seq analysis with Scanpy for preprocessing, clustering, and
  trajectory inference.
tags:
  - scanpy
---

Scanpy takes single-cell RNA-seq data from raw counts to annotated cell types and marker genes — the classical, fast, interpretable path through quality control, clustering, differential expression, and trajectory inference. Reach for it as your default for single-cell analysis when speed and interpretability matter and you don't have heavy batch effects to correct. When you do — multiple samples to integrate, or unknown cell types to annotate — pair it with [scvi-tools](/docs/scvi-tools), whose deep generative models plug into the same AnnData object. See [what you can achieve](/docs/capabilities#genomics-and-omics) for the full set.

## Scanpy single-cell analysis on the platform

Scanpy is a scalable toolkit for analyzing single-cell gene expression data, built on top of the AnnData data structure. Through the platform, you can run comprehensive scRNA-seq workflows from raw counts to publication-ready visualizations -- including quality control, normalization, dimensionality reduction, clustering, differential expression, and trajectory inference.

Scanpy is the most widely used Python framework for single-cell analysis, with native support for datasets ranging from a few hundred cells to millions. It integrates tightly with the broader scverse ecosystem (scvi-tools, squidpy, muon) for advanced modeling tasks.

## Citations

> Wolf FA, Angerer P, Theis FJ. SCANPY: large-scale single-cell gene expression data analysis. *Genome Biology*. 2018;19:15. doi: [10.1186/s13059-017-1382-0](https://doi.org/10.1186/s13059-017-1382-0)

## How the platform runs Scanpy

The platform runs Scanpy as a GPU-accelerated job on rapids-singlecell (cuML, cuGraph, cupy on a T4 GPU), which speeds up PCA, k-NN, UMAP, and Leiden relative to the CPU-only open-source package. You supply an AnnData `.h5ad` file (S3 URI or HTTPS URL) and choose one **workflow**:

- **`full`** (default) — the complete pipeline: QC → normalize → highly variable genes → PCA → neighbors → UMAP → Leiden → differential expression.
- **`qc`** — quality control and filtering only.
- **`clustering`** — QC through Leiden and UMAP, without marker genes.
- **`de`** — differential expression / marker genes.

Beyond these four GPU workflows, the tool exposes CPU-based **extension workflows** for batch correction (`harmony_integrate`, `scanorama_integrate`, `combat_correct`), automated annotation (`celltypist_annotate`), gene-set and marker scoring (`aucell_score`, `cosg_markers`, `hotspot_modules`), stemness (`cytotrace2_potency`), and RNA velocity (`scvelo_velocity`).

The sections below describe the underlying Scanpy methods in depth — the platform pipeline follows this same sequence, with GPU-accelerated implementations of the compute-heavy steps.

> The platform's Scanpy job focuses on the QC-to-clustering-to-markers path plus scverse extensions. Niche standalone workflows (trajectory inference, GRN, spatial clustering, cellxgene search) are handled by dedicated tools rather than this job — the trajectory and PAGA material below is background on the method, not a workflow you select here.

## Technical approach

### The AnnData object model

Scanpy operates on the **AnnData** (Annotated Data) object, which stores all information for a single-cell experiment in a structured format:

| Slot | Contents | Example |
|------|----------|---------|
| `X` | Expression matrix (cells x genes) | Raw counts or normalized values |
| `obs` | Cell-level metadata (one row per cell) | Sample ID, batch, cell type labels |
| `var` | Gene-level metadata (one row per gene) | Gene symbols, highly variable flags |
| `obsm` | Cell embeddings (multi-dimensional) | PCA coordinates, UMAP coordinates |
| `obsp` | Cell-cell graphs | Nearest-neighbor connectivity matrix |
| `uns` | Unstructured metadata | Clustering parameters, color palettes |
| `layers` | Alternative expression matrices | Raw counts, spliced/unspliced (for RNA velocity) |

This design means a single `.h5ad` file captures the entire analysis state -- raw data, processed matrices, embeddings, cluster assignments, and metadata -- making results fully reproducible.

### Preprocessing pipeline

Scanpy's standard preprocessing workflow follows a well-established sequence:

**1. Quality control and filtering**

- Filter cells by minimum gene count (default: 200 genes) to remove empty droplets
- Filter genes by minimum cell count (default: 3 cells) to remove uninformative genes
- Calculate mitochondrial gene percentages and filter cells above a threshold (default: 20%) to remove dying cells
- Optionally filter doublets using scrublet scores

**2. Normalization**

- **Library-size normalization** (`sc.pp.normalize_total`): Scale each cell to a target sum (typically 10,000) so that expression values are comparable across cells with different sequencing depths
- **Log transformation** (`sc.pp.log1p`): Apply log(1+x) to stabilize variance and make the data more normally distributed
- Store raw counts in `adata.layers['counts']` before normalization for differential expression

**3. Highly variable gene (HVG) selection**

- Identify genes with high cell-to-cell variation using `sc.pp.highly_variable_genes`
- Typically select 2,000-5,000 HVGs to focus downstream analysis on informative genes
- Methods: `seurat` (default), `seurat_v3` (for raw counts), or `cell_ranger`
- HVG selection dramatically reduces dimensionality and noise without losing biological signal

**4. Scaling**

- Center and scale expression values to zero mean and unit variance (`sc.pp.scale`)
- Optionally clip extreme values (e.g., `max_value=10`) to limit the influence of outliers

### Dimensionality reduction

Scanpy implements a two-stage dimensionality reduction approach:

**PCA (Principal Component Analysis)**

- Reduces the HVG expression matrix from ~2,000 dimensions to 50 principal components
- Captures the major axes of biological variation
- The number of informative PCs can be assessed with an elbow plot (`sc.pl.pca_variance_ratio`)
- Typically 30-50 PCs are used for downstream steps

**Neighbor graph construction**

- Builds a k-nearest neighbor (kNN) graph in PCA space using `sc.pp.neighbors`
- Default: 15 neighbors, Euclidean distance in PCA space
- This graph is the foundation for both clustering and visualization

**UMAP and t-SNE**

- **UMAP** (`sc.tl.umap`): Produces a 2D embedding that preserves both local and global structure. Preferred for most applications. Key parameters: `min_dist` (compactness, default 0.5) and `spread` (default 1.0)
- **t-SNE** (`sc.tl.tsne`): Produces a 2D embedding optimized for local structure. Better for visually separating tight clusters, but does not preserve global distances. Key parameter: `perplexity` (default 30)

> UMAP is generally recommended over t-SNE for exploratory analysis because it runs faster, scales better, and preserves more global structure. Use t-SNE when you need to emphasize local cluster separation for publication figures.

### Clustering

Scanpy implements graph-based community detection algorithms:

**Leiden algorithm** (`sc.tl.leiden`)

- Preferred method -- produces well-connected communities with a quality guarantee
- The `resolution` parameter controls cluster granularity: lower values (0.1-0.5) yield fewer, larger clusters; higher values (1.0-2.0) yield more, smaller clusters
- Default resolution: 1.0
- Operates on the kNN graph constructed during neighbor computation

**Louvain algorithm** (`sc.tl.louvain`)

- Older alternative to Leiden -- faster but can produce poorly connected communities
- Same resolution parameter semantics as Leiden
- Generally recommended to use Leiden instead unless backward compatibility is needed

**Choosing resolution**: Start with the default (1.0) and adjust based on biological expectations. Over-clustering is generally preferable to under-clustering -- you can always merge clusters, but splitting them requires re-running.

### Differential expression

Scanpy identifies marker genes for each cluster using `sc.tl.rank_genes_groups`:

| Method | Description | Best For |
|--------|-------------|----------|
| `wilcoxon` | Wilcoxon rank-sum test (default) | Most applications; robust to non-normality |
| `t-test` | Welch's t-test | Normally distributed data, fast |
| `t-test_overestim_var` | t-test with overestimated variance | Conservative, fewer false positives |
| `logreg` | Logistic regression | Multi-class marker selection |

Results include log fold change, p-values, and adjusted p-values (Benjamini-Hochberg). Use the top-ranked genes per cluster to annotate cell types by cross-referencing with known marker databases (CellMarker, PanglaoDB).

### Trajectory inference

Scanpy supports pseudotime and lineage analysis through several approaches:

- **Diffusion pseudotime** (`sc.tl.dpt`): Computes pseudotime ordering based on diffusion distances in the neighbor graph. Requires specifying a root cell (typically the most undifferentiated population).
- **PAGA** (`sc.tl.paga`): Partition-based graph abstraction. Creates a coarse-grained graph of cluster connectivity, useful for identifying differentiation trajectories and transitions between cell states.
- **RNA velocity** (via scVelo): Not built into Scanpy but integrates seamlessly. Uses spliced/unspliced RNA ratios to infer the direction of cell state transitions.

## When to use Scanpy

### Primary applications

- **scRNA-seq quality control and analysis**: The core use case. From raw 10X Genomics or Smart-seq2 data through to annotated cell types and marker genes.
- **Spatial transcriptomics preprocessing**: Scanpy handles the expression matrix for spatial technologies (Visium, MERFISH, Slide-seq). Use squidpy for spatial-specific analyses on top.
- **Atlas-scale integration**: With backed mode (`sc.read_h5ad(backed='r')`), Scanpy can handle datasets with millions of cells without loading the full matrix into memory.
- **Comparative analysis**: Compare cell populations across conditions, treatments, or time points using differential expression and composition analysis.
- **Cell type annotation**: Combine clustering with marker gene analysis and reference-based annotation (e.g., via Celltypist or manual curation).

### Comparison with Seurat

Seurat is the primary R-based alternative to Scanpy. Key differences:

| Aspect | Scanpy (Python) | Seurat (R) |
|--------|-----------------|------------|
| **Language** | Python | R |
| **Data structure** | AnnData (.h5ad) | Seurat object (.rds) |
| **Scalability** | Better for large datasets (&gt;500K cells) via backed mode | Memory-limited; requires Seurat v5 disk-backed for large data |
| **Ecosystem** | scverse (scvi-tools, squidpy, muon) | Signac (ATAC-seq), Azimuth (reference mapping) |
| **Integration methods** | Harmony, BBKNN, scVI (via scvi-tools) | CCA, RPCA, Harmony |
| **Visualization** | Matplotlib-based (customizable but verbose) | ggplot2-based (publication-ready defaults) |
| **Community** | Larger in computational biology / ML | Larger in experimental biology / clinical |

Both frameworks produce comparable results for standard workflows. Choose based on your language preference and downstream ecosystem needs. Results can be converted between formats using `anndata2ri` or `SeuratDisk`.

## Limitations

- **Memory-intensive for large datasets**: Datasets above 500,000 cells require careful memory management. Use backed mode, sparse matrices, and chunked processing. For datasets above 2 million cells, consider subsampling or using geometric sketching before full analysis.
- **Limited built-in batch correction**: Scanpy's native batch correction (`sc.pp.combat`) is basic. For multi-sample integration, use scVI-tools (`scvi.model.SCVI`), Harmony (`sc.external.pp.harmony_integrate`), or BBKNN (`sc.external.pp.bbknn`) -- all of which integrate with Scanpy but are separate packages.
- **CPU-only for extension workflows**: On the platform, the core workflows (`full`, `qc`, `clustering`, `de`) run GPU-accelerated via rapids-singlecell, but the batch-correction, annotation, and scoring extensions (Harmony, Scanorama, ComBat, CellTypist, AUCell, COSG, Hotspot, CytoTrace2, scVelo) run on CPU. Upstream open-source Scanpy is CPU-only; rapids-singlecell is the GPU-backed drop-in the platform uses.
- **No built-in multi-modal analysis**: For combined scRNA-seq + scATAC-seq or CITE-seq, use muon (part of scverse) which extends AnnData to multi-modal data.
- **Trajectory inference is basic**: Scanpy's diffusion pseudotime and PAGA are useful for simple trajectories, but complex branching lineages are better handled by CellRank or scVelo.

## Integration with scVI-tools

scVI-tools provides deep generative models that complement Scanpy's preprocessing:

- **scVI**: Variational autoencoder for dimensionality reduction, batch correction, and differential expression. Produces a latent space that replaces PCA for downstream clustering and visualization.
- **scANVI**: Semi-supervised variant of scVI that uses reference cell type labels for annotation transfer.
- **SOLO**: Doublet detection using a variational autoencoder.
- **totalVI**: Joint modeling of RNA and protein (CITE-seq) data.

The typical workflow is: preprocess with Scanpy (QC, filtering, normalization) then train a scVI model for batch-corrected embeddings and differential expression. The scVI latent space can be stored in `adata.obsm['X_scVI']` and used directly with Scanpy's neighbor graph and clustering functions.

### Integration with the platform ecosystem

- **Upstream**: Load data from 10X Genomics, Smart-seq2, or other platforms
- **Downstream**: Feed results to scVI-tools for advanced modeling, target validation pipelines for cell-type-specific target expression

## Chat Usage

### Example Prompts

- "Run Scanpy full pipeline on this H5AD file"
- "Cluster these single-cell data with Leiden resolution 0.5"
- "Run QC and normalize my scRNA-seq dataset, then find marker genes"
- "Compute UMAP and identify differentially expressed genes per cluster"
- "Run trajectory analysis with diffusion pseudotime on my preprocessed data"

### Workflow Chaining

- **Feeds into**: Target validation (cell types expressing your target), scVI-tools (probabilistic modeling), differential expression analysis
- **Accepts from**: AnnData `.h5ad` files (uploaded, or produced upstream). Convert 10X Cell Ranger output or CSV matrices to `.h5ad` before submitting — the job reads `.h5ad` only.

## Read next
