| name | bio-workflows-imc-pipeline |
| description | End-to-end imaging mass cytometry workflow from raw acquisitions to spatial cell analysis. Orchestrates image preprocessing, segmentation, phenotyping, and spatial statistics. Use when analyzing imaging mass cytometry data end-to-end. |
| tool_type | python |
| primary_tool | steinbock |
| workflow | true |
| depends_on | ["imaging-mass-cytometry/data-preprocessing","imaging-mass-cytometry/cell-segmentation","imaging-mass-cytometry/phenotyping","imaging-mass-cytometry/spatial-analysis","imaging-mass-cytometry/interactive-annotation","imaging-mass-cytometry/quality-metrics"] |
Imaging Mass Cytometry Pipeline
Pipeline Overview
Raw MCD/TIFF Files ──> Image Processing ──> Cell Masks
│
▼
┌─────────────────────────────────────────────┐
│ imc-pipeline │
├─────────────────────────────────────────────┤
│ 1. Data Preprocessing (spillover, hot px) │
│ 2. Cell Segmentation (Cellpose/Mesmer) │
│ 3. Single-cell Quantification │
│ 4. Clustering & Phenotyping │
│ 5. Spatial Analysis │
│ 6. Visualization │
└─────────────────────────────────────────────┘
│
▼
Cell Types + Spatial Neighborhoods
Complete steinbock Workflow
Step 1: Setup and Preprocessing
steinbock preprocess imc \
--mcd data/*.mcd \
--panel panel.csv \
--output raw/
steinbock preprocess imc hotpixel \
--input raw/ \
--output img/ \
--threshold 50
steinbock preprocess mosaic \
--input img/ \
--channels panel.csv \
--output mosaics/
Step 2: Cell Segmentation
steinbock segment cellpose \
--input img/ \
--panel panel.csv \
--channel DNA1 DNA2 \
--output masks/ \
--diameter 20
steinbock segment mesmer \
--input img/ \
--panel panel.csv \
--nuclear DNA1 DNA2 \
--membrane CD45 \
--output masks/
Step 3: Single-cell Quantification
steinbock measure intensities \
--input img/ \
--masks masks/ \
--panel panel.csv \
--output intensities/
steinbock measure regionprops \
--masks masks/ \
--output regionprops/
steinbock measure neighbors \
--masks masks/ \
--output neighbors/ \
--distance 15
Complete Python Workflow
import pandas as pd
import numpy as np
import anndata as ad
import scanpy as sc
import squidpy as sq
from pathlib import Path
data_dir = Path('steinbock_output')
intensities = pd.read_csv(data_dir / 'intensities.csv', index_col=0)
regionprops = pd.read_csv(data_dir / 'regionprops.csv', index_col=0)
neighbors = pd.read_csv(data_dir / 'neighbors.csv')
print(f'Loaded {len(intensities)} cells')
adata = ad.AnnData(X=intensities.values, obs=regionprops, var=pd.DataFrame(index=intensities.columns))
adata.obs['image_id'] = [idx.split('_')[0] for idx in intensities.index]
adata.obs['cell_id'] = intensities.index
adata.obsm['spatial'] = regionprops[['centroid_y', 'centroid_x']].values
adata.X = np.arcsinh(adata.X / 5)
sc.pp.scale(adata, max_value=10)
adata.raw = adata.copy()
sc.pp.pca(adata, n_comps=20)
sc.pp.neighbors(adata, n_neighbors=15)
sc.tl.umap(adata)
sc.tl.leiden(adata, resolution=)
()
sc.tl.rank_genes_groups(adata, , method=)
marker_genes = sc.get.rank_genes_groups_df(adata, group=)
cluster_annotations = {
: ,
: ,
: ,
: ,
:
}
adata.obs[] = adata.obs[].(cluster_annotations)
sq.gr.spatial_neighbors(adata, coord_type=, delaunay=)
sq.gr.nhood_enrichment(adata, cluster_key=)
sq.gr.co_occurrence(adata, cluster_key=)
sq.gr.ripley(adata, cluster_key=, mode=)
matplotlib.pyplot plt
fig, axes = plt.subplots(, , figsize=(, ))
sc.pl.umap(adata, color=, ax=axes[], show=)
sc.pl.umap(adata, color=, ax=axes[], show=)
plt.savefig(, dpi=, bbox_inches=)
fig, ax = plt.subplots(figsize=(, ))
sq.pl.spatial_scatter(adata[adata.obs[] == ],
color=, shape=, size=, ax=ax)
plt.savefig(, dpi=, bbox_inches=)
sq.pl.nhood_enrichment(adata, cluster_key=)
plt.savefig(, dpi=, bbox_inches=)
adata.obs[] = adata.obs[].({
: , : ,
: , :
})
proportions = adata.obs.groupby([, , ]).size().unstack(fill_value=)
proportions = proportions.div(proportions.(axis=), axis=)
adata.write()
proportions.to_csv()
()
R Alternative (imcRtools)
library(imcRtools)
library(cytomapper)
library(CATALYST)
spe <- read_steinbock('steinbock_output/')
assay(spe, 'exprs') <- asinh(counts(spe) / 5)
spe <- runDR(spe, features = rownames(spe), exprs_values = 'exprs', dr = 'UMAP')
spe <- cluster(spe, features = rownames(spe), exprs_values = 'exprs',
xdim = 10, ydim = 10, maxK = 20
spe buildSpatialGraphspe img_id type threshold
spe aggregateNeighborsspe colPairName by
cn detectCommunityspe colPairName
size_threshold group_by
plotSpatialspe img_id node_color_by
QC Checkpoints
| Stage | Check | Action if Failed |
|---|
| Preprocessing | No hot pixel streaks | Lower threshold |
| Segmentation | >80% cells detected | Adjust diameter |
| Quantification | All markers extracted | Check panel.csv |
| Clustering | 5-20 clusters | Adjust resolution |
| Spatial | Neighbors detected | Check distance |
Workflow Variants
High-plex Panels (40+ markers)
import scvi
scvi.model.SCVI.setup_anndata(adata, batch_key='image_id')
model = scvi.model.SCVI(adata)
model.train()
adata.obsm['X_scvi'] = model.get_latent_representation()
sc.pp.neighbors(adata, use_rep='X_scvi')
Tumor Microenvironment Analysis
tumor_cells = adata[adata.obs['cell_type'] == 'Tumor'].obs_names
sq.gr.ligrec(adata, cluster_key='cell_type', source_groups=['Tumor'],
target_groups=['T cells', 'Macrophages'])
Related Skills
- imaging-mass-cytometry/data-preprocessing - Hot pixel, spillover
- imaging-mass-cytometry/cell-segmentation - Cellpose/Mesmer details
- imaging-mass-cytometry/phenotyping - Cluster annotation
- imaging-mass-cytometry/spatial-analysis - Spatial statistics
- imaging-mass-cytometry/interactive-annotation - Manual cell labeling
- imaging-mass-cytometry/quality-metrics - QC metrics
- single-cell/clustering - Clustering methods
- spatial-transcriptomics/spatial-statistics - Related spatial methods