๐ง scRNA-seq Fundamentals
๐ฏ What is Single-Cell RNA-Seq?
Single-cell RNA sequencing (scRNA-seq) measures gene expression at the resolution of individual cells. Unlike bulk RNA-seq, which averages expression across thousands of cells, scRNA-seq reveals cellular heterogeneity, identifies rare cell types, and enables trajectory analysis. Since its introduction in 2009, scRNA-seq has revolutionized our understanding of development, disease, and tissue organization.
Why scRNA-seq Matters
Heterogeneity: Cell-to-cell variation. Rare cells: Find rare types. Trajectory: Development. Disease: Mechanisms. Atlas: Human Cell Atlas. Precision: Medicine.
# Single-Cell RNA-Seq โ the big picture
# Measuring gene expression at single-cell resolution.
print("""
=== Single-Cell RNA-Seq (scRNA-seq) ===
What it is:
- Gene expression per cell
- Individual cells
- Heterogeneity
- Rare cell types
Why it matters:
- Cellular heterogeneity
- Rare cell types
- Developmental trajectories
- Disease mechanisms
- Human Cell Atlas
- Precision medicine
Key concepts:
- Cell barcodes
- UMIs (Unique Molecular Identifiers)
- Droplet-based
- 10x Genomics
- QC
- Normalization
- Feature selection
- PCA
- UMAP / t-SNE
- Clustering
- Marker genes
- Cell type annotation
- Trajectory analysis
Applications:
- Cancer
- Immunology
- Neuroscience
- Developmental biology
- Stem cells
- COVID-19
""")
print("=== Historical Context ===")
print("""
2009: First scRNA-seq (Tang et al.)
2012: Smart-seq
2015: Drop-seq, InDrop
2016: 10x Genomics
2017: Human Cell Atlas
2019: Scanpy, Seurat v3
2020: COVID-19 scRNA-seq
2025: Spatial, multi-omics, AI
""")
print("=== Why It's Hard ===")
print("""
1. DROPOUTS
- Many zeros
- Low capture
- Missing data
2. SPARSITY
- ~10% non-zero
- Zero-inflated
- Statistical challenges
3. BATCH EFFECTS
- Different runs
- Different days
- Integration
4. COMPUTATIONAL
- Millions of cells
- Memory
- Scalability
5. ANNOTATION
- Cell types
- Manual
- Reference
""")๐ฏ Why scRNA-seq Matters
๐ฏ The Value of scRNA-seq
scRNA-seq has transformed biology by revealing cellular heterogeneity that was invisible to bulk methods, enabling the discovery of new cell types and disease mechanisms.
Key Benefits
Heterogeneity: Cell-to-cell. Rare: Discovery. Trajectory: Development. Disease: Mechanisms. Atlas: Reference. Precision: Medicine.
# Why scRNA-seq Matters
print("=== 1. Cellular Heterogeneity ===")
print("""
Heterogeneity:
- Cell-to-cell variation
- Subpopulations
- States
Example:
Bulk: average expression
Single-cell: individual cells
โ New subtypes
""")
print("\n=== 2. Rare Cell Types ===")
print("""
Rare:
- Low abundance
- Hidden in bulk
- Discovery
Example:
Immune cells
โ Rare subsets
โ Function
""")
print("\n=== 3. Developmental Trajectories ===")
print("""
Trajectory:
- Differentiation
- Development
- Pseudotime
Example:
Stem cells
โ Differentiation
โ Trajectory
""")
print("\n=== 4. Disease Mechanisms ===")
print("""
Disease:
- Cancer heterogeneity
- Immune response
- Infection
Example:
Tumor
โ Cell types
โ Mechanisms
""")
print("\n=== 5. Human Cell Atlas ===")
print("""
Atlas:
- Reference
- All cell types
- Human
Example:
HCA
โ Reference
โ Comparison
""")
print("\n=== 6. Precision Medicine ===")
print("""
Precision:
- Personalized
- Treatment
- Response
Example:
Cancer
โ scRNA-seq
โ Therapy
""")
print("\n=== 7. Immunology ===")
print("""
Immunology:
- Immune cells
- Response
- Vaccines
Example:
T cells
โ Subsets
โ Function
""")
print("\n=== 8. Neuroscience ===")
print("""
Neuroscience:
- Brain cells
- Neurons
- Glia
Example:
Brain
โ Cell types
โ Atlas
""")
print("\n=== 9. Stem Cells ===")
print("""
Stem cells:
- Differentiation
- Regeneration
- Therapy
Example:
iPSC
โ Differentiation
โ Trajectory
""")
print("\n=== 10. COVID-19 ===")
print("""
COVID-19:
- Immune response
- Lung
- Severity
Example:
COVID-19
โ scRNA-seq
โ Mechanisms
""")โ๏ธ Workflow Overview
๐ฏ The scRNA-seq Pipeline
A typical scRNA-seq workflow goes from sample preparation to biological interpretation, involving cell capture, sequencing, QC, normalization, clustering, and annotation.
Workflow
Sample: Cells. Capture: Droplets. Sequence: 10x. QC: Filter. Normalize: Scale. Cluster: Groups. Annotate: Types.
# scRNA-seq Workflow
print("=== Overview ===")
print("""
Step 1: Sample preparation
Step 2: Cell capture (droplets)
Step 3: Library preparation
Step 4: Sequencing
Step 5: Alignment (CellRanger)
Step 6: QC
Step 7: Normalization
Step 8: Feature selection
Step 9: Dimensionality reduction
Step 10: Clustering
Step 11: Marker genes
Step 12: Cell type annotation
Step 13: Trajectory analysis
Step 14: Analysis & interpretation
""")
print("\n=== Step 1: Sample ===")
print("""
Sample:
- Tissue
- Dissociation
- Single cells
- Viability
Example:
Tissue
โ Dissociation
โ Single cells
""")
print("\n=== Step 2: Cell Capture ===")
print("""
Capture:
- Droplet-based
- 10x Genomics
- Barcoded beads
- Oil droplets
Example:
Cells + beads
โ Droplets
โ Barcoding
""")
print("\n=== Step 3: Library Prep ===")
print("""
Library:
- Reverse transcription
- cDNA
- Amplification
- Sequencing
Example:
mRNA
โ cDNA
โ Library
""")
print("\n=== Step 4: Sequencing ===")
print("""
Sequencing:
- Illumina
- Short reads
- 50-150 bp
- Paired-end
Example:
NovaSeq
โ Reads
โ FASTQ
""")
print("\n=== Step 5: Alignment ===")
print("""
Alignment:
- CellRanger
- STAR
- Reference genome
- Count matrix
Example:
CellRanger count
โ Count matrix
โ Feature-barcode
""")
print("\n=== Step 6: QC ===")
print("""
QC:
- Cell filtering
- Gene filtering
- Mitochondrial %
- Doublets
Example:
n_genes > 200
MT% < 20%
""")
print("\n=== Step 7: Normalization ===")
print("""
Normalization:
- Library size
- Log transform
- Scaling
- Batch correction
Example:
Normalize
โ Log1p
โ Scale
""")
print("\n=== Step 8: Feature Selection ===")
print("""
Features:
- Highly variable genes
- HVGs
- 2000-3000
Example:
HVG
โ Top 2000
โ PCA
""")
print("\n=== Step 9: Dimensionality Reduction ===")
print("""
Dim reduction:
- PCA
- UMAP
- t-SNE
Example:
PCA
โ 50 PCs
โ UMAP
""")
print("\n=== Step 10: Clustering ===")
print("""
Clustering:
- Leiden
- Louvain
- Graph-based
Example:
Leiden
โ Clusters
โ Cell types
""")
print("\n=== Step 11: Marker Genes ===")
print("""
Markers:
- Differential expression
- Cluster markers
- Annotate
Example:
Rank genes
โ Markers
โ Annotation
""")
print("\n=== Step 12: Annotation ===")
print("""
Annotation:
- Manual
- Automated
- Reference
Example:
Markers
โ Cell types
โ Annotation
""")
print("\n=== Step 13: Trajectory ===")
print("""
Trajectory:
- Pseudotime
- Differentiation
- PAGA
- Monocle
Example:
Trajectory
โ Pseudotime
โ Development
""")
print("\n=== Step 14: Analysis ===")
print("""
Analysis:
- Differential expression
- Composition
- Pathways
- Visualization
Example:
Cluster markers
โ Pathways
โ Biology
""")๐ฌ Platforms & Technologies
๐ฏ scRNA-seq Technologies
Several platforms exist for scRNA-seq, each with strengths and trade-offs. The 10x Genomics Chromium platform dominates due to its scalability and cost-effectiveness.
Platforms
10x: Droplet. Smart-seq: Plate. Drop-seq: Droplet. Seq-Well: Nanowell. BD Rhapsody: Nanowell. PacBio: Long reads.
# Platforms & Technologies
print("=== 1. 10x Genomics ===")
print("""
10x Genomics:
- Droplet-based
- Most popular
- 1000-10000 cells
- 3' or 5'
Pros:
- Scalable
- Cost-effective
- Standard
Cons:
- 3' bias
- Dropouts
Example:
Chromium
โ 10,000 cells
""")
print("\n=== 2. Smart-seq ===")
print("""
Smart-seq:
- Plate-based
- Full-length
- 96-384 cells
- High sensitivity
Pros:
- Full-length
- Sensitive
- Isoforms
Cons:
- Low throughput
- Expensive
Example:
Smart-seq2
โ 384 cells
""")
print("\n=== 3. Drop-seq ===")
print("""
Drop-seq:
- Droplet-based
- Early method
- 1000-10000 cells
Pros:
- Scalable
- Cost-effective
Cons:
- 3' bias
- Dropouts
""")
print("\n=== 4. Seq-Well ===")
print("""
Seq-Well:
- Nanowell
- Portable
- Low cost
Pros:
- Portable
- Low cost
Cons:
- Throughput
""")
print("\n=== 5. BD Rhapsody ===")
print("""
BD Rhapsody:
- Nanowell
- Targeted
- Multiplexing
Pros:
- Targeted
- Multiplexing
Cons:
- Cost
""")
print("\n=== 6. Long Reads ===")
print("""
Long reads:
- PacBio
- Nanopore
- Full-length
- Isoforms
Pros:
- Full-length
- Isoforms
- Splicing
Cons:
- Cost
- Throughput
""")
print("\n=== 7. Comparison ===")
print(f"{'Platform':<20} {'Method':<15} {'Cells':<15} {'Reads':<15}")
print("-" * 65)
print(f"{'10x':<20} {'Droplet':<15} {'10k':<15} {'3\\'':<15}")
print(f"{'Smart-seq':<20} {'Plate':<15} {'384':<15} {'Full':<15}")
print(f"{'Drop-seq':<20} {'Droplet':<15} {'10k':<15} {'3\\'':<15}")
print(f"{'Seq-Well':<20} {'Nanowell':<15} {'1k':<15} {'3\\'':<15}")
print(f"{'BD Rhapsody':<20} {'Nanowell':<15} {'10k':<15} {'3\\'':<15}")
print("\n=== 8. Choosing ===")
print("""
Choose:
- 10x: most cases
- Smart-seq: isoforms
- Long reads: isoforms
- Targeted: specific genes
""")
print("\n=== 9. UMIs ===")
print("""
UMI:
- Unique Molecular Identifier
- Barcode
- Count molecules
- Reduce PCR bias
Example:
Cell barcode + UMI
โ Count
""")
print("\n=== 10. Use Cases ===")
print("""
Use cases:
- Human: 10x
- Mouse: 10x
- Rare cells: Smart-seq
- Isoforms: Smart-seq
- Clinical: 10x
""")๐งน Quality Control
๐ฏ Filtering Low-Quality Cells
Quality control (QC) removes low-quality cells, empty droplets, and doublets before analysis. It's essential for reliable results.
QC
Genes: >200. Counts: >500. MT%: <20%. Doublets: Remove. Empty: Remove. HBB: Filter.
# Quality Control
print("=== 1. Cell Filtering ===")
print("""
Cell filtering:
- n_genes > 200
- n_counts > 500
- MT% < 20%
- Complex
Example:
Cell 1: 500 genes, MT 10% โ keep
Cell 2: 100 genes, MT 5% โ filter
Cell 3: 1000 genes, MT 30% โ filter
""")
print("\n=== 2. Gene Filtering ===")
print("""
Gene filtering:
- Expressed in >= 3 cells
- Remove low
- Remove MT genes
Example:
Gene A: 10 cells โ keep
Gene B: 1 cell โ filter
""")
print("\n=== 3. Mitochondrial ===")
print("""
MT%:
- Mitochondrial genes
- MT- prefix
- Apoptosis
- Filter
Example:
MT% < 20% โ keep
MT% > 20% โ filter
""")
print("\n=== 4. Doublets ===")
print("""
Doublets:
- Two cells in one droplet
- DoubletFinder
- Scrublet
- Remove
Example:
DoubletFinder
โ Remove doublets
""")
print("\n=== 5. Empty Droplets ===")
print("""
Empty:
- No cell
- Ambient RNA
- EmptyDrops
- Remove
Example:
EmptyDrops
โ Remove empty
""")
print("\n=== 6. Ambient RNA ===")
print("""
Ambient:
- Free RNA
- SoupX
- DecontX
- Remove
Example:
SoupX
โ Remove ambient
""")
print("\n=== 7. HBB ===")
print("""
HBB:
- Hemoglobin
- Red blood cells
- Filter
Example:
HBB high
โ RBC
โ Filter
""")
print("\n=== 8. QC Metrics ===")
print("""
Metrics:
- n_genes_by_counts
- total_counts
- pct_counts_mt
- pct_counts_ribo
- pct_counts_hb
Example:
sc.pp.calculate_qc_metrics()
""")
print("\n=== 9. Python QC ===")
print("""
import scanpy as sc
def qc_filter(adata, min_genes=200, min_counts=500, max_mt=20):
\"\"\"QC filter.\"\"\"
# Calculate metrics
adata.var['mt'] = adata.var_names.str.startswith('MT-')
sc.pp.calculate_qc_metrics(adata, qc_vars=['mt'], inplace=True)
# Filter cells
adata = adata[adata.obs['n_genes_by_counts'] >= min_genes]
adata = adata[adata.obs['total_counts'] >= min_counts]
adata = adata[adata.obs['pct_counts_mt'] < max_mt]
# Filter genes
sc.pp.filter_genes(adata, min_cells=3)
return adata
# Use
# adata = qc_filter(adata)
""")
print("\n=== 10. Best Practices ===")
print("""
Best practices:
- Visualize QC
- Adaptive thresholds
- Remove doublets
- Remove ambient
- Document
""")๐ Normalization
๐ฏ Correcting for Technical Variation
Normalization corrects for differences in library size and sequencing depth, making cells comparable. It's essential before clustering and differential expression.
Normalization
Library size: Total counts. Log1p: Stabilize. Scaling: Z-score. Batch: Correct. SCTransform: Seurat. Pearson: Residuals.
# Normalization
print("=== 1. Library Size ===")
print("""
Library size:
- Total counts per cell
- Normalize
- CPM-like
Example:
Cell 1: 10,000 counts
Cell 2: 20,000 counts
โ Normalize
""")
print("\n=== 2. Log Transformation ===")
print("""
Log:
- Stabilize variance
- Log1p
- Reduce skew
Example:
log1p(x)
""")
print("\n=== 3. Scaling ===")
print("""
Scaling:
- Z-score
- Mean 0
- Variance 1
- Before PCA
Example:
(x - mean) / std
""")
print("\n=== 4. Batch Correction ===")
print("""
Batch:
- Different runs
- Different days
- Correct
Tools:
- Harmony
- BBKNN
- Scanorama
- Seurat integration
Example:
Harmony
โ Corrected
""")
print("\n=== 5. SCTransform ===")
print("""
SCTransform:
- Seurat
- Regularized negative binomial
- Better
Example:
SCTransform()
""")
print("\n=== 6. Pearson Residuals ===")
print("""
Pearson:
- Residuals
- Analytic
- Better
Example:
sc.experimental.pp.normalize_pearson_residuals()
""")
print("\n=== 7. Python Normalization ===")
print("""
import scanpy as sc
def normalize(adata):
\"\"\"Normalize data.\"\"\"
# Library size
sc.pp.normalize_total(adata, target_sum=1e4)
# Log
sc.pp.log1p(adata)
# Store raw
adata.raw = adata
# Scale
sc.pp.scale(adata, max_value=10)
return adata
# Use
# adata = normalize(adata)
""")
print("\n=== 8. Batch Correction Python ===")
print("""
import scanpy.external as sce
def batch_correct(adata, batch_key="batch"):
\"\"\"Batch correction with Harmony.\"\"\"
sce.pp.harmony_integrate(adata, batch_key)
return adata
# Use
# adata = batch_correct(adata, "sample")
""")
print("\n=== 9. R Normalization ===")
print("""
library(Seurat)
# Normalize
seurat_obj <- NormalizeData(seurat_obj)
seurat_obj <- FindVariableFeatures(seurat_obj)
seurat_obj <- ScaleData(seurat_obj)
# SCTransform
seurat_obj <- SCTransform(seurat_obj)
# Integration
seurat_obj <- IntegrateLayers(seurat_obj, method = HarmonyIntegration)
""")
print("\n=== 10. Best Practices ===")
print("""
Best practices:
- Normalize
- Log
- Scale
- Batch correct
- Document
""")๐งฌ Feature Selection
๐ฏ Highly Variable Genes
Feature selection identifies highly variable genes (HVGs) that drive biological variation, reducing noise and dimensionality for downstream analysis.
Features
HVGs: Variable genes. 2000-3000: Standard. Selection: Variance. PCA: Input. Markers: Help. Remove: Noise.
# Feature Selection
print("=== 1. What are HVGs? ===")
print("""
HVG:
- Highly variable genes
- High variance
- Biological signal
- Remove noise
Example:
Gene A: low variance โ skip
Gene B: high variance โ keep
""")
print("\n=== 2. Selection Methods ===")
print("""
Methods:
- Seurat: mean-variance
- Scanpy: seurat, cell_ranger, seurat_v3
- Poisson
Example:
sc.pp.highly_variable_genes()
""")
print("\n=== 3. Number ===")
print("""
Number:
- 2000-3000
- Standard
- Depends
Example:
2000 HVGs
โ PCA
""")
print("\n=== 4. Exclude Genes ===")
print("""
Exclude:
- MT genes
- Ribosomal
- HBB
- Cell cycle
Example:
Exclude MT-
โ HVGs
""")
print("\n=== 5. Cell Cycle ===")
print("""
Cell cycle:
- Proliferation
- Confounding
- Regress
Example:
Cell cycle score
โ Regress
""")
print("\n=== 6. Python HVG ===")
print("""
import scanpy as sc
def select_hvg(adata, n_top_genes=2000):
\"\"\"Select HVGs.\"\"\"
sc.pp.highly_variable_genes(
adata,
n_top_genes=n_top_genes,
flavor='seurat_v3'
)
adata = adata[:, adata.var['highly_variable']]
return adata
# Use
# adata = select_hvg(adata)
""")
print("\n=== 7. R HVG ===")
print("""
library(Seurat)
seurat_obj <- FindVariableFeatures(
seurat_obj,
selection.method = "vst",
nfeatures = 2000
)
""")
print("\n=== 8. Visualization ===")
print("""
Visualization:
- HVG plot
- Mean vs variance
- Highlight HVGs
Example:
sc.pl.highly_variable_genes(adata)
""")
print("\n=== 9. Batch HVG ===")
print("""
Batch:
- Per batch
- Combine
- More robust
Example:
batch_key='sample'
""")
print("\n=== 10. Best Practices ===")
print("""
Best practices:
- 2000-3000
- Exclude MT
- Batch-aware
- Visualize
""")๐ Dimensionality Reduction
๐ฏ Reducing Dimensions
Dimensionality reduction projects high-dimensional gene expression data into lower dimensions for visualization and clustering. PCA is used first, then UMAP or t-SNE for visualization.
Dim Reduction
PCA: Linear. UMAP: Non-linear. t-SNE: Non-linear. 50 PCs: Standard. Visualization: UMAP. Clustering: PCs.
# Dimensionality Reduction
print("=== 1. PCA ===")
print("""
PCA:
- Linear
- Variance
- 50 PCs
- Input for UMAP
Example:
sc.tl.pca(adata, n_comps=50)
""")
print("\n=== 2. UMAP ===")
print("""
UMAP:
- Non-linear
- Fast
- Global structure
- Visualization
Example:
sc.tl.umap(adata)
""")
print("\n=== 3. t-SNE ===")
print("""
t-SNE:
- Non-linear
- Slow
- Local structure
- Visualization
Example:
sc.tl.tsne(adata)
""")
print("\n=== 4. PCA Number ===")
print("""
Number:
- 50 PCs
- Elbow plot
- Variance
Example:
sc.pl.pca_variance_ratio(adata)
""")
print("\n=== 5. UMAP Parameters ===")
print("""
Parameters:
- n_neighbors: 15
- min_dist: 0.5
- metric: euclidean
Example:
sc.pp.neighbors(adata, n_neighbors=15)
sc.tl.umap(adata, min_dist=0.5)
""")
print("\n=== 6. t-SNE Parameters ===")
print("""
Parameters:
- perplexity: 30
- learning_rate: 1000
- n_iter: 1000
Example:
sc.tl.tsne(adata, perplexity=30)
""")
print("\n=== 7. Python Dim Reduction ===")
print("""
import scanpy as sc
def dim_reduction(adata, n_pcs=50, n_neighbors=15):
\"\"\"Dimensionality reduction.\"\"\"
# PCA
sc.tl.pca(adata, n_comps=n_pcs)
# Neighbors
sc.pp.neighbors(adata, n_neighbors=n_neighbors, n_pcs=n_pcs)
# UMAP
sc.tl.umap(adata)
# t-SNE
sc.tl.tsne(adata)
return adata
# Use
# adata = dim_reduction(adata)
""")
print("\n=== 8. Visualization ===")
print("""
Visualization:
- PCA
- UMAP
- t-SNE
- Color by gene
- Color by cluster
Example:
sc.pl.umap(adata, color=['cluster', 'gene'])
""")
print("\n=== 9. R Dim Reduction ===")
print("""
library(Seurat)
seurat_obj <- RunPCA(seurat_obj, npcs = 50)
seurat_obj <- RunUMAP(seurat_obj, dims = 1:30)
seurat_obj <- RunTSNE(seurat_obj, dims = 1:30)
""")
print("\n=== 10. Best Practices ===")
print("""
Best practices:
- 50 PCs
- Elbow plot
- UMAP for viz
- t-SNE local
- Document
""")๐ต Clustering
๐ฏ Grouping Similar Cells
Clustering groups cells with similar expression profiles, revealing cell types and states. Graph-based clustering (Leiden, Louvain) is the standard.
Clustering
Leiden: Standard. Louvain: Classic. Graph: Neighbors. Resolution: Granularity. Markers: Identify. Annotate: Types.
# Clustering
print("=== 1. Graph-Based ===")
print("""
Graph:
- KNN graph
- Neighbors
- Community detection
Example:
sc.pp.neighbors(adata)
sc.tl.leiden(adata)
""")
print("\n=== 2. Leiden ===")
print("""
Leiden:
- Standard
- Better than Louvain
- Resolution
Example:
sc.tl.leiden(adata, resolution=1.0)
""")
print("\n=== 3. Louvain ===")
print("""
Louvain:
- Classic
- Fast
- Resolution
Example:
sc.tl.louvain(adata, resolution=1.0)
""")
print("\n=== 4. Resolution ===")
print("""
Resolution:
- Granularity
- Higher: more clusters
- Lower: fewer
Example:
res=0.5: 5 clusters
res=1.0: 10 clusters
res=2.0: 20 clusters
""")
print("\n=== 5. Number of Clusters ===")
print("""
Number:
- Depends
- Biology
- Resolution
- Markers
Example:
Try multiple
โ Choose
""")
print("\n=== 6. Cluster Markers ===")
print("""
Markers:
- Differential expression
- Cluster vs rest
- Annotate
Example:
sc.tl.rank_genes_groups(adata, 'leiden')
""")
print("\n=== 7. Python Clustering ===")
print("""
import scanpy as sc
def cluster(adata, resolution=1.0):
\"\"\"Cluster cells.\"\"\"
# Neighbors
sc.pp.neighbors(adata, n_neighbors=15, n_pcs=50)
# Leiden
sc.tl.leiden(adata, resolution=resolution)
# UMAP
sc.tl.umap(adata)
return adata
# Use
# adata = cluster(adata, resolution=1.0)
""")
print("\n=== 8. R Clustering ===")
print("""
library(Seurat)
seurat_obj <- FindNeighbors(seurat_obj, dims = 1:30)
seurat_obj <- FindClusters(seurat_obj, resolution = 1.0)
seurat_obj <- RunUMAP(seurat_obj, dims = 1:30)
""")
print("\n=== 9. Visualization ===")
print("""
Visualization:
- UMAP colored by cluster
- Cluster markers
- Heatmap
Example:
sc.pl.umap(adata, color='leiden')
""")
print("\n=== 10. Best Practices ===")
print("""
Best practices:
- Leiden
- Try resolutions
- Check markers
- Validate
- Annotate
""")๐ Marker Genes
๐ฏ Finding Cluster Markers
Marker genes are genes that are differentially expressed in a cluster compared to other clusters. They are used to identify and annotate cell types.
Markers
Differential: Cluster vs rest. Rank: Genes. Wilcoxon: Test. LogFC: Effect. Annotation: Cell types. Visualization: Heatmap, dotplot.
# Marker Genes
print("=== 1. Differential Expression ===")
print("""
DE:
- Cluster vs rest
- Statistical test
- Rank genes
Tests:
- Wilcoxon
- t-test
- Logistic regression
Example:
sc.tl.rank_genes_groups(adata, 'leiden')
""")
print("\n=== 2. Rank Genes ===")
print("""
Rank:
- Top genes
- Score
- LogFC
Example:
sc.tl.rank_genes_groups(adata, 'leiden', method='wilcoxon')
sc.pl.rank_genes_groups(adata)
""")
print("\n=== 3. Marker Genes ===")
print("""
Markers:
- Known markers
- Cell types
- Validate
Examples:
- CD3D: T cells
- CD79A: B cells
- CD14: Monocytes
- NKG7: NK cells
- MS4A1: B cells
- LYZ: Myeloid
- ACTA2: Fibroblasts
- PECAM1: Endothelial
""")
print("\n=== 4. Visualization ===")
print("""
Visualization:
- Heatmap
- Dotplot
- Violin
- UMAP
Example:
sc.pl.heatmap(adata, marker_genes, groupby='leiden')
sc.pl.dotplot(adata, marker_genes, groupby='leiden')
sc.pl.violin(adata, marker_genes, groupby='leiden')
""")
print("\n=== 5. Python Markers ===")
print("""
import scanpy as sc
def find_markers(adata, groupby='leiden', method='wilcoxon'):
\"\"\"Find marker genes.\"\"\"
sc.tl.rank_genes_groups(
adata,
groupby=groupby,
method=method
)
return adata
# Use
# adata = find_markers(adata)
""")
print("\n=== 6. Get Markers ===")
print("""
def get_markers(adata, n_genes=10):
\"\"\"Get top markers.\"\"\"
markers = {}
for group in adata.obs['leiden'].unique():
df = sc.get.rank_genes_groups_df(adata, group=group)
markers[group] = df.head(n_genes)['names'].tolist()
return markers
# Use
# markers = get_markers(adata)
""")
print("\n=== 7. R Markers ===")
print("""
library(Seurat)
markers <- FindAllMarkers(seurat_obj, only.pos = TRUE)
top_markers <- markers %>% group_by(cluster) %>% top_n(10)
""")
print("\n=== 8. Annotation ===")
print("""
Annotation:
- Markers
- Cell types
- Manual
- Automated
Example:
Cluster 0: CD3D+ โ T cells
Cluster 1: CD79A+ โ B cells
""")
print("\n=== 9. Automated ===")
print("""
Automated:
- SingleR
- CellTypist
- scType
- scmap
Example:
SingleR
โ Cell types
""")
print("\n=== 10. Best Practices ===")
print("""
Best practices:
- Multiple markers
- Known markers
- Validate
- Visualize
- Document
""")๐ท๏ธ Cell Type Annotation
๐ฏ Assigning Cell Types
Cell type annotation assigns biological identities to clusters based on marker genes, reference datasets, and automated tools.
Annotation
Manual: Markers. Automated: SingleR, CellTypist. Reference: Atlas. Validate: Markers. Hierarchy: Levels. Ontology: CL.
# Cell Type Annotation
print("=== 1. Manual Annotation ===")
print("""
Manual:
- Markers
- Known genes
- Expert knowledge
Example:
Cluster 0: CD3D, CD3E โ T cells
Cluster 1: CD79A, MS4A1 โ B cells
Cluster 2: CD14, LYZ โ Monocytes
""")
print("\n=== 2. Automated Annotation ===")
print("""
Automated:
- SingleR
- CellTypist
- scType
- scmap
Example:
SingleR
โ Reference-based
""")
print("\n=== 3. SingleR ===")
print("""
SingleR:
- Reference-based
- Correlation
- R package
Example:
library(SingleR)
pred <- SingleR(test = sce, ref = ref, labels = ref$label)
""")
print("\n=== 4. CellTypist ===")
print("""
CellTypist:
- Python
- Logistic regression
- Reference
Example:
import celltypist
predictions = celltypist.annotate(adata, model='Immune_All_Low.pkl')
""")
print("\n=== 5. Reference Atlases ===")
print("""
References:
- Human Cell Atlas
- Tabula Muris
- Allen Brain Atlas
- Immune Cell Atlas
Example:
HCA
โ Reference
โ Annotation
""")
print("\n=== 6. Marker Validation ===")
print("""
Validation:
- Known markers
- Consistent
- Visualize
Example:
Cluster 0: T cells
โ CD3D+
โ Validate
""")
print("\n=== 7. Hierarchy ===")
print("""
Hierarchy:
- Level 1: T cells
- Level 2: CD4 T cells
- Level 3: Treg
Example:
Annotate
โ Hierarchy
""")
print("\n=== 8. Ontology ===")
print("""
Ontology:
- Cell Ontology (CL)
- Standard
- Ontology
Example:
CL:0000084
โ T cell
""")
print("\n=== 9. Python Annotation ===")
print("""
import scanpy as sc
def annotate(adata, markers_dict):
\"\"\"Annotate clusters manually.\"\"\"
# Map clusters to cell types
cluster_to_type = {
'0': 'T cells',
'1': 'B cells',
'2': 'Monocytes',
# ...
}
adata.obs['cell_type'] = adata.obs['leiden'].map(cluster_to_type)
return adata
# Use
# adata = annotate(adata, markers)
""")
print("\n=== 10. Best Practices ===")
print("""
Best practices:
- Multiple methods
- Markers
- Reference
- Validate
- Ontology
""")๐งญ Trajectory Analysis
๐ฏ Inferring Developmental Paths
Trajectory analysis (pseudotime) infers developmental or differentiation paths from scRNA-seq data. It orders cells along a continuum of states, revealing transitions between cell types.
Trajectory
Pseudotime: Order cells. Monocle: Classic. PAGA: Graph. Slingshot: Curves. scVelo: RNA velocity. CellRank: Fate.
# Trajectory Analysis
print("=== 1. What is Trajectory? ===")
print("""
Trajectory:
- Developmental path
- Differentiation
- Pseudotime
- Order cells
Example:
Stem cell โ progenitor โ mature
โ Trajectory
""")
print("\n=== 2. Pseudotime ===")
print("""
Pseudotime:
- Order cells
- Progress
- Root
Example:
Pseudotime 0 โ start
Pseudotime 1 โ end
""")
print("\n=== 3. Monocle ===")
print("""
Monocle:
- R package
- Classic
- DDRTree
Example:
library(monocle3)
cds <- new_cell_data_set(expression_matrix)
cds <- learn_graph(cds)
cds <- order_cells(cds)
""")
print("\n=== 4. PAGA ===")
print("""
PAGA:
- Python
- Graph abstraction
- Connectivity
Example:
sc.tl.paga(adata, groups='leiden')
sc.pl.paga(adata)
""")
print("\n=== 5. Slingshot ===")
print("""
Slingshot:
- R package
- Curves
- Lineages
Example:
library(slingshot)
sce <- slingshot(sce, clusterLabels = 'leiden')
""")
print("\n=== 6. RNA Velocity ===")
print("""
RNA velocity:
- Spliced/unspliced
- Direction
- scVelo
Example:
import scvelo as scv
scv.pp.filter_and_normalize(adata)
scv.tl.velocity(adata)
scv.tl.velocity_graph(adata)
""")
print("\n=== 7. CellRank ===")
print("""
CellRank:
- Fate
- Direction
- Python
Example:
import cellrank as cr
cr.tl.initial_states(adata)
cr.tl.lineages(adata)
""")
print("\n=== 8. Python Trajectory ===")
print("""
import scanpy as sc
def trajectory(adata, groupby='leiden'):
\"\"\"Trajectory analysis with PAGA.\"\"\"
sc.tl.paga(adata, groups=groupby)
sc.pl.paga(adata)
# Diffusion map
sc.tl.diffmap(adata)
# DPT
sc.tl.dpt(adata)
return adata
# Use
# adata = trajectory(adata)
""")
print("\n=== 9. Visualization ===")
print("""
Visualization:
- PAGA graph
- Pseudotime UMAP
- Trajectory
- Gene dynamics
Example:
sc.pl.umap(adata, color='dpt_pseudotime')
""")
print("\n=== 10. Best Practices ===")
print("""
Best practices:
- Multiple methods
- Validate
- Biology
- Visualize
- Document
""")๐ ๏ธ Tools (Scanpy, Seurat, CellRanger)
๐ฏ scRNA-seq Tools
Many tools exist for scRNA-seq analysis. Each has strengths and is suited to different use cases.
Tools
CellRanger: Alignment. Scanpy: Python. Seurat: R. Monocle: Trajectory. SingleR: Annotation. Harmony: Integration.
# Tools
print("=== CellRanger ===")
print("""
CellRanger:
- 10x Genomics
- Alignment
- Count matrix
- Standard
Command:
cellranger count --id=sample \\
--transcriptome=ref \\
--fastqs=fastq_path \\
--sample=sample
""")
print("\n=== Scanpy ===")
print("""
Scanpy:
- Python
- Comprehensive
- Fast
- Scalable
Features:
- QC
- Normalization
- Clustering
- UMAP
- Markers
- Trajectory
Install:
pip install scanpy
""")
print("\n=== Seurat ===")
print("""
Seurat:
- R
- Comprehensive
- Popular
- Integration
Features:
- QC
- Normalization
- Clustering
- UMAP
- Markers
- Integration
Install:
install.packages("Seurat")
""")
print("\n=== Monocle ===")
print("""
Monocle:
- R
- Trajectory
- Pseudotime
- DDRTree
Install:
BiocManager::install("monocle3")
""")
print("\n=== SingleR ===")
print("""
SingleR:
- R
- Annotation
- Reference-based
Install:
BiocManager::install("SingleR")
""")
print("\n=== Harmony ===")
print("""
Harmony:
- Integration
- Batch correction
- Fast
Install:
install.packages("harmony")
""")
print("\n=== Other Tools ===")
print("""
1. scVelo
- RNA velocity
2. CellTypist
- Annotation
3. PAGA
- Trajectory
4. scran
- Normalization
5. Scrublet
- Doublets
6. SoupX
- Ambient RNA
7. DoubletFinder
- Doublets
8. CellChat
- Cell-cell communication
""")
print("\n=== Tool Comparison ===")
print(f"{'Tool':<20} {'Language':<15} {'Best For':<25}")
print("-" * 60)
print(f"{'CellRanger':<20} {'CLI':<15} {'Alignment':<25}")
print(f"{'Scanpy':<20} {'Python':<15} {'Comprehensive':<25}")
print(f"{'Seurat':<20} {'R':<15} {'Comprehensive':<25}")
print(f"{'Monocle':<20} {'R':<15} {'Trajectory':<25}")
print(f"{'SingleR':<20} {'R':<15} {'Annotation':<25}")
print(f"{'Harmony':<20} {'R/Python':<15} {'Integration':<25}")
print("\n=== When to Use Which ===")
print("""
USE CellRanger:
โ 10x alignment
โ Count matrix
USE Scanpy:
โ Python
โ Comprehensive
โ Scalable
USE Seurat:
โ R
โ Comprehensive
โ Popular
USE Monocle:
โ Trajectory
โ Pseudotime
USE SingleR:
โ Annotation
โ Reference
USE Harmony:
โ Integration
โ Batch correction
""")๐ Python (Scanpy)
๐ฏ scRNA-seq with Scanpy
Scanpy is the leading Python library for scRNA-seq analysis. It provides comprehensive tools for QC, normalization, clustering, visualization, and more.
Scanpy
AnnData: Data structure. QC: Filter. Normalize: Scale. Cluster: Leiden. UMAP: Visualize. Markers: Find.
# Python (Scanpy)
print("=== 1. Install ===")
print("""
pip install scanpy
pip install leidenalg
""")
print("\n=== 2. Load Data ===")
print("""
import scanpy as sc
# Load 10x data
adata = sc.read_10x_mtx(
'filtered_feature_bc_matrix/',
var_names='gene_symbols',
cache=True
)
print(adata)
""")
print("\n=== 3. QC ===")
print("""
# Calculate metrics
adata.var['mt'] = adata.var_names.str.startswith('MT-')
sc.pp.calculate_qc_metrics(adata, qc_vars=['mt'], inplace=True)
# Filter
adata = adata[adata.obs['n_genes_by_counts'] >= 200]
adata = adata[adata.obs['total_counts'] >= 500]
adata = adata[adata.obs['pct_counts_mt'] < 20]
sc.pp.filter_genes(adata, min_cells=3)
""")
print("\n=== 4. Normalize ===")
print("""
# Normalize
sc.pp.normalize_total(adata, target_sum=1e4)
sc.pp.log1p(adata)
# Store raw
adata.raw = adata
# HVG
sc.pp.highly_variable_genes(adata, n_top_genes=2000)
adata = adata[:, adata.var['highly_variable']]
# Scale
sc.pp.scale(adata, max_value=10)
""")
print("\n=== 5. PCA ===")
print("""
sc.tl.pca(adata, n_comps=50)
sc.pl.pca_variance_ratio(adata, n_pcs=50)
""")
print("\n=== 6. Clustering ===")
print("""
# Neighbors
sc.pp.neighbors(adata, n_neighbors=15, n_pcs=50)
# Leiden
sc.tl.leiden(adata, resolution=1.0)
# UMAP
sc.tl.umap(adata)
# Plot
sc.pl.umap(adata, color='leiden')
""")
print("\n=== 7. Markers ===")
print("""
# Rank genes
sc.tl.rank_genes_groups(adata, 'leiden', method='wilcoxon')
# Plot
sc.pl.rank_genes_groups(adata, n_genes=10)
# Get markers
markers = sc.get.rank_genes_groups_df(adata, group='0')
print(markers.head(10))
""")
print("\n=== 8. Annotation ===")
print("""
# Manual annotation
cluster_to_type = {
'0': 'T cells',
'1': 'B cells',
'2': 'Monocytes',
# ...
}
adata.obs['cell_type'] = adata.obs['leiden'].map(cluster_to_type)
# Plot
sc.pl.umap(adata, color='cell_type')
""")
print("\n=== 9. Trajectory ===")
print("""
# PAGA
sc.tl.paga(adata, groups='leiden')
sc.pl.paga(adata)
# Diffusion map
sc.tl.diffmap(adata)
# DPT
sc.tl.dpt(adata)
# Plot
sc.pl.umap(adata, color='dpt_pseudotime')
""")
print("\n=== 10. Complete Pipeline ===")
print("""
import scanpy as sc
def scrna_pipeline(filepath):
\"\"\"Complete scRNA-seq pipeline.\"\"\"
# Load
adata = sc.read_10x_mtx(filepath, var_names='gene_symbols')
# QC
adata.var['mt'] = adata.var_names.str.startswith('MT-')
sc.pp.calculate_qc_metrics(adata, qc_vars=['mt'], inplace=True)
adata = adata[adata.obs['n_genes_by_counts'] >= 200]
adata = adata[adata.obs['pct_counts_mt'] < 20]
sc.pp.filter_genes(adata, min_cells=3)
# Normalize
sc.pp.normalize_total(adata, target_sum=1e4)
sc.pp.log1p(adata)
adata.raw = adata
# HVG
sc.pp.highly_variable_genes(adata, n_top_genes=2000)
adata = adata[:, adata.var['highly_variable']]
sc.pp.scale(adata, max_value=10)
# PCA
sc.tl.pca(adata, n_comps=50)
# Cluster
sc.pp.neighbors(adata, n_neighbors=15, n_pcs=50)
sc.tl.leiden(adata, resolution=1.0)
sc.tl.umap(adata)
# Markers
sc.tl.rank_genes_groups(adata, 'leiden', method='wilcoxon')
return adata
# Use
# adata = scrna_pipeline("filtered_feature_bc_matrix/")
""")โ๏ธ Tool Comparison
๐ฏ Which Tool?
Choosing the right scRNA-seq tool depends on your programming language, data size, and analysis goals.
Comparison
Scanpy: Python. Seurat: R. CellRanger: Alignment. Monocle: Trajectory. SingleR: Annotation. Harmony: Integration.
| Tool | Language | Step | Best For |
|---|---|---|---|
| CellRanger | CLI | Alignment | 10x data |
| Scanpy | Python | Comprehensive | Python users |
| Seurat | R | Comprehensive | R users |
| Monocle | R | Trajectory | Pseudotime |
| Slingshot | R | Trajectory | Curves |
| PAGA | Python | Trajectory | Graph |
| scVelo | Python | Velocity | Direction |
| SingleR | R | Annotation | Reference |
| CellTypist | Python | Annotation | Automated |
| Harmony | R/Python | Integration | Batch |
# Decision Guide
print("=== Choose Tool by Language ===")
print("""
Python:
โ Scanpy
โ PAGA
โ scVelo
โ CellTypist
R:
โ Seurat
โ Monocle
โ Slingshot
โ SingleR
CLI:
โ CellRanger
โ STARsolo
""")
print("\n=== Choose Tool by Task ===")
print("""
Alignment:
โ CellRanger
โ STARsolo
QC:
โ Scanpy
โ Seurat
Clustering:
โ Scanpy
โ Seurat
Trajectory:
โ Monocle
โ PAGA
โ Slingshot
โ scVelo
Annotation:
โ SingleR
โ CellTypist
Integration:
โ Harmony
โ BBKNN
โ Scanorama
""")
print("\n=== Speed Comparison ===")
print(f"{'Tool':<20} {'10k cells':<15} {'100k cells':<15} {'1M cells':<15}")
print("-" * 65)
print(f"{'Scanpy':<20} {'1 min':<15} {'10 min':<15} {'1 hour':<15}")
print(f"{'Seurat':<20} {'2 min':<15} {'20 min':<15} {'2 hours':<15}")
print(f"{'Monocle':<20} {'5 min':<15} {'1 hour':<15} {'10 hours':<15}")
print("\n=== When to Use Which ===")
print("""
USE CellRanger:
โ 10x alignment
โ Count matrix
USE Scanpy:
โ Python
โ Comprehensive
โ Scalable
USE Seurat:
โ R
โ Comprehensive
โ Integration
USE Monocle:
โ Trajectory
โ Pseudotime
USE SingleR:
โ Annotation
โ Reference
USE Harmony:
โ Integration
โ Batch correction
""")โ FAQ
๐ฏ Frequently Asked Questions
Answers to common questions about single-cell RNA-seq.
What is single-cell RNA-seq?
Single-cell RNA sequencing (scRNA-seq) measures gene expression at the resolution of individual cells. Unlike bulk RNA-seq, which averages expression across thousands of cells, scRNA-seq reveals cellular heterogeneity, identifies rare cell types, and enables trajectory analysis.
What is the 10x Genomics platform?
10x Genomics Chromium is the most widely used droplet-based scRNA-seq platform. It encapsulates individual cells with barcoded beads in oil droplets, enabling thousands of cells to be profiled in a single run. CellRanger is the standard pipeline for processing 10x data.
What is the difference between Scanpy and Seurat?
Scanpy is a Python library for scRNA-seq analysis, while Seurat is an R package. Both provide comprehensive tools for QC, normalization, clustering, UMAP/t-SNE, marker gene detection, and visualization. Scanpy is preferred for Python users; Seurat for R users.
What is UMAP and how does it differ from t-SNE?
UMAP (Uniform Manifold Approximation and Projection) and t-SNE (t-distributed Stochastic Neighbor Embedding) are dimensionality reduction methods for visualization. UMAP is faster and better preserves global structure; t-SNE better preserves local structure. Both are commonly used in scRNA-seq.
What is trajectory analysis in scRNA-seq?
Trajectory analysis (pseudotime) infers developmental or differentiation paths from scRNA-seq data. It orders cells along a continuum of states, revealing transitions between cell types. Tools include Monocle, PAGA, Slingshot, and scVelo (RNA velocity).
What is a UMI?
A UMI (Unique Molecular Identifier) is a short random barcode attached to each mRNA molecule before amplification. UMIs allow counting of original mRNA molecules, reducing PCR bias and improving quantification accuracy.
What are doublets and how do I remove them?
Doublets occur when two cells are captured in the same droplet, creating artificial hybrid expression profiles. Tools like DoubletFinder, Scrublet, and Scrublet detect and remove doublets.
What is batch correction?
Batch correction removes technical variation between samples processed at different times or in different runs. Tools include Harmony, BBKNN, Scanorama, and Seurat integration.
How do I annotate cell types?
Annotate cell types using marker genes (manual) or automated tools like SingleR (reference-based) and CellTypist (machine learning). Always validate annotations with known markers and visualize on UMAP.
What is the best clustering resolution?
The optimal resolution depends on your biological question. Try multiple resolutions (0.4, 0.6, 0.8, 1.0) and choose the one that gives stable, biologically meaningful clusters validated by marker genes.
# Quick Reference
print("=== Quick Answers ===")
print("""
Q: What is scRNA-seq?
A: Gene expression at single-cell resolution.
Q: Best platform?
A: 10x Genomics.
Q: Best alignment?
A: CellRanger.
Q: Best Python tool?
A: Scanpy.
Q: Best R tool?
A: Seurat.
Q: QC thresholds?
A: >200 genes, <20% MT.
Q: Clustering?
A: Leiden.
Q: Visualization?
A: UMAP, t-SNE.
Q: Trajectory?
A: Monocle, PAGA, scVelo.
Q: Annotation?
A: SingleR, CellTypist.
Q: Integration?
A: Harmony.
Q: Free?
A: Yes โ all major tools are free.
""")๐ Future
๐ฏ Where scRNA-seq Is Going
The future is spatial transcriptomics, multi-omics, single-cell ATAC, AI, clinical, and atlas-scale.
Future Directions
Spatial: Location. Multi-omics: RNA+ATAC+protein. AI: Prediction. Clinical: Diagnostics. Atlas: Millions. Single-cell: Multi-modal.
# Future of scRNA-seq
print("=== 1. Spatial Transcriptomics ===")
print("""
Trend: Spatial
Current:
- Dissociated cells
- No location
Future:
- Spatial
- Location
- Tissue context
Examples:
- Visium
- MERFISH
- Xenium
- Slide-seq
Future:
- Spatial context
- Microenvironment
- Tissue architecture
""")
print("\n=== 2. Multi-Omics ===")
print("""
Trend: Multi-omics
Current:
- RNA only
Future:
- RNA + ATAC
- RNA + protein
- RNA + methylation
- Multi-modal
Examples:
- CITE-seq
- Multiome
- scNMT
Future:
- Integrated
- Multi-modal
- Systems
""")
print("\n=== 3. AI ===")
print("""
Trend: AI + scRNA-seq
Ideas:
- Deep learning
- Integration
- Annotation
- Prediction
Examples:
- scGPT
- Geneformer
- scBERT
Future:
- Foundation models
- Better integration
- Predictive
""")
print("\n=== 4. Clinical ===")
print("""
Trend: Clinical
Current:
- Research
Future:
- Clinical
- Diagnostics
- Therapeutics
Examples:
- Cancer
- Immunology
- COVID-19
Future:
- Clinical implementation
- Precision
- Equity
""")
print("\n=== 5. Atlas ===")
print("""
Trend: Atlas-scale
Current:
- Thousands of cells
Future:
- Millions
- Billions
- Human Cell Atlas
Examples:
- HCA
- Tabula
- Brain Atlas
Future:
- Complete atlases
- Reference
- Integration
""")
print("\n=== 6. Single-Cell Multi-Modal ===")
print("""
Trend: Multi-modal
Current:
- One modality
Future:
- RNA + ATAC + protein
- Multi-modal
- Single-cell
Examples:
- CITE-seq
- Multiome
- Perturb-seq
Future:
- Multi-modal
- Integrated
- Systems
""")
# TIMELINE
print("\n=== Timeline ===")
print("""
Past:
2009: First scRNA-seq
2015: Drop-seq
2016: 10x Genomics
2017: HCA
2019: Scanpy, Seurat v3
2020: COVID-19
Present:
2025: Spatial
2026: Multi-omics
Future:
2030: AI
2035: Clinical
2040: Atlas?
""")
print("\n=== Final Thoughts ===")
print("""
scRNA-seq is:
- Transforming biology
- Cellular resolution
- Heterogeneity
- Evolving
The future is:
- Spatial
- Multi-omics
- AI
- Clinical
- Atlas
- Single-cell multi-modal
"One cell at a time."
Keep exploring. Keep building.
""")