📊 Single-Cell QC
You are SC QC, the OmicsClaw skill for first-pass single-cell RNA-seq
quality assessment. Your job is to calculate core QC metrics, render a standard
diagnostic gallery, and export figure-ready tables so users can decide filtering
thresholds deliberately in a later step.
Why This Exists
- Without it: users jump straight to filtering with vague or tissue-misaligned thresholds
- With it: one run produces a stable QC summary, diagnostic plots, and reusable per-cell metric tables
- Why OmicsClaw: the wrapper keeps a standard output contract across CLI / bot / chat usage and records analysis metadata back into AnnData for downstream reuse
Scope Boundary
Current OmicsClaw sc-qc exposes one implemented analysis path:
qc_metrics.
This skill:
- calculates QC metrics
- visualizes QC distributions
- exports per-cell and summary tables
- saves an AnnData with QC annotations
This skill does not:
- filter cells
- filter genes
- perform doublet detection
- normalize or cluster the data
Use sc-preprocessing or another downstream filtering workflow after reviewing
the QC outputs.
Core Capabilities
- QC metric calculation:
n_genes_by_counts, total_counts, pct_counts_mt, optional log metrics, and ribosomal percentage
- Species-aware gene tagging: mitochondrial and ribosomal features are detected from
--species
- Standard Python gallery: QC violin, scatter, histogram, and highest-expressed-gene panels
- Structured figure-data contract:
figure_data/ exports figure-ready CSVs plus a manifest for downstream plotting or styling
- Stable processed AnnData output: a canonical
processed.h5ad is produced with standardized scRNA contract fields, layers["counts"], adata.raw, QC metrics in .obs, marker flags in .var, and OmicsClaw metadata in .uns
- Notebook-friendly reproducibility: report, structured result JSON, reproducibility shell command, pinned requirements bundle, README, and analysis notebook
Input Formats
The current wrapper uses skills.singlecell._lib.io.smart_load(...).
| Format | Extension / form | Current wrapper support | Notes |
|---|
| AnnData | .h5ad | yes | preferred path |
| 10x HDF5 | .h5 | yes | delegated to shared single-cell loader |
| Loom | .loom | yes | delegated to shared single-cell loader |
| Delimited matrix | .csv, .tsv | yes | interpreted through the shared count-matrix loader |
| 10x directory | directory | yes | delegated to the shared 10x importer |
| Demo | --demo | yes | PBMC3k local/example fallback |
Input Expectations
- The most reliable input is a raw-count-like matrix available in
adata.layers["counts"], aligned adata.raw, or adata.X.
- If explicit counts are not in
adata.X, the wrapper now auto-selects the best count-like source before QC.
- Gene names should follow the selected species convention closely enough for mitochondrial and ribosomal prefix detection to work; when they do not, the run continues with warnings instead of faking precision.
Workflow
- Load: read input data with the shared single-cell loader or demo data.
- Preflight: check whether a count-like matrix exists, recommend
sc-standardize-input when provenance is unclear, and warn honestly about species-dependent gene naming.
- Prepare counts and gene IDs: choose the best available count-like source plus the best gene-symbol column for MT / ribosomal tagging.
- Calculate metrics: run Scanpy QC metric calculation and add log-transformed helper columns.
- Render standard gallery: generate the default OmicsClaw QC gallery under
figures/ through the shared skills/singlecell/_lib/viz layer.
- Export figure data and tables: write stable CSV exports under
figure_data/ and tables/.
- Write outputs: save
processed.h5ad, report.md, result.json, README, notebook, and reproducibility bundle.
CLI Reference
python skills/singlecell/scrna/sc-qc/sc_qc.py \
--input <data.h5ad> --output <dir>
python skills/singlecell/scrna/sc-qc/sc_qc.py \
--input <data.h5ad> --species mouse --output <dir>
python skills/singlecell/scrna/sc-qc/sc_qc.py \
--demo --output /tmp/sc_qc_demo
oc run sc-qc --input <data.h5ad> --output <dir>
Public Parameters
| Parameter | Default | Type | Role |
|---|
--input | required unless --demo | path | input dataset |
--output | required | path | output directory |
--demo | false | flag | run built-in demo data |
--species | human | enum | wrapper-level control for MT / ribosomal gene-prefix detection |
Parameter Design Notes
--species is the only public extra flag because the current wrapper exposes
a single QC path and does not surface thresholding knobs here.
calculate_ribo=True is fixed in the current implementation and is not a
public CLI parameter.
- Do not present
sc-qc as if users were choosing among multiple QC
algorithms today. The main decision in current OmicsClaw is how to interpret
the output, not how to configure many QC backends.
Algorithm / Methodology
Implemented Method: qc_metrics
Current OmicsClaw sc-qc uses Scanpy QC metric calculation with
species-specific feature tagging.
- Species-aware feature tagging
human: mitochondrial genes start with MT-; ribosomal genes match ^RP[SL]
mouse: mitochondrial genes start with mt-; ribosomal genes match ^Rp[sl]
- Metric calculation
scanpy.pp.calculate_qc_metrics(..., qc_vars=["mt", "ribo"], percent_top=None, log1p=False, inplace=True)
- Derived helper metrics
log10_total_counts
log10_n_genes_by_counts
- Standard gallery renderers
- QC violin plots
- QC scatter plots
- QC histograms
- highest expressed genes summary
Current Input Robustness Behavior
smart_load(...) is now loader-only: it reads the object and records a minimal input contract.
- User-facing standardization advice is emitted by shared
preflight, not by the loader.
prepare_count_like_adata(...) then selects layers["counts"] → aligned adata.raw → count-like adata.X in that order.
- The saved
processed.h5ad declares matrix semantics explicitly in adata.uns["omicsclaw_matrix_contract"]: here adata.X is raw count-like, adata.layers["counts"] is the canonical raw layer, and adata.raw is a count-like snapshot.
- If no mitochondrial or ribosomal genes match the selected species convention, the run continues with warnings and counts-based QC metrics remain available.
Guaranteed Metric Columns After Success
The saved processed.h5ad is expected to contain at least:
adata.obs["n_genes_by_counts"]
adata.obs["total_counts"]
adata.obs["pct_counts_mt"]
adata.obs["log10_total_counts"]
adata.obs["log10_n_genes_by_counts"]
When ribosomal pattern matching succeeds, the wrapper also writes:
adata.obs["pct_counts_ribo"]
adata.var["ribo"]
The feature-tag columns below are written during QC metric setup:
adata.var["mt"]
adata.var["ribo"]
OmicsClaw analysis metadata is also persisted in:
adata.uns["omicsclaw_analyses"]
Interpretation Guidance
Read These Metrics As Diagnostics, Not Hard Laws
n_genes_by_counts: low values often indicate empty droplets or low-complexity cells; very high values may indicate doublets
total_counts: very low values may indicate poor capture; very high values may reflect doublets or highly loaded droplets
pct_counts_mt: elevated mitochondrial percentage often suggests stressed or dying cells, but acceptable ranges vary by tissue
pct_counts_ribo: useful supporting context, especially when translation-heavy cell states dominate
Practical First-Pass Reading
- PBMC-like data often tolerates stricter mitochondrial cutoffs
- solid tissues / tumors often require broader tolerance
- highly metabolic tissues may show biologically elevated mitochondrial fractions
Do not convert these plots directly into filtering without considering tissue,
chemistry, ambient RNA burden, and expected cell complexity.
Output Contract
Stable Files
output_dir/
├── README.md
├── report.md
├── result.json
├── processed.h5ad
├── figures/
│ ├── qc_violin.png
│ ├── qc_scatter.png
│ ├── qc_histograms.png
│ ├── highest_expr_genes.png
│ ├── barcode_rank.png
│ ├── qc_correlation_heatmap.png
│ └── manifest.json
├── figure_data/
│ ├── manifest.json
│ ├── qc_run_summary.csv
│ ├── qc_metrics_summary.csv
│ ├── qc_metrics_per_cell.csv
│ ├── highest_expr_genes.csv
│ ├── barcode_rank_curve.csv
│ └── qc_metric_correlations.csv
├── tables/
│ ├── qc_metrics_summary.csv
│ ├── qc_metrics_per_cell.csv
│ ├── highest_expr_genes.csv
│ ├── barcode_rank_curve.csv
│ └── qc_metric_correlations.csv
└── reproducibility/
├── commands.sh
├── requirements.txt
└── analysis_notebook.ipynb
What Users Should Inspect First
report.md
figures/qc_violin.png and figures/qc_scatter.png
tables/qc_metrics_summary.csv
tables/qc_metrics_per_cell.csv
tables/barcode_rank_curve.csv and tables/qc_metric_correlations.csv for deeper QC review
processed.h5ad for downstream filtering workflows
Structured Result Contract
result.json includes:
summary.method = "qc_metrics"
data.params.species
data.effective_params.calculate_ribo = true
data.visualization.recipe_id = "standard-sc-qc-gallery"
data.visualization.available_figure_data
- top-level summary values such as
n_cells, n_genes, median_genes, and median_counts
data.params records replayable public CLI parameters.
data.effective_params records the actual runtime configuration, including
fixed wrapper behavior.
Visualization Contract
sc-qc treats Python plots as the standard analysis gallery. The current
recipe roles are:
overview: QC violin plots
diagnostic: QC scatter plots and histograms
supporting: highest expressed genes panel
figure_data/ is the stable hand-off layer for downstream custom plotting,
including future R-side visualization or user-authored beautification scripts.
Example Queries
- "Calculate QC metrics for this scRNA-seq dataset"
- "Show me mitochondrial percentage and genes-per-cell distributions"
- "Generate QC violin and scatter plots before filtering"
- "Run single-cell QC and export the per-cell QC table"
Dependencies
Required core packages:
scanpy
anndata
numpy
pandas
matplotlib
Notebook export additionally depends on the standard OmicsClaw notebook helper
stack when available.
Safety And Guardrails
- This skill is diagnostic only and does not remove cells or genes.
- Species choice affects mitochondrial / ribosomal pattern matching and should
be stated explicitly before the run.
- If gene symbols do not follow expected human or mouse prefixes, explain that
percentage estimates may be incomplete.
- For short execution guardrails, see
knowledge_base/knowhows/KH-sc-qc-guardrails.md.
- For longer method and interpretation guidance, see
knowledge_base/skill-guides/singlecell/sc-qc.md.
Workflow Position
- Upstream step: Input should come from
sc-count, sc-multi-count, or sc-standardize-input
- Usual next step:
sc-filter to remove low-quality cells based on the QC metrics visualized here
- Optional: Run
sc-doublet-detection before or after filtering
CLI Parameters
| Flag | Type | Default | Description | Validation |
|---|
--input | path | — | Input AnnData file (.h5ad); required unless --demo | — |
--output | path | — | Output directory (required) | — |
--demo | flag | false | Run with built-in PBMC3K demo data | — |
--species | enum | human | Species for MT/ribosomal gene prefix detection: human, mouse | — |
--r-enhanced | flag | false | Generate R Enhanced figures via ggplot2 renderers | — |
Note: calculate_ribo=True is fixed and not exposed as a CLI parameter.
R Enhanced Plots
| Renderer | Output file | What it shows | R packages |
|---|
plot_embedding_discrete | r_embedding_discrete.png | Cell scatter colored by discrete group/cluster label | ggplot2, ggrepel, cowplot |
plot_cell_barplot | r_cell_barplot.png | Cell count bar chart per group/sample | ggplot2, cowplot |