3D Pipeline Tutorial#
This tutorial demonstrates how to use InterSCellar for 3D spatial omics analysis. The 3D pipeline has three steps:
Neighbor Graph: detect neighboring cells and build a cell neighbor graph.
Volume: compute the interscellar volume between each pair of neighboring cells, using either the absolute or the adaptive pathway.
Score: quantify biomarker expression inside each interscellar volume.
Step 1: Neighbor Graph#
First, detect cell neighbors in 3D space:
import interscellar
neighbors_3d, adata, conn = interscellar.find_cell_neighbors_3d(
ome_zarr_path="data/segmentation.zarr",
metadata_csv_path="data/cell_metadata.csv",
max_distance_um=0.5,
voxel_size_um=(0.56, 0.28, 0.28),
db_path="results/sample_neighbor_graph.db",
output_csv="results/sample_neighbors_3d.csv",
n_jobs=8
)
Parameters#
ome_zarr_path: Path to OME-Zarr file containing 3D segmentationmetadata_csv_path: Path to CSV file with cell metadatamax_distance_um: Maximum surface-to-surface distance in micrometers for neighbor detectionvoxel_size_um: Tuple of (z, y, x) voxel sizes in micrometersdb_path: Output neighbor graph databaseoutput_csv: Output CSV of neighbor pairsn_jobs: Number of parallel jobs
Output#
The function returns:
neighbors_3d: DataFrame with neighbor pairsadata: AnnData object (if available) with graph informationconn: Database connection object
Step 2: Volume#
After detecting neighbors, compute the interscellar volumes. There are two pathways, which differ in how far each volume reaches into its two cells:
(a) Absolute: dilates inwards from the cell surface by a fixed, user-defined distance.
(b) Adaptive: dilates inwards from the cell surface by a depth ratio relative to the cell's maximum reach.
(a) Absolute#
volumes_3d, adata, conn = interscellar.compute_interscellar_volumes_3d(
ome_zarr_path="data/segmentation.zarr",
neighbor_pairs_csv="results/sample_neighbors_3d.csv",
neighbor_db_path="results/sample_neighbor_graph.db",
voxel_size_um=(0.56, 0.28, 0.28),
max_distance_um=3.0,
intracellular_threshold_um=1.0,
n_jobs=8
)
Parameters
ome_zarr_path: Path to OME-Zarr file containing 3D segmentationneighbor_pairs_csv: Path to CSV file with neighbor pairs from step 1neighbor_db_path: Path to database file with neighbor pairs from step 1voxel_size_um: Tuple of (z, y, x) voxel sizes in micrometersmax_distance_um: Maximum distance for volume computationintracellular_threshold_um: Fixed depth the volume reaches into each celln_jobs: Number of parallel jobs
Output
The function returns:
volumes_3d: DataFrame with interscellar volume measurementsadata: AnnData object with volume informationconn: Database connection object
Outputs are written next to the neighbor pairs CSV as sample_absolute_volumes.csv, sample_absolute_interscellar_volumes.zarr and sample_absolute_cell_only_volumes.zarr.
(b) Adaptive#
volumes_3d = interscellar.compute_interscellar_volumes_3d_adaptive(
ome_zarr_path="data/segmentation.zarr",
neighbor_pairs_csv="results/sample_neighbors_3d.csv",
voxel_size_um=(0.56, 0.28, 0.28),
max_distance_um=3.0,
rho_threshold=0.5,
n_jobs=8
)
Parameters
ome_zarr_path: Path to OME-Zarr file containing 3D segmentationneighbor_pairs_csv: Path to CSV file with neighbor pairs from step 1voxel_size_um: Tuple of (z, y, x) voxel sizes in micrometersmax_distance_um: Maximum distance for volume computationrho_threshold: Depth ratio, relative to each cell's maximum reach, that the volume extends into the celln_jobs: Number of parallel jobs
Output
The function returns:
volumes_3d: DataFrame with interscellar volume measurements
Outputs are written next to the neighbor pairs CSV as sample_adaptive_volumes.csv and sample_adaptive_interscellar_volumes.zarr. Pairs with no extracellular corridor connecting the two cells are rejected and listed in sample_adaptive_rejected_pairs.csv.
Cell-only volumes#
After computing interscellar volumes with either pathway, you can compute cell-only volumes by subtracting the interscellar volumes from the original segmentation:
cellonly_3d = interscellar.compute_cell_only_volumes_3d(
ome_zarr_path="data/segmentation.zarr",
interscellar_volumes_zarr="results/sample_adaptive_interscellar_volumes.zarr"
)
Parameters
ome_zarr_path: Path to original OME-Zarr file containing 3D segmentationinterscellar_volumes_zarr: Path to interscellar volumes zarr file from step 2
The output zarr file is automatically saved in the same directory as the interscellar_volumes_zarr.
Output
The function returns:
cellonly_3d: DataFrame with cell-only volume measurements
Step 3: Score#
Finally, quantify biomarker expression inside each interscellar volume.
Points (transcriptomics, punctate proteomics)#
The centrality score counts each spot inside a volume, weighted by its distance from the pair's contact interface:
scores_3d = interscellar.calculate_interscellar_scores_3d(
interscellar_volumes_zarr="results/sample_adaptive_interscellar_volumes.zarr",
spot_zarrs={"GZMB": "data/GZMB_spots.zarr"},
n_jobs=8
)
Parameters
interscellar_volumes_zarr: Interscellar volumes zarr from the adaptive pathway of step 2spot_zarrs: Mapping of biomarker name to spot mask zarr on the same voxel gridn_jobs: Number of parallel jobs
Output
The function returns:
scores_3d: DataFrame with one row per pair and biomarker, also written assample_adaptive_scores.csv
Immunofluorescence (metabolomics, intensity proteomics)#
Intensity statistics per volume are computed from a raw expression image:
python -m interscellar.core.calculate_interscellar_scores_3d_intensity \
--segmentation-zarr "results/sample_adaptive_interscellar_volumes.zarr" \
--raw-expression-zarr "data/raw_expression.zarr" \
--n-jobs 8