sc-de
Load when finding marker genes per cluster or comparing condition expression in single-cell RNA-seq. Skip when the data is bulk (use bulkrna-de); spatial (use spatial-de); cluster-only markers without
SKILL.mdskills/sc-de/SKILL.md
GitHubsc-de
When to use
The user has a preprocessed scRNA-seq AnnData and wants to know either
(a) which genes mark each cluster (Wilcoxon / t-test / logreg ranking) or
(b) which genes change between conditions in a replicate-aware way
(deseq2_r pseudobulk). Five backends are exposed; the wrapper enforces
the matrix contract (normalized expression vs raw counts) per backend
because mixing them is the most common silent-wrong-answer failure mode.
Inputs & Outputs
<!-- AUTO-GENERATED from skill.yaml (interface) — do not edit by hand. Regenerate: python scripts/generate_skill_md.py <skill_dir> -->Inputs
- Modalities: scrna
- File types:
.h5ad - Requires a preprocessed AnnData (
Xnormalised, PCA/neighbours present)
Outputs
tables/counts.csvtables/de_full.csvtables/de_group_summary.csvtables/de_top_markers.csvtables/deseq2_results.csvtables/gene_expression.csvtables/markers_top.csvtables/mast_results.csvtables/metadata.csvtables/pseudobulk_summary.csvfigures/marker_dotplot.pngfigures/pseudobulk_group_summary.pngfigures/r_de_heatmap.pngfigures/r_de_manhattan.pngfigures/r_de_volcano.pngfigures/r_feature_cor.pngfigures/r_feature_violin.pngfigures/rank_genes_groups.pnginput.h5adprocessed.h5adreport.mdresult.json- Processed AnnData (
saves_h5ad)
Flow
- Load the AnnData and inspect which matrix is in
X(normalized vs raw). - Validate the requested method's matrix contract — fail fast on mismatch.
- For exploratory paths: run Scanpy
rank_genes_groupsand export marker dotplot + rank summary. - For
mast: hand the log-normalized matrix to the R MAST bridge. - For
deseq2_r: pseudobulk-aggregate bysample_key×celltype_key, drop bins under--pseudobulk-min-cells/--pseudobulk-min-counts, run R DESeq2. - Render direct figures (and R-enhanced ones if
--r-enhanced). - Write
processed.h5ad, tables,figure_data/manifest.json,report.md,result.json, and reproducibility script.
Gotchas
- Exploratory ranking paths are NOT replicate-aware. Wilcoxon / t-test / logreg / mast treat each cell as an independent observation, which inflates Type I error for treated-vs-control comparisons across samples. Use
deseq2_rwhenever biological replicates exist and the question is condition-level inference — not cluster markers. deseq2_rrequires raw counts. It looks forlayers["counts"]first, thenadata.raw, thenadata.X, gated by amatrix_looks_count_likeheuristic on each candidate. After every pseudobulk run, checkresult.json["summary"]["expression_source"]— it should readlayers.countsoradata.raw, notadata.X. If the heuristic mis-classifies a normalized matrix as count-like, the run will fall through toadata.Xsilently.--group1and--group2are required fordeseq2_r.sc_de.pyraisesValueErrorwhen either is missing on the pseudobulk path. Other methods treat them as optional (cluster-vs-rest if absent).mastanddeseq2_rneed a working R stack.mastneedsMAST+SingleCellExperiment+zellkonverter;deseq2_rneedsDESeq2+ same companions. The wrapper raises if the R bridge is unavailable — install via the project's R bootstrap, not pip.- Pseudobulk bin filtering silently drops entire cell types. Per
skills/singlecell/_lib/pseudobulk.py:103, any sample × cell type bin with fewer than--pseudobulk-min-cells(default 10) cells iscontinue'd with no diagnostic written toresult.json. When DESeq2 reports "no DEGs in cell type X," sanity-check the per-sample cell counts manually before assuming biological null. sample_keyis statistical design, not a label. DESeq2 fits a per-sample dispersion; using a non-replicate column (e.g.cell_typeitself) gives nonsense. The wrapper does not currently catch this — sanity-check the column has >=2 distinct values per condition.
Key CLI
# Demo: PBMC3k Wilcoxon cluster markers
python omicsclaw.py run sc-de --demo
# Exploratory: cluster markers via Wilcoxon
python omicsclaw.py run sc-de \
--input processed.h5ad --output results/ \
--groupby leiden --method wilcoxon --n-top-genes 20
# Replicate-aware: treated vs control via DESeq2 pseudobulk
python omicsclaw.py run sc-de \
--input processed.h5ad --output results/ \
--method deseq2_r --groupby condition \
--group1 treated --group2 control \
--sample-key sample_id --celltype-key cell_type \
--pseudobulk-min-cells 10 --pseudobulk-min-counts 1000
See also
references/parameters.md— every CLI flag and per-method tuning hintreferences/methodology.md— Five DE paths, scope boundary, input expectations, workflowreferences/output_contract.md— exact output directory layout + visualization contractreferences/r_visualization.md— five R-enhanced renderers- Adjacent skills:
sc-clustering(upstream cluster discovery),sc-cell-annotation(upstream cell type labels forcelltype_key),sc-markers(lighter cluster-marker-only path),sc-enrichment(downstream pathway enrichment of DEG lists),bulkrna-de/spatial-de(sibling DE skills for the other two data modalities)