Pathway Enrichment Analysis¶
Overview¶
Pathway enrichment interprets differential expression (or other ranked/hit gene lists) at the pathway and GO-term level rather than gene by gene. This guide covers when to use over-representation analysis (ORA), GSEA Prerank, or standard GSEA; how to prepare inputs; which outputs and plots to produce; and how to run the analyses with GSEApy against Enrichr libraries (GO, KEGG, MSigDB, Reactome, and 200+ others). Use it after DESeq2, edgeR, limma, or scanpy DE — not as a substitute for the DE step itself.
When to Use¶
- Interpreting DESeq2 or edgeR differential expression results at pathway/GO-term level
- Choosing among ORA, GSEA Prerank, and standard GSEA given the available inputs
- Running Enrichr ORA against GO, KEGG, MSigDB Hallmarks, and other libraries
- Performing GSEA prerank on a log2-fold-change-ranked gene list without a raw expression matrix
- Identifying enriched pathways in scRNA-seq cluster marker genes
- Producing enrichment tables plus required bar plots, network maps, and GSEA running-score plots
- For upstream DESeq2 differential expression, use
bulk-rnaseqinstead
Key Concepts¶
Over-representation analysis (ORA)¶
ORA tests whether a discrete gene list (e.g. significant DEGs) is enriched for genes in curated sets. In GSEApy this is gp.enrichr, which queries Enrichr. It is simple and fast, but ignores magnitude of change and depends on an arbitrary significance cutoff. Run separately on up- and down-regulated lists. Typical threshold: adjusted P-value < 0.05. Full recipe: references/ora_analysis_reference.md.
GSEA Prerank¶
GSEA Prerank runs the GSEA algorithm on a ranked list of all tested genes (e.g. log2 fold-change sorted descending) without needing a raw expression matrix. In GSEApy this is gp.prerank. It detects coordinated pathway shifts even when individual genes are modest, handles both directions in one run (positive NES = up, negative NES = down), and avoids cutoff bias. Typical threshold: FDR q-val < 0.25. Full recipe: references/gsea_prerank_analysis_reference.md.
Standard GSEA¶
Standard GSEA (gp.gsea) permutes sample/phenotype labels on an expression matrix. It is closest to the original Broad methodology but needs enough samples per group (≥7 recommended), is slowest, and couples ranking to the test. Prefer gp.prerank() in virtually every other case — it separates DE from enrichment and works with output from any DE tool.
Gene set libraries and identifiers¶
Enrichr provides 200+ libraries (gp.get_library_name(organism="human")). Pass a local .gmt via gene_sets= for offline use. Gene IDs must match the library (typically HGNC symbols, not Ensembl IDs).
Decision Framework¶
ALWAYS decide which method to use BEFORE running any enrichment analysis.
Question: What input do you have?
├── Discrete gene list only (no ranks)
│ └── → ORA (`gp.enrichr`)
├── Full DE results with a ranking metric (e.g. log2FC)
│ ├── Default → GSEA Prerank (`gp.prerank`)
│ └── User explicitly wants ORA / Enrichr → ORA on significant subset
├── Raw expression matrix + phenotype labels
│ └── User explicitly wants sample-permutation GSEA
│ └── → Standard GSEA (`gp.gsea`); otherwise still prefer Prerank on a DE ranking
└── User asks for both ORA and GSEA
└── → ORA on significant genes + Prerank on full ranked list
| Scenario | Recommended approach | Rationale |
|---|---|---|
| Full DE table with log2FC for all genes | GSEA Prerank | More powerful; no arbitrary cutoff |
| Only a gene list (e.g. scRNA-seq cluster markers) | ORA | No ranks available |
| Quick hypothesis check on a curated hit list | ORA | Fast and interpretable |
| Expression matrix + labels; user wants classic Broad GSEA | Standard GSEA | Sample-label permutation |
| User asks for both methods | ORA + Prerank | Discrete hits + subtle coordinated signals |
| Default when unsure and ranks exist | GSEA Prerank | Preferred over gp.gsea() in almost all cases |
| Criterion | ORA (gp.enrichr) |
GSEA Prerank (gp.prerank) |
Standard GSEA (gp.gsea) |
|---|---|---|---|
| Input | Discrete gene list | Ranked list of ALL tested genes | Expression matrix + phenotype |
| Typical source | padj < 0.05 & abs(log2FC) > 1 |
Full log2FoldChange column |
TPM/CPM + two-group labels |
| Strength | Simple, fast, focused | Subtle distributed signals; no cutoff | Faithful to Broad GSEA |
| Weakness | Threshold-dependent; ignores magnitude | Slower; sensitive to ranking metric | Needs ≥7 samples/group; slowest |
| Significance | Adjusted P < 0.05 | FDR q < 0.25 | FDR q < 0.25 |
| Direction | Separate up/down runs | One run (sign of NES) | One run (sign of NES) |
Best Practices¶
- Choose the method first: Apply the decision framework before calling Enrichr or prerank — do not default to ORA solely because it is familiar.
- Prefer GSEA Prerank when ranks exist: Use the full DE ranking (e.g. log2FC) rather than thresholding away signal.
- Split ORA by direction: Always run up- and down-regulated gene lists separately; never pool them.
- Use HGNC symbols and exact library names: Confirm species and ID type; list libraries with
gp.get_library_name()rather than guessing strings. - Ship required plots every run: Always produce the bar plot and network enrichment map; for GSEA also produce enrichment curves for the top 3 terms per direction. Use
gp.barplot/gseapy.plot.dotplot— not ad-hoc seaborn/matplotlib bar charts. - Dot plots only on request: Generate a dot plot only when the user explicitly asks for one.
- Set seeds and publication-grade permutations: For prerank, use
permutation_num=1000and a fixedseedwhen reporting results. - Compare across contrasts deliberately: For multiple conditions, repeat the full workflow per contrast and compare significant-term sets afterward.
Troubleshooting¶
- Running ORA on a thresholded list when full ranks were available
- How to avoid: Default to GSEA Prerank whenever log2FC (or another ranking metric) exists for all tested genes.
- Pooling up- and down-regulated genes in one ORA call
- How to avoid: Always run separate Enrichr analyses per direction.
- Using Ensembl IDs against symbol-based Enrichr libraries
- How to avoid: Convert to HGNC (or matching) symbols before enrichment; verify overlap size is non-trivial.
- Skipping the network map or using custom bar charts
- How to avoid: Follow the required visualization table; call GSEApy plotting helpers.
- Calling
gp.gsea()by default on an expression matrix- How to avoid: Prefer DE → ranked list →
gp.prerank()unless the user explicitly wants sample-permutation GSEA.
- How to avoid: Prefer DE → ranked list →
- Unsorted or tiny ranked lists yielding flat NES ≈ 0
- How to avoid: Sort
rnkdescending; keep gene-set size withinmin_size/max_size; ensure ≥10 genes for ORA.
- How to avoid: Sort
- Offline or API failures treated as empty biology
- How to avoid: Check Enrichr availability; fall back to a local
.gmtviagene_sets=.
- How to avoid: Check Enrichr availability; fall back to a local
Workflow¶
- Step 1: Planning
- Apply the decision framework (ORA / GSEA Prerank / standard GSEA / both).
- Confirm organism, gene ID type, and target Enrichr libraries (or local
.gmt).
- Step 2: Prepare input
- ORA: derive up- and down-regulated gene lists (
references/ora_analysis_reference.md→ Load Gene Lists). - Prerank: build full ranked Series, e.g. log2FC sorted descending (
references/gsea_prerank_analysis_reference.md→ Load Ranked Gene List).
- ORA: derive up- and down-regulated gene lists (
- Step 3: Run analysis
- ORA:
gp.enrichrper direction against one or more databases. - Prerank: single
gp.prerankon the full list.
- ORA:
- Step 4: Save results
- Write full and significance-filtered tables (
references/*.md→ Save Results).
- Write full and significance-filtered tables (
- Step 5: Visualize
- Required plots + method-specific diagnostics (see Protocol Guidelines).
- Dot plot only if explicitly requested.
- Step 6: Multi-contrast (optional)
- Repeat steps 2–5 per comparison; compare significant-term sets across runs.
Load the matching reference file on demand and adapt variable names to the user's existing DESeq2/edgeR/scanpy objects — snippets are step-oriented recipes, not a packaged library.
Protocol Guidelines¶
- Required visualizations (always)
- ORA: bar plot + network enrichment map; plus up/down term-overlap comparison and gene-set-size vs significance scatter for full analyses.
- GSEA Prerank: NES bar plot + enrichment curves (top 3 terms per direction) + network map; plus NES waterfall and leading-edge overlap heatmap for full analyses.
- Both methods requested: produce the full set for each.
- Optional visualizations: Dot plot only when the user asks (e.g. "show a dotplot").
-
Key parameters
Parameter Default Range / options Effect gene_setsrequired string, list, or .gmtpathEnrichr library name(s) or local GMT organism(enrichr)"human"human, mouse, fly, fish, worm, yeast Species for lookup cutoff(enrichr)0.050–1 Adjusted p-value filter rnk(prerank)required pd.SeriesGene → score; sort descending permutation_num(prerank)1000100–10000 Permutations for p-values min_size/max_size(prerank)15/5005–50 / 100–2000 Gene-set size bounds threads(prerank)41–64 CPU threads seed(prerank)Noneinteger Reproducibility -
Expected output patterns
Output pattern Method Description ora_{up,down}_all_terms.tsv,ora_{up,down}_significant_terms.tsvORA Full and filtered tables ora_{up,down}_barplot.png,ora_{up,down}_network_map.pngORA Required plots ora_{up,down}_dotplot.pngORA Optional (request only) ora_updown_term_overlap.png,ora_size_vs_significance.pngORA Additional diagnostics gsea_prerank_all_terms.tsv,gsea_prerank_significant_terms.tsvPrerank Full and FDR-filtered tables gsea_nes_barplot.png,gsea_curve_*_NES_*.png,gsea_network_map.pngPrerank Required plots gsea_dotplot.png,gsea_nes_waterfall.png,gsea_leading_edge_overlap.pngPrerank Optional / additional -
Environment
- Packages:
gseapy,pandas,matplotlib,networkx,seaborn. - Install:
pip install gseapy. Internet required unless a local.gmtis supplied.
- Packages:
Guardrails¶
- Apply the Decision Framework before the first
gp.enrichr/gp.prerank/gp.gseacall — do not pick a method after seeing results. - Never pool up- and down-regulated genes into one ORA call; run each direction separately.
- Check symbol overlap against the chosen library before interpreting. A near-zero overlap is an identifier problem (e.g. Ensembl IDs against symbol-based libraries), not absent biology.
- Treat an Enrichr network or API failure as a failure, not an empty result. Report it, or fall back to a local
.gmtviagene_sets=; never state "no enriched pathways" on the back of a failed request. - State the significance threshold with every result set. GSEA/Prerank hits are reported at FDR q < 0.25 and must not be presented as significant at the ORA adjusted P < 0.05 bar.
- Do not retry a failing enrichment more than 3 times — read the error (see Troubleshooting) first.
- Confirm with the user before heavy workloads:
permutation_numabove 1000, sweeping many contrasts in one run, or standardgp.gseaon large expression matrices.
Related Skills¶
bulk-rnaseq— upstream differential expression (DESeq2); produce the ranked lists and DEG tables this guide consumes.
Companion Assets¶
references/ora_analysis_reference.md— ORA implementation: directional Enrichr runs, bar/network plots, optional dot plot, up/down overlap and size-vs-significance diagnostics.references/gsea_prerank_analysis_reference.md— GSEA Prerank implementation: single-run prerank, NES bar/curves/network, optional dot plot, NES waterfall and leading-edge overlap diagnostics.
References¶
- Adapted from SciAgent gseapy-gene-enrichment skill
- GSEApy documentation — usage guide and API reference
- GSEApy GitHub: zqfang/GSEApy — source and examples
- Fang Z et al. (2023) "GSEApy: a comprehensive package for performing gene set enrichment analysis in Python" — Bioinformatics 39(1):btac757. DOI:10.1093/bioinformatics/btac757
- Subramanian A et al. (2005) "Gene set enrichment analysis: A knowledge-based approach for interpreting genome-wide expression profiles" — PNAS 102(43):15545-15550. DOI:10.1073/pnas.0506580102
- Enrichr gene set databases — 200+ gene set libraries