itasc.contact_analysis¶
Contact Analysis: pool per-position sources into aggregate tidy tables.
This package hosts the quantifier seam. The stable, napari-free surface that the
itasc-aggregate CLI calls and notebooks import is the
pipeline — build_catalog →
build_quantities → aggregate — re-exported here alongside the catalogue
load/save helpers and the quantifier registry. Everything it produces is
label-agnostic: tidy CSVs with no subpopulation classification baked in.
Reduction to replicate-level summaries and plotting are downstream concerns
owned by the data repo, not this package.
The contacts quantifier’s public API (cell-cell edges, T1 events) is also
re-exported for stability; see itasc.contact_analysis.contacts.
- itasc.contact_analysis.build_catalog(root, *, cell_name=None, nucleus_name=None, out_csv=None)[source]¶
Discover the positions under root and return them as catalogue records.
Wraps
discover_catalog_entries(): a position is any folder holding at least one named input (cell and/or nucleus labels). When out_csv is given, the discovered skeleton is written there (save_catalog()) for an analyst to fill incondition/date/notesbefore building.The records carry the discovered paths but no metadata; that is fine for an immediate build (which keys only on the inputs) and is the editable skeleton when persisted.
- itasc.contact_analysis.build_quantities(catalog, *, quantifiers=None, params=None, progress_cb=None)[source]¶
Build and persist every producer quantity for every position in catalog.
THE extracted build loop (previously trapped in the napari studio): one job per
(quantifier, position)where the quantifiercan_build()the position’s inputs; each job calls.build(inputs, output_path, params=...), overwriting an existing artifact. Positions lacking a quantifier’s inputs are skipped.Only producers — quantifiers whose
producesanother quantifier’srequiresnames (in practice justcontacts, writingcontact_analysis.h5) — persist a per-position artifact here. Every other (cheap) quantity is never built to disk per-position: it is instead computed in memory, straight from a position’s raw inputs, insideaggregate()/build_table()viacompute_object_table(). A normal run therefore writes onlycontact_analysis.h5per position; the pooled tables are the only place the cheap quantities live.quantifiers defaults to one instance of every registered quantifier (
available_quantifiers()); it is filtered down to producers before planning, so passing non-producers here is harmless (they are simply skipped). params (the shared build knobs — z-score shuffles, density FOV, pixel size, frame interval) is threaded only into quantifiers that opt in viawants_build_params; the rest keep their ownparamsschema clean. A quantifier whoserequired_build_paramsparams does not satisfy is skipped whole (mirrors the studio greying the metric out), so “build everything” stays usable when an optional knob like the density FOV is unset. progress_cb is called(done, total, position_name)before each build. Exceptions propagate — a failed build aborts the run rather than being silently swallowed.
- itasc.contact_analysis.select_quantifiers(quantities)[source]¶
Instantiate the quantifiers a run should build for the selected quantities.
Empty quantities selects every registered quantifier. A non-empty list selects those
quantity_ids plus, transitively, any producer whoseproducesfield a selected (or pulled-in) quantifierrequires— so asking for a contacts-derived metric silently brings contacts along instead of leaving it unbuildable. Order follows registration; the build loop re-sorts by dependency.- Return type:
- Parameters:
- itasc.contact_analysis.aggregate(catalog, out_dir=None, *, params=None, quantities=None)[source]¶
Pool every built product across catalog into the index-keyed tables.
Thin pass-through to
itasc.contact_analysis.shape_tables.aggregate(): returns the table name → written CSV path map. The tables are written flat under out_dir (<out_dir>/<name>.csv); out_dir defaults to the catalogue root (the common ancestor of the positions). params carries the shared build knobs (pixel size, frame interval, FOV area, …) so a param-gated cheap quantity (e.g. cell shape needingpixel_size_um) pools with the same knobs a normal build would have used. quantities restricts which tables are written (None= all); seeshape_tables.aggregate().
- itasc.contact_analysis.author_config(out_dir, records, *, tables_dir=None, quantities=(), params=None, catalog_name='catalog.csv', config_name='config.toml')[source]¶
Write
catalog.csv+config.tomlinto out_dir; return the config path.The composition point behind the studio’s “Save config…” / “Run”: persist the in-memory records to a catalog CSV, then author a run-config beside it that points at that CSV (a relative
catalogkey, so the folder stays relocatable). tables_dir is written as the config’sout_dir(where the flat pooled tables land);Noneleaves it unset (defaults to the catalogue root at run time).run(author_config(...))reproduces the UI’s run headlessly. Creates out_dir if missing.
- itasc.contact_analysis.run(config_path, *, progress_cb=None, build=True)[source]¶
Run the whole pipeline from a TOML run-config: the “author once, then run”.
Loads the
RunConfig, then threads its choices through the stages: load the catalog CSV, build the selected quantities — of which only producers (contacts) actually persist a per-position artifact, seebuild_quantities()— and aggregate into the flat measurement tables under the config’sout_dir(default: the catalogue root), where the cheap quantities are computed in memory. The samequantitiesselection restricts which tablesaggregatewrites (empty = all), so a pool-only run honors the choice too. Returns the table name → written CSV path map. The optional progress_cb is forwarded to the build stage.Set build to
Falsefor pool-only: skip the per-position build stage entirely and go straight to aggregate. The producer’s.buildoverwrites its.h5unconditionally (it is not guarded likeensure_contacts), so a plainrunrecomputes every position’s contacts even when the artifact already exists.build=Falsereads the existing.h5via each quantifier’scompute_object_tableand computes the cheap quantities in memory — a load-and-pool with no recompute. Positions missing their.h5simply contribute nothing (scope them out before calling).
- itasc.contact_analysis.load_catalog(csv_path)[source]¶
Load CSV catalog records and expose normalized compatibility keys.
Only
position_pathis required. Uniqueness of the position identity (the combination of classification columns) is not checked here — a catalog may hold more positions than any one run aggregates; the aggregator validates uniqueness over the in-scope subset and refuses with an explanation there (seeitasc.contact_analysis.shape_tables.aggregate()).
- itasc.contact_analysis.save_catalog(csv_path, records)[source]¶
Write catalog records to CSV.
Each row stores the absolute
position_pathand the position’s files as paths relative to that folder. Records without a known position folder (legacy / hand-made) fall back to paths relative to the CSV file.
- class itasc.contact_analysis.RunConfig(catalog, out_dir=None, quantities=(), params=<factory>)[source]¶
Bases:
objectA parsed run-config. Paths are absolute (resolved against the config dir).
quantities empty means “every available quantifier”; a non-empty tuple selects a subset by
quantity_id(dependency producers are pulled in at run time even when omitted). params is the shared build-knob mapping threaded to quantifiers that opt in. out_dir is where the pooled tidy tables land (flat);Nonedefaults to the catalogue root (the positions’ common ancestor).
- itasc.contact_analysis.load_config(config_path)[source]¶
Parse the TOML run-config at config_path into a
RunConfig.catalogis required. Relative paths resolve against the config file’s directory. Selectedquantitiesare validated against the registered quantifiers so a typo fails loudly rather than silently computing nothing.
- itasc.contact_analysis.available_quantifiers()[source]¶
Return registered quantifier classes, sorted by display name.
- Return type:
- itasc.contact_analysis.build_contacts(*, cell_labels_path, output_path, nucleus_labels_path=None, source_path=None, edge_extraction_params=None, progress_cb=None)[source]¶
Build the canonical contact-analysis HDF5 file from label stacks.
Position-agnostic core: takes an explicit cell-label TIFF (2D+t) and an optional nucleus-label TIFF, writing the HDF5 to
output_path.source_pathis recorded as provenance only. Whennucleus_labels_pathis given thecell_id == nucleus_idinvariant is enforced; otherwise nucleus validation is skipped.
- itasc.contact_analysis.build_position_contacts(position_path, output_path, *, cell_tracked_labels_path=None, nucleus_tracked_labels_path=None, edge_extraction_params=None, progress_cb=None)[source]¶
Staged-layout wrapper around
build_contacts().Resolves the committed
<position>/cell_labels.tifand<position>/nucleus_labels.tiflabels (what finalize/”commit” writes to the position base folder) when explicit paths are not supplied, then delegates to the position-agnostic core. These are the downstream-stable inputs, not the pre-commit working3_cell/2_nucleustracked labels. Retained for the orchestrator and out-of-repo consumers that pass a position directory.
- itasc.contact_analysis.ensure_contacts(*, cell_labels_path, output_path, nucleus_labels_path=None, overwrite=False, edge_extraction_params=None, progress_cb=None)[source]¶
Build the contact-analysis HDF5 only when it is missing (or
overwrite).The
.h5is a pure derived artifact of the label inputs, so callers that only need it present (the visualizer, the batch runner) should go through this guard rather than rebuilding unconditionally. Returns(output_path, built)wherebuiltisFalsewhen an existing file was reused.
- class itasc.contact_analysis.ContactBatchJob(group_dir, cell_labels, output, nucleus_labels=None)[source]¶
Bases:
objectOne discovered contact-analysis build: a cell-labels file and where its output goes, with an optional co-located nucleus-labels file.
- class itasc.contact_analysis.ContactBatchResult(job, status, error=None)[source]¶
Bases:
objectOutcome of a single
ContactBatchJob.statusis"built"(computed),"skipped"(output already present), or"failed"(errorholds the message).- Parameters:
job (ContactBatchJob)
status (str)
error (str | None)
- job: ContactBatchJob¶
- itasc.contact_analysis.discover_contact_batch_jobs(root, *, cell_name, h5_name, nucleus_name=None)[source]¶
Find contact-analysis jobs under
rootby file name.Files are discovered recursively, then grouped by position folder — the first directory under
rooton the path to each match (rootitself for files lying directly in it). The named files of one position may live in different subfolders (e.g.pos01/3_cell/andpos01/2_nucleus/); they are still grouped together.For a position with exactly one cell-labels file, that file is one job whose output is
<position>/<h5_name>; the nucleus is associated only when exactly onenucleus_namefile exists anywhere in that position (zero or several → cell-only, “can’t associate → don’t assign”). A position holding several cell-labels files is ambiguous to group, so each falls back to a cell-only job written beside its own cell file. Jobs are sorted by cell path.
- itasc.contact_analysis.run_contact_batch(jobs, *, overwrite=False, edge_extraction_params=None, progress_cb=None, cancel=None)[source]¶
Build the contact-analysis HDF5 for each job, collecting per-job outcomes.
A single job’s failure never aborts the run — it is recorded as a
failedresult and the batch continues.cancelis polled before each job;progress_cb(done, total, label)is reported after each.
Submodules
Catalog of contact-analysis positions for Contact Analysis. |
|
The TOML run-config — Contact Analysis's hand-authored knob file. |
|
Cell-cell contact quantifier: edges, T1 events, neighbourhood & density. |
|
The curation artifact — hand QC exclusions joined onto the measurement tables. |
|
Track-dynamics compute core: motion read off tracked label stacks. |
|
Resolve a position's frame interval (seconds per frame). |
|
The napari-free orchestration surface for Contact Analysis. |
|
Resolve a position's physical pixel size (µm per pixel). |
|
The quantifier seam: per-position compute units, discovered by subclassing. |
|
Quantifier plugins. |
|
Qt-free bridge from catalogue records to a quantifier's per-position files. |
|
Shape compute core: per-object morphology + relational nucleus-vs-cell shape. |
|
Aggregated shape tables — index-keyed, materialized views of the products. |