Getting Started: Single-Slice Analysis
This tutorial is fully self-contained. It creates a deterministic synthetic spatial transcriptomics dataset, trains Mievformer, and uses reference-probability correspondence analysis (CA) for niche clustering and UMAP. The complete executable version is provided as run_tutorial.py.
1. Create spatial data
Mievformer requires a cell representation in adata.obsm[‘X_pca’] and spatial coordinates in adata.obsm[‘spatial’]. The tutorial generator creates 120 cells with three spatially organized cell types:
import numpy as np
import pandas as pd
import scanpy as sc
rng = np.random.default_rng(7)
side_x, side_y = 12, 10
spatial = np.stack(
np.meshgrid(np.arange(side_x), np.arange(side_y)), axis=-1
).reshape(-1, 2)
spatial = spatial + rng.normal(scale=0.08, size=spatial.shape)
cell_type_index = np.digitize(spatial[:, 0], bins=[4.0, 8.0])
cell_types = np.asarray(['TypeA', 'TypeB', 'TypeC'])[cell_type_index]
means = np.full((spatial.shape[0], 30), 1.2)
for group in range(3):
means[cell_type_index == group, group * 5:(group + 1) * 5] += 3.0
counts = rng.poisson(means).astype(np.float32)
u, s, _ = np.linalg.svd(
counts - counts.mean(axis=0, keepdims=True), full_matrices=False
)
adata = sc.AnnData(
counts,
obs=pd.DataFrame(
{'cell_type': cell_types},
index=[f'cell_{i:03d}' for i in range(spatial.shape[0])],
),
)
adata.var_names = [f'Gene_{i:02d}' for i in range(adata.n_vars)]
adata.obsm['spatial'] = spatial.astype(np.float32)
adata.obsm['X_pca'] = (u[:, :10] * s[:10]).astype(np.float32)
For real data, replace this block with your AnnData object while keeping the same two obsm keys.
2. Train and calculate the standard CA view
optimize_nicheformer now performs model training, score-weight calculation, CA, neighbors, UMAP, and Leiden clustering in one call:
import torch
import mievformer as mf
adata = mf.optimize_nicheformer(
adata,
model_path='tutorial_model.pth',
ngpu=1 if torch.cuda.is_available() else 0,
max_epochs=1, # Increase for real analysis
batch_size=32,
latent_dim=6,
neighbor_num=5, # Use a larger context for real datasets
ca_reference_num=30, # Omit for the adaptive default up to 1000
ca_n_components=5, # Omit to use automatic dimension selection
niche_n_neighbors=10,
random_state=7,
)
The standard representation contract is:
AnnData key |
Meaning |
|---|---|
obsm[‘mievformer_raw_e’] |
Raw neural-network embedding |
obsm[‘reference_probability_ca’] |
Reference-probability CA scores |
obsm[‘e’] |
Alias of the standard CA scores |
obsm[‘X_umap’] |
UMAP calculated from CA |
obs[‘leiden_e’] |
Leiden clusters calculated from CA |
uns[‘mievformer_default_representation’] |
Strategy and provenance |
Use representation_mode=’raw’ only for a controlled legacy comparison.
3. Downstream density-ratio analysis
The score weights are already available after optimization. The existing density-ratio and niche-membership APIs therefore work directly:
adata = mf.calculate_niche_density_ratio(
adata, ref_num=30, stratify_key='leiden_e'
)
adata = mf.calculate_niche_cluster_membership(adata)
adata = mf.estimate_population_density(
adata,
group='TypeA',
cluster_key='cell_type',
max_cell_num=30,
)
corrs = mf.analyze_density_correlation(
adata,
density_col='TypeA_density',
file_path='density_correlation.png',
)
adata = mf.analyze_niche_membership(
adata,
n_clusters=3,
file_path='niche_composition_clustermap.png',
)
For multiple spatial samples, continue with the multi-batch tutorial.