Skip to main content

SpatialCheckpoint

PyPI version Python License: MIT

Spatial heterogeneity profiling of immune checkpoints in spatial transcriptomics data.

SpatialCheckpoint is a bioinformatics pipeline that integrates spatial gene expression profiling, consensus clustering, ensemble ML classification, SHAP interpretability, and clinical survival analysis to characterize immune checkpoint heterogeneity across the tumor microenvironment.


Installation

pip install spatialcheckpoint

Requirements: Python ≥ 3.10


CLI

# Run the built-in demo (no data files needed)
spatialcheckpoint demo

# Download a registered dataset
spatialcheckpoint download BRCA_visium_10x

# Download all BRCA datasets
spatialcheckpoint download all --cancer-type BRCA

# Preprocess raw Visium output or H5AD
spatialcheckpoint preprocess path/to/spaceranger/  data/processed/
spatialcheckpoint preprocess sample.h5ad           data/processed/

# Run full spatial analysis on a preprocessed sample
spatialcheckpoint analyze sample01

# Discover archetypes from a feature matrix CSV
spatialcheckpoint discover results/sample01/features.csv --k-min 2 --k-max 8

# Train the archetype classifier
spatialcheckpoint classify features.csv archetype_labels.csv --model-dir models/

# Generate publication figures
spatialcheckpoint figures --results-dir results/ --output-dir paper/figures/

Usage

Gene Panel

import spatialcheckpoint as scp

# 44 checkpoint genes across 6 functional categories
genes = scp.get_all_checkpoint_genes()

# Genes by category
pd1_pathway  = scp.get_category_genes("co_inhibitory_receptors")
novel        = scp.get_category_genes("novel_checkpoints")
cell_markers = scp.get_immune_cell_markers()    # {cell_type: [genes]}
lr_pairs     = scp.get_ligand_receptor_pairs()  # [{ligand, receptor, alias}]

Data Preprocessing

# From Space Ranger output directory
preprocessor = scp.SpatialDataPreprocessor(spaceranger_out_path="path/to/spaceranger/output")
adata = preprocessor.load_visium()
adata = preprocessor.quality_control(adata, min_genes=200, max_mt_pct=25.0)
adata = preprocessor.normalize(adata)
adata.write_h5ad("data/processed/sample01_preprocessed.h5ad")

# Or from an existing H5AD
preprocessor = scp.SpatialDataPreprocessor(h5_path="existing_data.h5ad")

Spatial Profiling & Feature Extraction

genes = scp.get_all_checkpoint_genes()

# Region-based expression (tumor_core, invasive_margin, stroma, …)
profiler    = scp.SpatialCheckpointProfiler(adata, genes)
region_expr = profiler.expression_by_region()
hotspots    = profiler.checkpoint_hotspot_detection()   # Moran's I per gene

# 80+ spatial features per slide
engineer = scp.SpatialFeatureEngineer(adata, genes)
features = engineer.extract_all_features(sample_id="sample01")

Archetype Discovery

# feature_matrix: DataFrame (n_samples × n_features)
# sample_metadata: DataFrame with 'cancer_type' column, same index
discovery = scp.SpatialArchetypeDiscovery(feature_matrix, sample_metadata)

cc     = discovery.consensus_clustering(k_range=(2, 8), n_iterations=100)
labels = cc["labels"]
char   = discovery.characterize_archetypes(labels)

nmf = discovery.run_nmf(k=cc["optimal_k"])
# nmf["W"]  →  (n_samples, k) soft membership weights
# nmf["H"]  →  (k, n_features) archetype profiles

Classifier Training & SHAP

trainer = scp.ArchetypeModelTrainer(
    feature_matrix=feature_matrix,
    archetype_labels=labels,
    output_dir="models/",
)
results = trainer.run(n_optuna_trials=30)

explainer = scp.ArchetypeExplainer(results["model"], feature_matrix)
shap_df   = explainer.global_feature_importance()

Demo

Runs entirely on synthetic data — no Visium files required.

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

print(f"SpatialCheckpoint v{scp.__version__}")

# ── Gene panel ───────────────────────────────────────────────────────────────
genes = scp.get_all_checkpoint_genes()
print(f"Checkpoint panel : {len(genes)} genes")
print(f"PD-1 pathway     : {scp.get_category_genes('co_inhibitory_receptors')}")

lr = scp.get_ligand_receptor_pairs()
print(f"LR pairs ({len(lr)}) e.g. {lr[0]}")

# ── Synthetic Visium slide ───────────────────────────────────────────────────
rng = np.random.default_rng(42)
cp8 = genes[:8]
dummy_genes = [f"GENE{i:04d}" for i in range(92)] + cp8

X = rng.negative_binomial(2, 0.5, size=(200, 100)).astype(float)
adata = sc.AnnData(X=X)
adata.var_names = pd.Index(dummy_genes)

gx, gy = np.meshgrid(np.arange(20), np.arange(10))
coords = np.column_stack([gx.ravel(), gy.ravel()]).astype(float)
coords += rng.uniform(-0.1, 0.1, size=coords.shape)
adata.obsm["spatial"] = coords

region_map = []
for x, y in coords:
    if   x < 5  and y < 5:  region_map.append("tumor_core")
    elif x < 10 and y < 8:  region_map.append("invasive_margin")
    elif x >= 15:            region_map.append("immune_enriched")
    elif y >= 8:             region_map.append("necrotic")
    else:                    region_map.append("stroma")

adata.obs["region_type"] = pd.Categorical(
    region_map,
    categories=["tumor_core","invasive_margin","stroma","immune_enriched","necrotic"]
)

# ── Spatial feature extraction ───────────────────────────────────────────────
engineer = scp.SpatialFeatureEngineer(adata, cp8)
features = engineer.extract_all_features(sample_id="demo")
print(f"\nFeature matrix   : {features.shape[1]} features extracted")

# ── Multi-sample archetype discovery ────────────────────────────────────────
feat_mat = pd.DataFrame(
    rng.standard_normal((30, features.shape[1])),
    index=[f"sample_{i:03d}" for i in range(30)],
    columns=features.columns,
)
meta = pd.DataFrame(
    {"cancer_type": rng.choice(["BRCA","CRC","NSCLC"], 30)},
    index=feat_mat.index,
)

discovery = scp.SpatialArchetypeDiscovery(feat_mat, meta)
cc = discovery.consensus_clustering(k_range=(2, 4), n_iterations=20)
print(f"\nOptimal k        : {cc['optimal_k']}")

char = discovery.characterize_archetypes(cc["labels"])
print("\nArchetype summary:")
print(char[["archetype_name","n_samples"]].to_string())

# ── NMF soft membership ──────────────────────────────────────────────────────
nmf = discovery.run_nmf(k=cc["optimal_k"])
print(f"\nNMF explained variance : {nmf['explained_variance']:.3f}")
print("Membership weights (first 3 samples):")
print(nmf["W"].head(3).round(3).to_string())

Gene Panel

Category Genes (examples)
Co-inhibitory receptors PDCD1 (PD-1), CTLA4, LAG3, HAVCR2 (TIM-3), TIGIT
Co-inhibitory ligands CD274 (PD-L1), PDCD1LG2 (PD-L2), LGALS9
Novel checkpoints VSIR (VISTA), CD276 (B7-H3), VTCN1 (B7-H4)
Innate checkpoints CD47, SIRPA, LILRB1, LILRB2
Immune enzymes IDO1, ENTPD1 (CD39), NT5E (CD73), ARG1
Co-stimulatory reference CD28, ICOS, TNFRSF4 (OX40), TNFRSF9 (4-1BB)

Archetypes

Archetype Spatial signature
Checkpoint-Hot High checkpoint + high immune + co-localized
Checkpoint-Cold Low checkpoint + low immune infiltration
Checkpoint-Excluded Checkpoint at margin, immune at periphery
Checkpoint-Mismatch Checkpoint and immune spatially separated
Innate-Dominant CD47/SIRPα axis dominant
Novel-Enriched VISTA / B7-H3 / B7-H4 enriched

Pipeline Architecture

Raw Visium data (Space Ranger dir or H5AD)
  → SpatialDataPreprocessor      QC, normalize → 'counts' / 'log1p' layers
  → SpatialCheckpointProfiler    region expression (tumor_core, invasive_margin,
                                  stroma, immune_enriched, necrotic)
  → SpatialFeatureEngineer       80+ features: co-localization, gradients,
                                  Moran's I, region expression ratios
  → SpatialArchetypeDiscovery    consensus KMeans + delta-area k-selection + NMF
  → ArchetypeModelTrainer        LightGBM + XGBoost + MLP + RF ensemble,
                                  SMOTE, RFECV, Optuna HPO
  → ArchetypeExplainer           SHAP global / per-class feature importance
  → ClinicalAssociationAnalyzer  KM curves, Cox PH, logistic regression (OS/PFS)

Output Files

Path Contents
results/{sample_id}/features.csv 80+ spatial features
results/{sample_id}/region_expression.csv Region × gene expression
results/{sample_id}/hotspots.csv Moran's I per gene
results/{sample_id}/colocalization.csv Ligand-receptor co-occurrence
results/archetypes/archetype_labels.csv Sample → archetype assignment
results/archetypes/nmf_W.csv, nmf_H.csv NMF basis / coefficient matrices
models/archetype_classifier.joblib Serialized ensemble model
paper/figures/ Publication-ready PDF/PNG plots

Citation

@article{spatialcheckpoint2025,
  title   = {SpatialCheckpoint: Spatial heterogeneity profiling of immune checkpoints
             in spatial transcriptomics},
  author  = {},
  journal = {},
  year    = {2025},
}

License

MIT

Metadata

Release files for spatialcheckpoint 0.1.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for spatialcheckpoint 0.1.3
File Size Uploaded
spatialcheckpoint-0.1.3.tar.gz 3.8 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for spatialcheckpoint 0.1.3
File Interpreter ABI Platform
spatialcheckpoint-0.1.3-py3-none-any.whl Python 3 none any Details

Total release size: 7.6 MB

Release files / spatialcheckpoint-0.1.3.tar.gz

Download URL spatialcheckpoint-0.1.3.tar.gz
Size 3.8 MB
Tags Source
SHA-256 checksum
How to use checksums
b39183e0cf2caa4297616d7d6996d94a45ab0e7e949eb6080f58ba5e5f6f3a2e
BLAKE2b-256 checksum
How to use checksums
10f667158d9f729ca8dc2adcf817541bd0b9bdd0a067ed313b069b0606997580
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.15

Release files / spatialcheckpoint-0.1.3-py3-none-any.whl

Download URL spatialcheckpoint-0.1.3-py3-none-any.whl
Size 3.8 MB
Tags Python 3
SHA-256 checksum
How to use checksums
3e5caeb9ccfe8155d8f09e6e0b6d0ef2a66ea6ba8db653d7256ef2a3bc1343d5
BLAKE2b-256 checksum
How to use checksums
d959b7b2459aabcea0d97f7559b5c060ff6c2ccfc13e5190f930d5683e4f4f9c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.15

Release history Release notifications | RSS feed

This release

0.1.3 This release

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page