skills/pathml/references/multiparametric.md
This reference targets PathML 3.0.5 stable. It distinguishes generic loading support from a dedicated analysis implementation and corrects older examples that invented MERFISH decoders, spectral unmixing options, named-channel arguments, or a DeepCell cloud prediction endpoint.
from pathml.core import CODEXSlide, MultiparametricSlide, VectraSlide
codex = CODEXSlide(
"data/codex_region.tif",
name="slide-001",
backend="bioformats",
)
vectra = VectraSlide(
"data/vectra_component_data.tif",
name="slide-002",
)
generic = MultiparametricSlide(
"data/multiplex.ome.tiff",
name="slide-003",
)
Bio-Formats returns PathML arrays as:
(i, j, z, c, t) = (row, column, z-plane, channel, time/cycle)
Generic Bio-Formats support means a format may be readable. It does not mean PathML implements registration, decoding, spectral unmixing, compensation, autofluorescence correction, cell phenotyping, or platform-specific QC for that format.
Stable PathML has convenience classes for CODEX and Vectra. It can load examples
of MERFISH/Visium-like image data through generic backends, but it has no
MERFISHSlide, DecodeMERFISH, or AssignTranscripts stable API.
Create a local, versioned channel manifest before processing:
channel_index,channel_name,marker,cycle,z_plane,role,exposure,batch
0,DAPI,DAPI,0,2,nuclear,100,run-01
1,CD45,CD45,0,2,membrane,150,run-01
2,CD3,CD3,1,2,measurement,200,run-01
Validate:
Do not include patient names, accession numbers, or other direct identifiers.
Stable signature:
from pathml.preprocessing import CollapseRunsCODEX, Pipeline
pipeline = Pipeline([CollapseRunsCODEX(z=2)])
CollapseRunsCODEX(z) expects (i, j, z, c, t), combines c and t into one
channel axis, selects the zero-based Z-plane, and produces (i, j, c*t).
It does not:
Perform and validate those operations upstream with a protocol appropriate to the
acquisition system. Record the exact flattened (cycle, channel) → output index
mapping.
Stable signature:
from pathml.preprocessing import CollapseRunsVectra
collapse = CollapseRunsVectra()
It applies numpy.squeeze to coerce the image toward (i, j, c). It does not
accept wavelengths and does not perform spectral unmixing or autofluorescence
correction. Supply already unmixed component data or perform those steps with
validated upstream software. Verify that squeezing singleton axes did not remove
an axis whose semantics must be retained.
For sensitive images, use an institution-approved local segmenter with a
reviewed, checksummed local model and network disabled. PathML's generic local
ONNX Inference can run compatible models, but Mesmer-specific pre/postprocessing
must match the model card exactly.
PathML 3.0.5 has no fully offline, nondeprecated Mesmer convenience class that accepts a pre-provisioned model without trying a network download. Plan this constraint before choosing PathML's Mesmer wrapper.
SegmentMIFRemote: local inference after a model downloadStable signature:
SegmentMIFRemote(
model_path="temp.onnx",
nuclear_channel=<integer index>,
cytoplasm_channel=<integer index>,
image_resolution=0.5,
preprocess_kwargs=None,
postprocess_kwargs_nuclear=None,
postprocess_kwargs_whole_cell=None,
)
Despite the name, v3.0.5 does not send images to a DeepCell prediction service. At construction it performs an HTTP GET from:
https://huggingface.co/pathml/test/resolve/main/mesmer.onnx
It writes the response to model_path, loads that ONNX model, and runs pixels
locally with ONNX Runtime. The outbound request discloses ordinary connection
metadata (for example IP address and request headers) to Hugging Face; image
pixels, channel data, and PathML metadata are not uploaded by this stable source.
Security and reproducibility limitations:
nuclear_channel and cytoplasm_channel are integer indices, not names.Do not instantiate it until the user explicitly consents to that endpoint and download. Do not use it in a network-disabled workflow.
SegmentMIFSegmentMIF imports deepcell.applications.Mesmer and calls its prediction API
locally. PathML emits a deprecation warning directing users to
SegmentMIFRemote. deepcell is not a PathML extra and is not declared in
PathML's PyPI dependencies. Depending on the DeepCell version/cache, model
initialization may fetch weights.
Do not silently install an unpinned DeepCell stack or assume compatibility with PathML's pinned Python/TensorFlow ecosystem. If legacy replication requires it, lock the complete environment, pre-provision and verify artifacts, test with synthetic data, disable network during sensitive runs, and document the deprecation.
Before any download or hosted inference, present:
Action: download model | download public dataset | upload image for prediction
Destination: exact HTTPS host and path
Outbound data: exact pixels/channels/metadata/identifiers, or "none; GET only"
Inbound artifact: name, expected bytes, version, SHA-256/signature
Local destination: approved path
Retention/logging: vendor and institutional policy
Authorization: data-use agreement/consent/waiver and user approval
Alternative: local, network-disabled method
Only proceed after explicit opt-in. A future hosted endpoint that receives image data needs a new disclosure; do not infer permission from consent to download a model. Never upload PHI by default.
Stable transform:
from pathml.preprocessing import QuantifyMIF
quantify = QuantifyMIF(segmentation_mask="cell_segmentation")
Input requirements:
(i, j, channels);(i, j) or (i, j, 1);tile.coords is present.QuantifyMIF.apply(tile) writes an AnnData object to tile.counts.
Stable output contains:
X: per-object mean intensity for each channel;layers["min_intensity"] and layers["max_intensity"];obs["label"], filled_area, euler_number, x, and y;obsm["spatial"]: (x, y) centroids.Channel variables are generated from numeric positions. Assign marker names only after matching the validated channel manifest:
counts = tile.counts
assert counts.n_vars == len(channel_names)
counts.var_names = channel_names
Do not interpret raw intensity as abundance without validated background, normalization, exposure, compensation/unmixing, segmentation, and batch policies.
Tile.coords uses selected-level (i, j). QuantifyMIF adds tile offsets to
region centroids, then stores:
obs["y"]: row coordinate;obs["x"]: column coordinate;obsm["spatial"]: [x, y].Convert selected-level pixels to level-0 and physical units:
x_um = x_selected_level * level_downsample * mpp_x
y_um = y_selected_level * level_downsample * mpp_y
Record whether coordinates are pixel centers, integer-rounded centroids, or continuous region centroids. Preserve source level and MPP. Do not combine slides with different resolutions in a shared coordinate space without conversion.
For exchange, use one row per cell:
cell_id,patient_id,slide_id,tile_i,tile_j,x,y,coordinate_unit,level,
segmentation_label,area,marker:DAPI,marker:CD3,marker:CD8,...
Required invariants:
(slide_id, cell_id) is unique;coordinate_unit is explicit (level_pixels, level0_pixels, or um);Validate bounded local CSV:
python scripts/validate_spatial_schema.py multiplex \
--input derived/cells.csv \
--root . \
--marker-columns marker:DAPI,marker:CD3,marker:CD8
Review representative training regions:
Freeze QC thresholds before the test set. Report exclusions and sensitivity analyses rather than hiding failed tiles.
Before concatenation:
obs_names globally unique with pseudonymous slide and cell IDs;patient_id, slide_id, site, batch, and split in obs;Threshold cell typing from markers is a research annotation procedure, not a diagnosis. Use controls and domain review, and report ambiguous/unassigned cells.
Present in stable:
MultiparametricSlide, VectraSlide, CODEXSlideCollapseRunsCODEX(z)CollapseRunsVectra()SegmentMIFRemote(...)SegmentMIF(...)QuantifyMIF(segmentation_mask)Not present as stable APIs:
"DAPI" or "CD45" for segmentation;CollapseRunsCODEX(method=..., background_subtract=...);CollapseRunsVectra(wavelengths=..., unmix=True);MERFISHSlide, DecodeMERFISH, or AssignTranscripts;QuantifyMIF;