domains / science / spatial-transcriptomics-statistics / spatial-statistics

spatial-statistics

Skill card

combined

The two skills cover the same domain but with different depth and scope. The first copy (OpenClaw) is a practical, code-heavy recipe for running specific Squidpy functions (Moran's I, Geary's C, co-occurrence, etc.) and interpreting basic outputs. The second copy (GPTomics) is a methodological guide that emphasizes the statistical pitfalls (cell-type confounding, null model choice, graph sensitivity) and provides a decision framework for choosing between different SVG methods (SpatialDE, SPARK, SPARK-X, nnSVG, Moran's I). The first copy lacks the critical methodological warnings and the broader method selection logic, while the second copy is truncated and lacks the specific code implementation details for the basic Squidpy workflows. Combining them provides both the 'how-to' code and the 'why/when' statistical reasoning.

Repositories

RepositoryPath
FreedomIntelligence/OpenClaw-Medical-Skillsskills/spatial-transcriptomics-analysis/bioSkills/spatial-statistics/SKILL.md
GPTomics/bioSkillsspatial-transcriptomics/spatial-statistics/SKILL.md

Other copies

RoleRepositoryPath
peerFreedomIntelligence/OpenClaw-Medical-Skillsskills/spatial-transcriptomics-analysis/bioSkills/spatial-statistics/SKILL.md
peerGPTomics/bioSkillsspatial-transcriptomics/spatial-statistics/SKILL.md

Combined skill

# Spatial Statistics for Spatial Transcriptomics

## 1. Method Selection & Statistical Caveats
Before running any code, determine the biological question:
- **Tissue Organization:** If the goal is to find where tissue is organized, sample-wide Spatially Variable Gene (SVG) detection is appropriate. Note that these will largely overlap with cell-type markers.
- **Within-Type Regulation:** If the goal is to find genes regulated *within* a cell type, sample-wide SVG is the wrong tool. Use cell-type-aware methods (e.g., C-SIDE, CTSV) or regress out cell-type composition first.
- **Null Model Awareness:** All spatial statistics depend on the neighbor graph (kNN k) and the null model. Results are sensitive to these choices. Always report the graph parameters and consider if results hold under a different k or null.

**SVG Method Choice:**
- **Small Data (Visium, <1e4 spots):** SpatialDE (Gaussian) or SPARK (Poisson).
- **Large Single-Cell Data (MERFISH/Xenium, >1e4 cells):** SPARK-X or nnSVG (linear scaling).
- **Quick Screen:** Moran's I / Geary's C (fast, but single-scale).

## 2. Required Imports
```python
import squidpy as sq
import scanpy as sc
import pandas as pd
import numpy as np
# For local statistics
from esda.moran import Moran_Local
from libpysal.weights import KNN
```

## 3. Compute Spatial Autocorrelation (Moran's I / Geary's C)
*Use for quick screening on an existing neighbor graph.*

```python
# Ensure spatial neighbors are built (e.g., k=6)
sq.gr.spatial_neighbors(adata, coord_type='generic', n_neighs=6)

# Compute Moran's I
sq.gr.spatial_autocorr(adata, mode='moran')
moran_results = adata.uns['moranI']

# Interpretation:
# I > 0: Positive autocorrelation (clustering)
# I < 0: Negative autocorrelation (dispersion)
# Filter for significant genes (p < 0.05)
svg = moran_results[moran_results['pval_norm'] < 0.05].sort_values('I', ascending=False)
```

## 4. Local Statistics (LISA)
*Use to identify specific hot/cold spots for a gene.*

```python
# Build weights matrix for local analysis
coords = adata.obsm['spatial']
w = KNN.from_array(coords, k=6)
w.transform = 'r'

# Compute Local Moran's I for a specific gene
gene_expr = adata[:, 'GENE1'].X.toarray().flatten()
lisa = Moran_Local(gene_expr, w)

# Store results
adata.obs['GENE1_lisa'] = lisa.Is
adata.obs['GENE1_lisa_q'] = lisa.q  # Quadrant: HH, HL, LH, LL
```

## 5. Cell-Type Co-occurrence & Enrichment
*Use to test if specific cell types are spatially associated.*

```python
# Ensure cluster labels exist (e.g., Leiden)
sc.pp.neighbors(adata)
sc.tl.leiden(adata)

# Co-occurrence
sq.gr.co_occurrence(adata, cluster_key='leiden')
sq.pl.co_occurrence(adata, cluster_key='leiden')

# Neighborhood Enrichment
sq.gr.nhood_enrichment(adata, cluster_key='leiden')
sq.pl.nhood_enrichment(adata, cluster_key='leiden')

# Interpretation:
# zscore > 0: Clusters co-localize more than expected
# zscore < 0: Clusters avoid each other
```

## 6. Validation & Reporting
- Report the kNN parameter used for the neighbor graph.
- If using sample-wide SVG, acknowledge the potential for cell-type marker confounding.
- Cross-validate significant hits with a second method or a different graph k if possible.