Skip to content
Development
Skill

/spatial-domain-detection

Spatial domain detection (tissue regions / niches) for spatial transcriptomics: SpaGCN (expression + spatial graph + H&E histology, Visium/ST), GraphST (self-supervised graph contrastive embedding, spots or cells) and UTAG (spatial message passing for Xenium/MERFISH/CosMx/IMC

BOOST
From plugin
sciagent-skills
382200 skills
Install
$ npx -y skills add jaechang-hits/SciAgent-Skills --skill spatial-domain-detection --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/spatial-domain-detection

Context preview

The summary Claude sees to decide when to auto-load this skill.

Spatial domain detection (tissue regions / niches) for spatial transcriptomics: SpaGCN (expression + spatial graph + H&E histology, Visium/ST), GraphST (self-supervised graph contrastive embedding, spots or cells) and UTAG (spatial message passing for Xenium/MERFISH/CosMx/IMC

SKILL.md

spatial-domain-detection.SKILL.md
name: "spatial-domain-detection"
description: "Spatial domain detection (tissue regions / niches) for spatial transcriptomics: SpaGCN (expression + spatial graph + H&E histology, Visium/ST), GraphST (self-supervised graph contrastive embedding, spots or cells) and UTAG (spatial message passing for Xenium/MERFISH/CosMx/IMC cells). Outputs a domain label per spot or cell, boundary refinement, cross-method agreement (ARI) and domain marker genes. For niches defined by the cell type composition of annotated cells use Step 7 of spatial-transcriptomics-cell-type-annotation; for neighbourhood enrichment and spatial statistics use spatial-transcriptomics-analysis-squidpy."
license: "CC-BY-4.0"

Spatial Domain Detection

Overview

Split a tissue section into spatially coherent regions (cortical layers, tumour core vs stroma, germinal centres) from expression plus location. Each method returns one domain label per spot or cell. Output: domain labels from one or more methods, their agreement, domain marker genes and domain maps.

| Method | Data | Uses | Compute | |---|---|---|---| | SpaGCN | Visium / ST spots, optionally with the H&E image | Expression + spatial graph + histology colour | CPU, minutes | | GraphST | Spots or cells up to ~30k observations | Contrastive graph embedding | GPU preferred (torch) | | UTAG | Single-cell resolution (Xenium, MERFISH, CosMx, IMC) | Expression averaged over a radius | CPU, scales to 10^5-10^6 cells | | Composition niches | Annotated single cells | Cell type mix of the neighbourhood | CPU; Step 7 of `spatial-transcriptomics-cell-type-annotation` |

Domains are clusters, not ground truth: run two methods and report where they agree.

When to Use

  • Dividing a Visium or ST section into tissue regions such as layers, tumour core and stroma
  • Using the H&E image together with expression to draw region boundaries (SpaGCN)
  • Finding cellular niches in Xenium, MERFISH, CosMx or IMC data without labels (UTAG)
  • Getting region labels to summarise deconvolved compositions or cell types by
  • Checking whether two independent methods agree on the main boundaries
  • Use Step 7 of `spatial-transcriptomics-cell-type-annotation` instead when cells are already annotated and niches should be defined by cell type mix
  • For neighbourhood enrichment or spatially variable genes, use `spatial-transcriptomics-analysis-squidpy`

Prerequisites

  • **Input**: raw counts in `X` (or `layers["counts"]`) and coordinates in `obsm["spatial"]`
  • **SpaGCN**: pulls torch. Its Louvain init needs `louvain`, which has no Python 3.13

conda build or wheel and cannot be compiled here; without it use the k-means init (Step 3)

  • **GraphST**: pulls torch; a CUDA GPU makes training ~10x faster; the dense

spot-by-spot graph limits it to ~30k observations

  • **UTAG**: not on PyPI; install from GitHub
# Install only what `import` reports missing. `--pypi` keeps the env's scanpy/numba
# stack; a conda add can swap it and bare pip can shadow it.
pixi add --pypi scanpy SpaGCN GraphST
pixi add --pypi "utag @ git+https://github.com/ElementoLab/utag.git@main"

Workflow

1. Load Visium data (or your own) 2. Preprocess 3. SpaGCN domains (spots, with histology) 4. GraphST domains (spots or cells) 5. UTAG domains (single-cell resolution) 6. Compare methods and characterise domains

Step 1: Load Visium Data

For your own Space Ranger output set `OUTS` to the `outs/` folder and skip the download. The demo is the 10x mouse brain (sagittal anterior) section.

import json
import tarfile
import urllib.request
from pathlib import Path

import numpy as np
import pandas as pd
import scanpy as sc

CACHE = Path("data_cache/V1_Mouse_Brain_Sagittal_Anterior")
BASE = ("https://cf.10xgenomics.com/samples/spatial-exp/1.1.0/V1_Mouse_Brain_Sagittal_Anterior/"
        "V1_Mouse_Brain_Sagittal_Anterior_")
CACHE.mkdir(parents=True, exist_ok=True)
for name in ["filtered_feature_bc_matrix.h5", "spatial.tar.gz"]:
    if not (CACHE / name).exists():
        urllib.request.urlretrieve(BASE + name, CACHE / name)          # ~20 MB + ~9 MB
if not (CACHE / "spatial").exists():
    with tarfile.open(CACHE / "spatial.tar.gz") as tar:
        tar.extractall(CACHE, filter="data")
OUTS = CACHE                                    # your data: Path("path/to/outs")

SPATIAL_DIR = OUTS / "spatial"
adata = sc.read_10x_h5(OUTS / "filtered_feature_bc_matrix.h5")
adata.var_names_make_unique()
cols = ["in_tissue", "array_row", "array_col", "pxl_row", "pxl_col"]
if (SPATIAL_DIR / "tissue_positions.csv").exists():                    # Space Ranger >= 2.0
    pos = pd.read_csv(SPATIAL_DIR / "tissue_positions.csv", index_col=0)
    pos.columns = cols
else:                                                                   # older, no header
    pos = pd.read_csv(SPATIAL_DIR / "tissue_positions_list.csv", header=None, index_col=0, names=cols)
adata.obs = adata.obs.join(pos, how="left")
adata.obsm["spatial"] = adata.obs[["pxl_col", "pxl_row"]].to_numpy(float)   # x, y in full-res pixels
scale = json.loads((SPATIAL_DIR / "scalefactors_json.json").read_text())
print(adata)

Step 2: Preprocess

adata.var["mt"] = adata.var_names.str.upper().str.startswith("MT-")
sc.pp.calculate_qc_metrics(adata, qc_vars=["mt"], inplace=True)
sc.pp.filter_cells(adata, min_counts=500)       # Visium; use ~10 for imaging panels
sc.pp.filter_genes(adata, min_cells=10)
adata.layers["counts"] = adata.X.copy()         # SpaGCN and GraphST start from counts
sc.pp.normalize_total(adata)
sc.pp.log1p(adata)
print(f"{adata.n_obs} spots, {adata.n_vars} genes, median mt% {adata.obs['pct_counts_mt'].median():.1f}")

Step 3: SpaGCN (Visium with H&E)

SpaGCN smooths expression over a graph whose edges combine spot distance and histology colour, then clusters with a graph convolutional network. Coordinates passed with the image must be **(image row, image column)** at the image's scale.

import random

import SpaGCN as spg
Read more
Ships withsciagent-skills

Turn your AI coding agent into a life sciences expert — 199 bioinformatics skills for Claude Code covering RNA-seq, single-cell analysis, genomics, proteomics, drug discovery, and more. Boosted BixBench from 65% to 92%. Open source.

Get the whole plugin

Other skills on sciagent-skills.