Skip to content

iscc.data.estimate_visium

Method-of-moments estimate_visium() for the Visium assay.

The spatial analogue of the scRNA estimate() and DNA estimate_dna(): fits the technical hyper-parameters of the spatial batch model (VisiumBatchHyperParams in batch.py) from a real Visium AnnData reduced to per-spot counts + spot coordinates — so realistic spatial-technical magnitudes are learned, not guessed. The fitted VisiumBatchHyperParams drive Visium directly (same field names).

This is not ABC: every fitted Visium parameter maps to a marginal / spatial summary statistic, so estimation is closed-form / 1-D curve-fit — fast and simulation-free (ABC stays for the biology).

What is fit (and from what):

mu_counts          mean per-spot library size (total UMIs / spot)            (always)
sigma_counts       NON-spatial (nugget) part of the per-spot log-library sd  (always)
field_sigma        SPATIAL (autocorrelated) part of the per-spot log-library (always)
                   sd — the capture-field strength
field_lengthscale  capture-field autocorrelation scale: squared-exponential   (always)
                   length-scale fit of the per-spot library-size residual
                   autocorrelation (Moran's-I correlogram / variogram range)
kappa (dm)         per-spot count overdispersion (DM concentration)           (always)
nb_dispersion (nb) per-spot count overdispersion phi (NB)                     (count_model=nb)
sigma_batch        per-gene cross-section log-fold-change scale               (needs >=2 sections)

The headline decomposition. The per-spot library total is mu_counts * field_s * noise_s with field_s the spatially-autocorrelated capture field (mean 1) and noise_s the i.i.d. LogNormal depth noise. So the variance of log(total) splits into a SPATIAL part (the field, recovered as the autocorrelation amplitude a at zero lag) and a NON-SPATIAL nugget (the i.i.d. noise, 1-a): field_sigma = sqrt(a * Var[log total]), sigma_counts = sqrt((1-a) * Var[log total]). This is exactly what separates the spatial technical layer from the per-spot depth noise — the spatial analogue of the scRNA estimator's library-size de-biasing of the dispersion.

The _PRIOR_ONLY escape (as in estimate/estimate_dna) carries the genuinely unidentifiable-from-one-section fields honestly: ambient_frac (needs off-tissue/background spots), edge_sigma and diffusion_sigma (confounded with biology in a single section), and sigma_batch on single-section data (the per-gene factor is constant within a section, so it is confounded with the true expression — identifiable only across >=2 sections, exactly as the scRNA estimator needs >=2 batches).

numpy / scipy only (no JAX / R); stateless and config-driven.

Classes:

Name Description
VisiumEstimate

Fitted Visium technical parameters, ready to drive Visium(...).

Functions:

Name Description
estimate_visium

Fit VisiumBatchHyperParams from a real Visium AnnData (MoM / curve-fit).

estimate_visium_from_assay

Fit from a run Visium instance (extracts per-spot counts + coords + occupancy).

VisiumEstimate dataclass

VisiumEstimate(hypers: VisiumBatchHyperParams, count_model: str, n_spots: int, n_genes: int, n_sections: int, spots_per_tissue: int, occupied_fraction: float, fitted: list, diagnostics: dict = dict())

Fitted Visium technical parameters, ready to drive Visium(...).

hypers is a VisiumBatchHyperParams with the fitted magnitudes; visium_kwargs() returns the hyper fields (minus count_model, an explicit assay constructor arg) as a kwargs dict, so the fit splats straight back into the assay without redefinition. fitted lists the fields actually learned; everything else is carried from the preset and flagged honestly. spots_per_tissue / occupied_fraction are spatial-extent diagnostics (not hyper fields).

Methods:

Name Description
visium_kwargs

Hyper-parameter overrides to splat into Visium (minus count_model).

visium_kwargs

visium_kwargs()

Hyper-parameter overrides to splat into Visium (minus count_model).

count_model is an explicit assay constructor arg, so drive the assay as Visium(count_model=est.count_model, **est.visium_kwargs()).

estimate_visium

estimate_visium(adata, *, count_model='dm', coords=None, section_labels=None, occupied_fraction=None)

Fit VisiumBatchHyperParams from a real Visium AnnData (MoM / curve-fit).

Parameters:

Name Type Description Default
adata AnnData | DataFrame | ndarray

Per-spot integer counts, spots x genes (raw, not normalized).

required
count_model (dm, nb)

Count emission (chosen). Selects kappa (DM) vs nb_dispersion (NB) as the fit target.

"dm"
coords array | None

Per-spot (row, col) coordinates (n_spots, 2). Defaults to adata.obsm['spatial'].

None
section_labels sequence | None

Per-spot section label. With >=2 sections, sigma_batch (the per-gene factor) is fit; otherwise it is carried from the preset and flagged not-fit (single-section confounding).

None
occupied_fraction float | None

Fraction of laid spots that are on-tissue. Defaults to the fraction of non-empty spots (spots with >0 counts). Sets spots_per_tissue = on-tissue spot count.

None

Returns:

Type Description
VisiumEstimate

estimate_visium_from_assay

estimate_visium_from_assay(assay, *, section_labels=None)

Fit from a run Visium instance (extracts per-spot counts + coords + occupancy).

The synthetic recovery convenience: pulls the spot count matrix, the spot coordinates, and the on-tissue fraction straight from the run assay, then defers to :func:estimate_visium.