itasc.contact_analysis.quantifier

The quantifier seam: per-position compute units, discovered by subclassing.

A Quantifier turns a position’s source files (PositionInputs) into a persisted, plottable quantity. Contacts is the first one; new quantities (nucleus-track kinematics, nucleus-vs-cell offset, cell shape, …) drop in as modules under itasc.contact_analysis.quantifiers without touching the studio.

The mechanics mirror itasc.napari.contact_analysis.plugins: subclassing with a non-empty quantity_id auto-registers the quantifier, and available_quantifiers() imports every module in the quantifiers package so its plugins self-register. This module stays backend-only (no Qt / napari) so the standalone wheel and headless batch runs can use it.

Module attributes

OUTPUT_SUBDIR

Per-position subfolder for quantifier artifacts that persist to disk.

Functions

available_quantifiers()

Return registered quantifier classes, sorted by display name.

Classes

PositionInputs(position_dir[, ...])

Resolved source files for one position.

Quantifier()

Base class for per-position quantifiers.

itasc.contact_analysis.quantifier.OUTPUT_SUBDIR = '4_contact_analysis'

Per-position subfolder for quantifier artifacts that persist to disk. Numbered to mirror the staged layout (0_input3_cell). The dynamics quantifiers land here (cell_dynamics.h5, nucleus_dynamics.h5); the cheap quantities (shape, relational, density, neighbor count) are pooled in memory during run() rather than written to disk. Note contact_analysis.h5 is not here — ContactsQuantifier overrides Quantifier.default_output() to write it to the position root, beside the committed cell_labels.tif / nucleus_labels.tif.

class itasc.contact_analysis.quantifier.PositionInputs(position_dir, cell_labels_path=None, nucleus_labels_path=None, pixel_size_um=None, time_interval_s=None, contact_analysis_path=None)[source]

Bases: object

Resolved source files for one position. Quantifiers read what they need.

Every field has a live consumer. A future track-based quantifier adds its own field (e.g. tracks_db_path) in the same commit that first reads it — no speculative placeholders here.

Parameters:
  • position_dir (Path)

  • cell_labels_path (Path | None)

  • nucleus_labels_path (Path | None)

  • pixel_size_um (float | None)

  • time_interval_s (float | None)

  • contact_analysis_path (Path | None)

position_dir: Path
cell_labels_path: Path | None = None
nucleus_labels_path: Path | None = None
pixel_size_um: float | None = None

Physical pixel size (µm/px); None when unknown. Quantifiers that emit values in physical units (cell shape) require it.

time_interval_s: float | None = None

Frame interval (seconds/frame); None when unknown. Quantifiers that emit time-derived values (track dynamics) require it.

contact_analysis_path: Path | None = None

The position’s built contact_analysis.h5; None when contacts is not in the catalogue. The contacts-derived quantifiers (neighbor count / enrichment / z-score / density / signed contact length) read it as their input instead of re-running contact extraction.

class itasc.contact_analysis.quantifier.Quantifier[source]

Bases: object

Base class for per-position quantifiers.

Subclasses set quantity_id / display_name (and usually requires) and implement build() and read(). A quantifier owns its own persistence: build() writes whatever artifact format suits the quantity and read() parses it back — the framework imposes no schema.

quantity_id: ClassVar[str] = ''

Stable key; an empty value marks an intermediate (non-registered) base.

display_name: ClassVar[str] = ''

Human-readable label shown wherever a quantity is selected.

requires: ClassVar[tuple[str, ...]] = ()

PositionInputs field names this quantifier needs to build.

produces: ClassVar[str] = ''

The PositionInputs field this quantifier’s artifact populates, if any (e.g. contacts populates contact_analysis_path). A quantifier whose requires names another’s produces is derived from it — the studio uses this to draw the build-dependency graph. Empty for a leaf quantity that only consumes raw source inputs.

default_output_name: ClassVar[str] = ''

Default artifact file name (relative to a position); empty for an intermediate base that does not persist.

table_keys: ClassVar[tuple[str, ...]] = ()

The index columns of this quantifier’s object_table — its natural grain (e.g. ("frame", "cell_id")). A non-empty value marks the quantity as aggregated: itasc.contact_analysis.shape_tables pools it across positions into a table named by quantity_id, keyed on these columns. Empty ⇒ not aggregated into an index-keyed table (e.g. contacts). Value columns are namespaced by quantity_id so a later joined view across tables never has colliding names.

wants_build_params: ClassVar[bool] = False

Whether the studio threads the shared plot/build params (z-score shuffle count, density field-of-view) into build() via params. Off by default so a quantifier with its own params schema (contacts edge extraction, shape, dynamics) is never handed the shared bar’s keys.

required_build_params: ClassVar[dict[str, str]] = {}

Shared build-param keys that must be present and positive for this quantifier to build, mapped to the human label shown in the UI (e.g. cell density needs {"fov_area_mm2": "FOV area (mm²)"}). The studio greys the metric out — rather than letting the build fail — until they are supplied. Empty for a quantifier that needs no shared param.

can_build(inputs)[source]

True when inputs supplies every field named in requires.

Return type:

bool

Parameters:

inputs (PositionInputs)

missing_build_params(params)[source]

Labels of required_build_params that params doesn’t satisfy.

A required key is satisfied when present and a positive number; anything else (absent, blank, None, non-positive) counts as missing. The studio uses the returned labels to grey the metric out and explain why. Empty tuple ⇒ every required shared param is supplied.

Return type:

tuple[str, ...]

Parameters:

params (Mapping[str, Any] | None)

default_output(inputs)[source]

Where this quantifier’s artifact lives for inputs, by default.

position_dir / OUTPUT_SUBDIR / default_output_name — every quantity lands in the shared OUTPUT_SUBDIR folder, so each subclass sets just a bare file name. The studio uses this to decide a build’s destination, so a second quantifier no longer inherits the contacts artifact path. Subclasses may override for richer layouts.

Return type:

Path

Parameters:

inputs (PositionInputs)

is_built(output_path)[source]

True when the artifact at output_path already exists.

Return type:

bool

Parameters:

output_path (Path)

object_table(output_path)[source]

A tidy, column-major per-object table for the plotting backend.

At least a frame key plus a per-object key (e.g. cell_id). Returns None when this quantifier produces no per-object table; the plotting backend then skips it.

Return type:

Mapping[str, Any] | None

Parameters:

output_path (Path)

compute_object_table(inputs, *, params=None)[source]

The pooled tidy table for one position, computed directly from inputs.

A pooled quantifier (one that declares table_keys) implements this: it returns the same column-major table that object_table used to return after a disk round-trip, but never touches disk. None when this position yields no rows. Producers (contacts) are not pooled and do not implement it. params carries the shared build knobs (e.g. fov_area_mm2) for the quantifiers that opt in; per-position values (pixel size, frame interval) arrive via inputs.

Return type:

Mapping[str, Any] | None

Parameters:
build(inputs, output_path, *, params=None, progress_cb=None)[source]
Return type:

Path

Parameters:
read(output_path)[source]
Return type:

Any

Parameters:

output_path (Path)

itasc.contact_analysis.quantifier.available_quantifiers()[source]

Return registered quantifier classes, sorted by display name.

Return type:

list[type[Quantifier]]