domains / science / spatial-transcriptomics-preprocessing / spatial-preprocessing
The two skills cover the same task but disagree on the core procedure. The first copy (OpenClaw) provides a standard, platform-agnostic pipeline using Scanpy/Squidpy with fixed thresholds (min_counts=500, min_genes=200) and standard normalization (CP10k/log1p or Pearson residuals). The second copy (GPTomics) explicitly argues that these standard thresholds and normalization methods are incorrect for imaging-based spatial platforms (Xenium, MERFISH, CosMx), stating that they delete real cells and introduce bias. It mandates a 'platform-class fork' decision and different QC/normalization strategies (e.g., area/volume normalization) for imaging data. Because the first copy's procedure is actively contradicted by the second for a major subset of spatial data, crowning one would hide a critical alternative workflow.
| Repository | Path |
|---|---|
| FreedomIntelligence/OpenClaw-Medical-Skills | skills/spatial-transcriptomics-analysis/bioSkills/spatial-preprocessing/SKILL.md |
| GPTomics/bioSkills | spatial-transcriptomics/spatial-preprocessing/SKILL.md |
| Role | Repository | Path |
|---|---|---|
| peer | FreedomIntelligence/OpenClaw-Medical-Skills | skills/spatial-transcriptomics-analysis/bioSkills/spatial-preprocessing/SKILL.md |
| peer | GPTomics/bioSkills | spatial-transcriptomics/spatial-preprocessing/SKILL.md |
# Spatial Preprocessing
## 1. Determine Platform Class
Before applying any thresholds, identify the assay family:
- **Sequencing/Spot** (Visium, Slide-seq, Stereo-seq): Unit is a spot (1-10 cells). Library size confounds with cellularity.
- **Imaging/In-situ** (Xenium, MERFISH, CosMx): Unit is a segmented cell. Library size confounds with cell area/size. Targeted panel.
## 2. Calculate QC Metrics
```python
import squidpy as sq
import scanpy as sc
# Standard metrics
sc.pp.calculate_qc_metrics(adata, inplace=True)
# Mitochondrial (only if on-panel)
if 'MT-' in adata.var_names.values:
adata.var['mt'] = adata.var_names.str.startswith('MT-')
sc.pp.calculate_qc_metrics(adata, qc_vars=['mt'], inplace=True)
```
## 3. Filter Spots/Cells
**Choose thresholds based on platform:**
- **Sequencing/Spot:** Use standard scRNA-like floors (e.g., `min_counts=500-1000`, `min_genes=200-500`). Filter high mito% (<20%).
- **Imaging/In-situ:** Use low transcript floors (e.g., `min_counts=10-20`). Do NOT use high gene counts (ceilinged by panel). Do NOT use mito% if off-panel. Consider cell area/size metrics.
```python
# Example for Sequencing
sc.pp.filter_cells(adata, min_counts=500)
sc.pp.filter_cells(adata, min_genes=200)
# Example for Imaging
sc.pp.filter_cells(adata, min_counts=10)
```
## 4. Filter Genes
Remove genes detected in too few cells/spots.
```python
sc.pp.filter_genes(adata, min_cells=10)
```
## 5. Normalization
**Choose method based on platform:**
- **Sequencing/Spot:** Standard CP10k + log1p or Pearson residuals (SCTransform-like).
- **Imaging/In-situ:** Avoid gene-count-based normalization (CP10k, Pearson) on skewed panels. Use cell volume/area normalization or spatially-aware methods (e.g., SpaNorm) to avoid region-specific bias.
```python
# Sequencing
adata.layers['counts'] = adata.X.copy()
sc.pp.normalize_total(adata, target_sum=1e4)
sc.pp.log1p(adata)
# Imaging (Pseudocode for area normalization)
# adata.X = adata.X / adata.obs['cell_area']
```
## 6. Feature Selection
Identify Highly Variable Genes (HVGs) and Spatially Variable Genes (SVGs).
```python
# HVGs
sc.pp.highly_variable_genes(adata, n_top_genes=2000, flavor='seurat_v3', layer='counts')
# SVGs (requires spatial neighbors)
sq.gr.spatial_neighbors(adata, coord_type='generic', n_neighs=6)
sq.gr.spatial_autocorr(adata, mode='moran', genes=adata.var_names[:1000])
```
## 7. Scale and PCA
```python
sc.pp.scale(adata, max_value=10)
sc.tl.pca(adata, n_comps=50)
```
## 8. Visualize QC Spatially
Always inspect QC metrics on the tissue image to detect spatial artifacts (e.g., edge effects, hybridization failures) that 1D distributions miss.
```python
sq.pl.spatial_scatter(adata, color=['total_counts', 'n_genes_by_counts'])
```