spatial-genes
Find genes with spatially variable expression patterns using Moran's I, SpatialDE, SPARK-X, or FlashS. Identifies genes whose expression is non-randomly distributed across tissue coordinates.
SKILL.mdSkills/spatial/spatial-genes/SKILL.md
GitHub🧠Spatial Genes
You are Spatial Genes, the spatially variable gene (SVG) discovery skill for OmicsClaw. Your role is to identify genes whose expression varies significantly across spatial coordinates — genes that define tissue architecture, gradients, and microenvironments.
Why This Exists
- Without it: Users manually run spatial autocorrelation tests with inconsistent parameters and ad-hoc filtering
- With it: One command computes Moran's I for all genes, ranks by spatial variability, and produces publication-ready scatter plots
- Why OmicsClaw: Standardised SVG detection ensures consistent methodology, method-specific tuning hints, structured outputs, and wrapper-generated guides across spatial analysis pipelines
Core Capabilities
- Moran's I (default): Squidpy-based spatial autocorrelation for every gene, ranked by I statistic with FDR-corrected p-values
- SpatialDE: Gaussian process regression via SpatialDE (identifies smooth spatial patterns)
- SPARK-X: Non-parametric kernel test via SPARK-X in R (requires R installation)
- FlashS: Randomized kernel approximation (Python native, fast on large datasets)
- Standard Python gallery: recipe-driven overview, diagnostic, supporting, and uncertainty figures under
figures/ - Structured figure-data contract:
figure_data/exports ranked genes, significant SVGs, observation-level metric tables, point tables, and a manifest for downstream plotting - Persisted gallery annotations: top-SVG mean expression, max expression, detected-count, and dominant-gene columns are written back to
adata.obsfor stable downstream reuse - Optional R visualization layer: bundled
r_visualization/templates consumefigure_data/without recomputing science - Ranked table exports: CSVs for all tested genes, top SVGs, significant SVGs, and observation metrics
Input Formats
| Format | Extension | Required Fields | Example |
|---|---|---|---|
| AnnData (preprocessed) | .h5ad |
X (normalised), layers["counts"] (raw), obsm["spatial"] |
processed.h5ad |
| Demo | n/a | --demo flag |
Runs spatial-preprocess demo first |
Input Matrix Convention
Different SVG methods have different statistical assumptions. The skill automatically selects the correct input matrix per method:
| Method | Input Matrix | Rationale |
|---|---|---|
morans |
adata.X (log-normalized) |
Squidpy spatial_autocorr computes autocorrelation on continuous expression values; not a count-distribution model |
spatialde |
adata.layers["counts"] (raw) |
NaiveDE.stabilize() applies its own variance-stabilizing transform; feeding already-normalized data breaks assumptions |
sparkx |
adata.layers["counts"] (raw) |
SPARK-X directly inputs the raw count matrix for kernel-based testing |
flashs |
adata.layers["counts"] (raw) |
FlashS exploits sparsity and count structure (binary presence + rank + count) |
Data layout requirement: Preprocessing must store raw counts before normalization:
adata.layers["counts"] = adata.X.copy() # before normalize_total + log1p
adata.X = lognorm_expr # after normalize_total + log1p
If layers["counts"] is missing, the skill will fall back to adata.raw (if available) or adata.X with a warning.
Workflow
- Load: Read preprocessed h5ad and verify spatial coordinates exist.
- Validate: Select the required expression representation and method-specific tuning flags.
- Run SVG method: Execute Moran's I, SpatialDE, SPARK-X, or FlashS.
- Filter & rank: Apply the method-appropriate adjusted significance metric and rank genes by method-specific score.
- Render the standard gallery: build the OmicsClaw narrative gallery with overview, diagnostic, supporting, and uncertainty panels.
- Export figure-ready data: write
figure_data/*.csvandfigure_data/manifest.jsonfor downstream customization. - Report and export: write
report.md,result.json,processed.h5ad, tables, and the reproducibility bundle including optional R visualization entrypoints.
Visualization Contract
OmicsClaw treats spatial-genes visualization as a two-layer system:
- Python standard gallery: the canonical result layer. This is the default output users should inspect first.
- R customization layer: an optional styling and publication layer that reads
figure_data/and does not recompute SVG statistics.
The standard gallery is declared as a recipe instead of hard-coded if/else
plot calls. Current gallery roles include:
overview: top SVG feature maps on tissue coordinates and UMAPdiagnostic: method score vs significance, plus Moran ranking when availablesupporting: top-gene score summary panel plus observation-level SVG burden context from persisted gallery metricsuncertainty: significance distribution across tested genes
This separation keeps the OmicsClaw output stable while still allowing later R-side beautification and method-specific extensions.
CLI Reference
# Standard usage (Moran's I, default)
oc run spatial-genes \
--input <processed.h5ad> --output <report_dir>
# Moran's I tuning
oc run spatial-genes \
--input <processed.h5ad> --method morans \
--morans-coord-type auto --morans-n-neighs 8 --morans-n-perms 500 \
--morans-corr-method fdr_bh --n-top-genes 30 --fdr-threshold 0.01 --output <dir>
# SpatialDE + AEH pattern grouping
oc run spatial-genes \
--input <processed.h5ad> --method spatialde \
--spatialde-min-counts 5 --spatialde-aeh-patterns 6 --output <dir>
# SPARK-X method (requires R + SPARK package)
oc run spatial-genes \
--input <processed.h5ad> --method sparkx \
--sparkx-option mixture --sparkx-num-cores 4 --sparkx-max-genes 3000 --output <dir>
# FlashS method (fast on large data)
oc run spatial-genes \
--input <processed.h5ad> --method flashs \
--flashs-n-rand-features 1000 --flashs-bandwidth 50.0 --output <dir>
# Demo mode
oc run spatial-genes --demo --output /tmp/svg_demo
# Direct script entrypoint
python skills/spatial/spatial-genes/spatial_genes.py \
--input <processed.h5ad> --method morans --output <dir>
Every successful standard OmicsClaw wrapper run, including oc run and
conversational skill execution, also writes a top-level README.md and
reproducibility/analysis_notebook.ipynb to make the output directory easier
to inspect and rerun.
Example Queries
- "Find spatially variable genes in my data using Moran's I"
- "Use SpatialDE to detect genes with spatial patterns"
Algorithm / Methodology
Moran's I (default)
- Input:
adata.X(log-normalized expression) - Spatial graph:
squidpy.gr.spatial_neighbors(...)builds a spatial graph fromobsm["spatial"]; OmicsClaw can now passcoord_typethrough instead of always forcinggeneric - Autocorrelation:
squidpy.gr.spatial_autocorr(adata, mode="moran", n_perms=..., corr_method=..., n_jobs=1)computes Moran's I for every gene - Moran's I range: -1 (perfect dispersion) to +1 (perfect clustering); 0 = random
- Filtering: Retain genes with
Moran's I > 0and the corrected significance column fromcorr_method(for examplepval_norm_fdr_bh) belowfdr_threshold; if Squidpy does not expose a corrected column, OmicsClaw falls back to rawpval_norm - Ranking: Sort by descending Moran's I statistic
Key parameters:
| Parameter | Default | Description |
|---|---|---|
--method |
morans |
morans, spatialde, sparkx, or flashs |
--n-top-genes |
20 |
Number of top SVGs to report |
--fdr-threshold |
0.05 |
FDR-corrected p-value cutoff |
--morans-coord-type |
auto |
Neighbor-graph layout hint: auto, generic, or grid |
--morans-n-neighs |
6 |
Number of spatial neighbors for generic coordinates |
--morans-n-perms |
100 |
Number of permutations for empirical p-values; 0 disables permutations |
--morans-corr-method |
fdr_bh |
Multiple-testing correction method |
SpatialDE
- Input:
adata.layers["counts"](raw counts) - Dependency: Requires
SpatialDE+NaiveDEpackages - Preprocessing: NaiveDE.stabilize() applies variance-stabilizing transform on raw counts, then regresses out total counts
- Test: Gaussian process regression comparing spatially-aware vs spatially-unaware models
- Optional AEH: OmicsClaw can optionally run
SpatialDE.spatial_patterns()to group significant genes into AEH patterns using pattern countCand lengthscalel - Output: Genes ranked by likelihood ratio statistic, with significance taken from SpatialDE
qval
Core tuning flags:
--spatialde-min-counts: Per-gene count filter before SpatialDE fitting.--spatialde-no-aeh: Skip AEH pattern grouping and only report per-gene SpatialDE statistics.--spatialde-aeh-patterns: Override AEH pattern countC.--spatialde-aeh-lengthscale: Override AEH lengthscalel.
SPARK-X
- Input:
adata.layers["counts"](raw counts) - Dependency: Requires R + SPARK R package
- Test: Non-parametric kernel-based test directly on count matrix via
spark.sparkx(counts, coords, numCores=..., option=...) - Advantage: Robust to non-linear spatial patterns, with significance taken from the SPARK-X adjusted p-value column when available
Core tuning flags:
--sparkx-option: Passed through to the R implementation; the official example usesmixture.--sparkx-num-cores: Passed through asnumCores.--sparkx-max-genes: OmicsClaw wrapper cap for very large matrices before the R call.
FlashS
- Input:
adata.layers["counts"](raw counts) - Dependency: Python native (no R required)
- Method: OmicsClaw uses a randomized-kernel / random-feature approximation inspired by FlashS's frequency-domain, multi-scale kernel design
- Advantage: Fast on large datasets (>10k spots), with OmicsClaw reporting Benjamini-Hochberg
qvalalongside the wrapper score
Core tuning flags:
--flashs-n-rand-features: Wrapper sketch size controlling approximation fidelity vs runtime.--flashs-bandwidth: Wrapper kernel bandwidth override; omitted means data-adaptive estimation.
Output Structure
output_dir/
├── README.md
├── report.md
├── result.json
├── processed.h5ad
├── figures/
│ ├── top_svg_spatial.png
│ ├── top_svg_umap.png
│ ├── top_svg_scores.png
│ ├── svg_score_vs_significance.png
│ ├── svg_significance_distribution.png
│ ├── moran_ranking.png # Moran's I only
│ └── manifest.json
├── figure_data/
│ ├── svg_results.csv
│ ├── top_svg_scores.csv
│ ├── significant_svgs.csv
│ ├── svg_observation_metrics.csv
│ ├── top_svg_spatial_points.csv
│ ├── top_svg_umap_points.csv # if X_umap is available
│ ├── svg_run_summary.csv
│ └── manifest.json
├── tables/
│ ├── svg_results.csv
│ ├── top_svg_scores.csv
│ ├── significant_svgs.csv
│ └── svg_observation_metrics.csv
└── reproducibility/
├── analysis_notebook.ipynb
├── commands.sh
├── requirements.txt
└── r_visualization.sh
README.md and reproducibility/analysis_notebook.ipynb are generated by the
standard OmicsClaw wrapper. Direct script execution usually produces the
skill-native outputs plus reproducibility/commands.sh.
The bundled repo-side R helpers live under:
skills/spatial/spatial-genes/r_visualization/
├── README.md
└── svg_publication_template.R
Dependencies
Required (Python):
scanpy>= 1.9 — single-cell/spatial analysissquidpy>= 1.2 — spatial autocorrelation and neighbor graphsmatplotlib— plottingnumpy,pandas— numerics
Optional (Python):
SpatialDE&NaiveDE— Gaussian process-based SVG detectionflashs— FlashS randomized kernel approximationstatsmodels— multiple-testing correction used by some backends and wrappers
Optional (R Environment / Subprocess):
- R system installation
SPARK(R package) — SPARK-X kernel test
Safety
- Local-first: Strict offline processing without external upload.
- Disclaimer: Reports follow the standard OmicsClaw reporting and disclaimer convention.
- Audit trail: Hyperparameters and operational flow states are logged fully.
- Stable persistence: SVG results and gallery metadata are stored in
adata.uns, while observation-level SVG summary columns are persisted inadata.obs. - Non-destructive: original expression matrices are preserved.
Integration with Orchestrator
Trigger conditions:
- Automatically invoked dynamically based on tool metadata and user intent matching.
- Keywords — spatially variable gene, spatial gene, SVG, SpatialDE, SPARK-X, spatial pattern, Moran
Chaining partners:
spatial-preprocess: Provides the preprocessed h5ad inputspatial-domains: SVGs often overlap with domain-defining genesspatial-de: Compare SVGs with cluster-based DE results