Skip to main content

spatioloji_s

Tests PyPI version Release License: MIT Python DOI

spatioloji_s is a Python package for image-based spatial transcriptomics analysis, purpose-built for CosMx, MERFISH, and Xenium. It provides an integrated workflow from raw data loading through quality control, processing, spatial analysis, and polygon-native cell-cell communication.


Key Features

  • Custom data structure --- A spatioloji object that unifies expression matrices, cell metadata, spatial coordinates, cell polygons, and FOV images under a single master cell index.
  • Two spatial modes --- Point-based (centroid, fast) and polygon-based (boundary geometry, accurate) analysis with shared interface, gradient, infiltration, and motif APIs.
  • Polygon-native CCC --- Cell-cell communication using actual membrane geometry, not centroid distance. Edge-level scoring with exponential distance decay, analytical and permutation significance testing, interface zone stratification, and morphology-aware analysis.
  • 80+ visualization functions --- Embedding plots, spatial maps (dot and polygon), neighborhood enrichment, Ripley's K/L, morphology, CCC heatmaps/networks/gradients, motif maps, and more.
  • Comprehensive processing --- Normalization, HVG selection (6 methods), PCA/UMAP/tSNE/diffusion maps, Leiden/KMeans/hierarchical clustering, DEG (5 methods), batch correction (ComBat, Harmony, scVI), imputation, and gene set scoring.

Installation

pip install spatioloji-s

Requires Python >= 3.12.

Optional extras:

pip install "spatioloji-s[clustering]"   # Leiden (leidenalg + igraph)
pip install "spatioloji-s[reduction]"    # UMAP
pip install "spatioloji-s[batch]"        # Harmony, ComBat
pip install "spatioloji-s[deg]"          # DESeq2, statsmodels
pip install "spatioloji-s[anndata]"      # AnnData/scanpy interop
pip install "spatioloji-s[annotation]"   # Cell type annotation (CellTypist)
pip install "spatioloji-s[decoupler]"    # Pathway scoring
pip install "spatioloji-s[ripley]"       # Ripley's K/L
pip install "spatioloji-s[all]"          # All of the above

[all] covers every pip-installable analysis feature. The deep-learning imputation backends are excluded on purpose — scVI and MAGIC are meant to run in a dedicated environment (pass conda_env= to scvi_impute / magic_impute), and pulling PyTorch into a default install costs several GB. Install them in-process with pip install "spatioloji-s[imputation]" if you prefer.

Not sure what you have? spatioloji_s info lists every optional feature and whether it is available.


Quick Start

import spatioloji_s as sj

# 1. Load data
sp = sj.spatioloji(
    expression=expression_df,
    cell_meta=cell_meta_df,
    spatial_coords=spatial_df,
    polygons=polygon_dict,
)

# 2. Process
sj.processing.normalize_total(sp)
sj.processing.log_transform(sp)
sj.processing.pca(sp)
sj.processing.umap(sp)
sj.processing.leiden_clustering(sp)

# 3. Spatial analysis
from spatioloji_s.spatial.polygon import build_buffer_graph, neighborhood_enrichment
graph = build_buffer_graph(sp, buffer_distance=15)
neighborhood_enrichment(sp, graph, "cell_type")

# 4. Cell-cell communication
from spatioloji_s.ccc import CCCConfig, run_ccc
config = CCCConfig(group_col="cell_type", layer="log_normalized")
result = run_ccc(sp, config)

# 5. Visualize
sj.visualization.plot_umap(sp, color_by="cell_type")
sj.visualization.plot_ccc_heatmap(result)
sj.visualization.plot_ccc_network(result)

Module Overview

Module Functions Description
sj.data 12 Core spatioloji object, QC, image handling, export
sj.processing 44 Normalization, HVG, dim reduction, clustering, DEG, batch correction, imputation, gene sets
sj.spatial.point 30 Centroid-based: KNN/radius/Delaunay graphs, neighborhoods, Moran's I, Getis-Ord, Ripley's K/L, motifs
sj.spatial.polygon 35 Polygon-based: contact graphs, morphology, boundaries, neighborhoods, interface, gradient, infiltration, motifs
sj.ccc 14 LR database, edge scoring, significance testing, zone/gradient/morphology stratification
sj.visualization 74 Embedding, spatial maps, point/polygon analysis, CCC plots

Cell-Cell Communication

spatioloji_s uses polygon geometry for biologically accurate CCC inference:

Scoring formula: score(i,j) = sqrt(L_i x R_j) x w_ij

Signal type Weight w_ij Graph
Juxtacrine contact_frac_a x contact_frac_b Polygon contact graph
Secreted exp(-distance / sigma) Radius graph (default 200 um)
ECM exp(-distance / sigma) Radius graph

Sizing the radius: expected neighbors per cell ≈ π·r²·density, so edge count (memory and run time) grows quadratically with the radius. The 200 µm default suits sparse tissue — at ~6,000 cells/mm² (a typical Xenium tumor section) it already means ~740 neighbors per cell; use ~100 µm there and less for denser tissue (e.g. 75 µm for a reactive lymph node at ~15,000 cells/mm²).

Features:

  • 50 built-in LR pairs + CellChatDB (3,234 interactions) support
  • Analytical z-score (fast) or permutation significance testing with BH-FDR
  • Interface zone comparison --- interface vs. interior enrichment
  • Communication gradient --- OLS regression of score vs. signed distance
  • Morphology stratification --- CCC by sender cell shape (round/elongated)
  • Fitted contact radii --- per-cell-type centroid radius as a fast stand-in for the polygon contact graph (see below)
Feature CellChat COMMOT SpatialDM spatioloji_s
Single-cell resolution Partial Yes Partial Yes
Polygon contact geometry No No No Yes
Spatial edge scoring No OT (centroid) Moran's I sqrt(LR) x w
Interface zone analysis No No No Yes
Communication gradient No No No Yes
Morphology stratification No No No Yes
Significance testing Permutation No Permutation Both

Fitted contact radii (when polygons are missing or too slow)

Juxtacrine signalling needs a contact graph, and polygons are the accurate source. Where they are unavailable — a sample whose boundaries were never exported — or too expensive, a centroid radius graph stands in. A single radius cannot serve a tissue whose cell types differ in size, so optimize_contact_radius fits one per cell type against the polygon graph:

from spatioloji_s.ccc.radius import build_typed_radius_graph, optimize_contact_radius

fit = optimize_contact_radius(sp_roi, group_col="cell_type")
fit.radius_map            # {'Tumor': 12.0, 'Mast': 10.0, ...} — covers every type
fit.per_type              # best_radius, jaccard, missed_rate, false_rate, low_evidence
fit.per_pair              # the same optimum per cell-type pair

# apply it: directly, or through the pipeline
graph = build_typed_radius_graph(sp, fit.radius_map)          # d <= max(r_i, r_j)
result = run_ccc(sp, CCCConfig(juxtacrine_radius_map=fit.radius_map))

What it buys, measured on two Xenium ROIs (ovarian carcinoma, 14k cells; reactive lymph node, 48k cells):

Ovarian carcinoma Reactive lymph node
fitted radii 10–12 um (7 types) 8 um (all 8 types)
edge agreement with polygon contact (Jaccard) 0.63 0.79
graph build time 0.1 s vs 15.3 s (polygon) 0.2 s vs 66.5 s (polygon)

The graph is built 100–300x faster, and the tissue difference is the point: in the dense, uniform lymph node one radius serves every cell type, while the morphologically heterogeneous tumour pulls the per-type optima apart and agrees less well with real contact.

Read the fit as a diagnosis, not a free win. Agreement peaks at 0.67–0.80 across tissues even when the radius is fitted against the ground truth, so the approximation is good, never exact — optimize_contact_radius warns when your tissue fits poorly. Downstream, juxtacrine scores keep their ranking (Spearman rho 0.92–0.95 against the polygon result) but significance is conservative: on these ROIs the radius graph recovered 22/32 and 19/48 of the polygon graph's significant calls. Use it for speed and for data without polygons; use the polygon graph when a call list is the deliverable.


Spatial Analysis Highlights

Interface & Gradient

from spatioloji_s.spatial.polygon import identify_interface, compute_gradient

iface = identify_interface(sp, group_col="cell_type", region_a="Tumor", region_b="Stroma")
grad = compute_gradient(sp, iface, genes=["TGFB1", "VIM"])

Morphology

from spatioloji_s.spatial.polygon import compute_morphology, classify_morphology

compute_morphology(sp, store=True)  # area, circularity, elongation, solidity, ...
classify_morphology(sp)             # round / intermediate / elongated

Spatial Motifs

from spatioloji_s.spatial.polygon import run_motif_pipeline

motifs = run_motif_pipeline(sp, graph, group_col="cell_type", match_builtin="TME")
# Built-in: TLS, tumor buds, immune aggregate, perivascular niche, immune desert

Data Structure

The spatioloji object stores all data aligned to a master cell index:

Component Type Description
sp.expression ExpressionMatrix Sparse/dense gene x cell matrix (auto-switched)
sp.cell_meta pd.DataFrame Per-cell metadata, QC metrics, cluster labels
sp.gene_meta pd.DataFrame Per-gene metadata (NegProbe flags, HVG status)
sp.spatial SpatialData Global and local x/y coordinates
sp.polygons GeoDataFrame Cell boundary polygons (Shapely)
sp.images ImageHandler Lazy-loaded FOV images with LRU cache
sp.embeddings dict PCA, UMAP, tSNE, diffusion map coordinates
sp.layers dict Named expression layers (raw, normalized, scaled)

Examples

Example notebooks are being reworked alongside the documentation rebuild. The workflows they cover:

  • Basic Workflow --- Loading, QC, normalization, clustering, visualization
  • Spatial Analysis --- Graphs, neighborhoods, Moran's I, interface detection
  • CCC Analysis --- LR scoring, significance, zone comparison, morphology
  • Interface Detection --- Tumor-stroma boundary, gradient analysis
  • Pathway Scoring --- Gene set analysis via decoupler

Citation

If you use spatioloji_s in your research, please cite it. Use the "Cite this repository" button on the GitHub repository page (generated from CITATION.cff), or cite the archived release on Zenodo via the DOI badge above --- the concept DOI always resolves to the latest version.


License

MIT License --- see LICENSE for details.


Contributing

Contributions are welcome! See CONTRIBUTING.md.

git clone https://github.com/gynecoloji/spatioloji_s.git
cd spatioloji_s
pip install -e ".[test]"
pytest tests/ -v
ruff check src/ tests/ --fix

Commits follow Conventional Commits; versioning, CHANGELOG.md, and releases are automated with release-please. See RELEASING.md.

Metadata

Release files for spatioloji-s 1.0.0

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

Source distribution (sdist)

Source distribution for spatioloji-s 1.0.0
File Size Uploaded
spatioloji_s-1.0.0.tar.gz 397.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for spatioloji-s 1.0.0
File Interpreter ABI Platform
spatioloji_s-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 748.8 kB

Release files / spatioloji_s-1.0.0.tar.gz

Download URL spatioloji_s-1.0.0.tar.gz
Size 397.8 kB
Tags Source
SHA-256 checksum
How to use checksums
6c71bde0799786233a320164d84f4bb016594ff93b5d355c550f367f40d1701f
BLAKE2b-256 checksum
How to use checksums
de1adb192df5a3fa9a62cf60be115692e676b2ca8bb055ecfd0ad0923b50a357
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.

Transparency log

Release files / spatioloji_s-1.0.0-py3-none-any.whl

Download URL spatioloji_s-1.0.0-py3-none-any.whl
Size 351.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
85c100bd6baa2d1487bdef87a93811475500d9938fa910acac11fc54e86ff619
BLAKE2b-256 checksum
How to use checksums
67b60c022b2547d2e8708a3733bdee4afbbb057ef9f8ea376c54801fc3ece877
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.

Transparency log

Release history Release notifications | RSS feed

2.0.1

2 release files

2.0.0

2 release files

This release

1.0.0 This release

2 release files

0.6.0

2 release files

0.5.2

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.9

2 release files

0.4.8

2 release files

0.4.7

2 release files

0.4.6

2 release files

0.4.5

2 release files

0.4.4

2 release files

0.4.3

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.3.0

2 release files

0.2.0

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