1. Getting Started#
This notebook demonstrates a minimal end-to-end workflow using synthetic data. No project files or large datasets are required.
Pipeline phase: Covers Phases 3 and 3.5b in brief.
What you will learn:
Create a synthetic AnnData with spatial coordinates
Run the preprocessing recipe for Visium data
Score Hallmark gene sets
Produce a basic spatial plot
import numpy as np
import anndata as ad
import sc_tools as st
print(f"sc_tools version: {st.__version__}")
Create a synthetic Visium-like AnnData#
In a real workflow this would be a Phase 1 checkpoint loaded from disk:
adata = ad.read_h5ad("results/adata.raw.p1.h5ad")
np.random.seed(42)
n_spots, n_genes = 500, 200
# Raw count matrix (integer)
X = np.random.negative_binomial(5, 0.5, size=(n_spots, n_genes)).astype(float)
# Gene names: first 10 are Hallmark HYPOXIA genes (for scoring demo)
hallmark_genes = ["ALDOA", "CDKN3", "ENO1", "LDHA", "PGK1", "TPI1", "VEGFA", "HK1", "HK2", "PFKL"]
gene_names = hallmark_genes + [f"GENE_{i}" for i in range(n_genes - len(hallmark_genes))]
# Spatial coordinates (grid layout)
row_idx, col_idx = np.divmod(np.arange(n_spots), 25)
spatial_coords = np.column_stack([col_idx * 100, row_idx * 100]).astype(float)
adata = ad.AnnData(
X=X,
obs={"sample": "sample_A", "library_id": "lib_A"},
var={"gene_ids": gene_names},
obsm={"spatial": spatial_coords},
)
adata.var_names = gene_names
adata.obs_names = [f"spot_{i}" for i in range(n_spots)]
print(adata)
Phase 3: Preprocess#
The preprocess recipe handles normalization, HVG selection, PCA, neighbors,
UMAP, and Leiden clustering in one call. For Visium data the default
integration is scvi; we use harmony here to avoid the heavy dependency.
st.pp.preprocess(
adata,
modality="visium",
integration="harmony",
batch_key=None, # single sample — no batch correction
n_top_genes=100,
n_pcs=20,
resolution=0.5,
)
print("Clusters:", adata.obs["leiden"].value_counts().to_dict())
Phase 3.5b: Score gene signatures#
Load the bundled MSigDB Hallmark gene sets and score them against the data.
Scores are written to adata.obsm['signature_score'] and adata.obsm['signature_score_z'].
# Load bundled Hallmark sets (offline — no network required)
hallmark = st.tl.load_hallmark()
print(f"Loaded {len(hallmark)} Hallmark gene sets")
# Score (scanpy method by default)
st.tl.score_signature(adata, hallmark)
# Inspect available score columns
from sc_tools.utils.signatures import get_signature_columns
cols = get_signature_columns(adata)
print(f"Scored {len(cols)} signatures. First 5: {cols[:5]}")
Save Phase 3.5b checkpoint#
In a real project, save to the standard checkpoint path:
adata.write_h5ad("results/adata.normalized.scored.p35.h5ad")
Next steps#
QC deep-dive: See Tutorial 2 — QC and Filtering
Preprocessing details: See Tutorial 3 — Preprocessing
Gene signature scoring: See Tutorial 4 — Gene Signature Scoring
API reference: See the API docs for
sc_tools.ppandsc_tools.tl