itasc.contact_analysis.pipeline¶
The napari-free orchestration surface for Contact Analysis.
Three composable functions thread the existing headless stages — discovery, per-position build, aggregate — into one pipeline the CLI, notebooks, and (during the napari parallel-run) the Qt studio all drive:
catalog = build_catalog(root, cell_name=…, nucleus_name=…, out_csv=…) build_quantities(catalog) # one .build() per (quantifier, position) tables = aggregate(catalog, out_dir) # pooled, index-keyed CSVs (flat)
Or, end to end from a TOML run-config: run("config.toml").
Everything produced is label-agnostic tidy CSVs: there is no classification step and no plot/figure export — a subpopulation classification and any plots are a downstream, dataset-specific concern, computed from these tables.
This module composes — it owns no compute. Discovery lives in catalog,
the per-position units in quantifier, the record→inputs bridge in
records, and pooling in shape_tables. The only orchestration that
previously lived nowhere but the napari studio — the per-position build loop —
is build_quantities().
Backend-only (no Qt / napari): the standalone wheel and headless batch runs use it unchanged.
Functions
|
Pool every built product across catalog into the index-keyed tables. |
|
Write |
|
Discover the positions under root and return them as catalogue records. |
|
Build and persist every producer quantity for every position in catalog. |
|
Run the whole pipeline from a TOML run-config: the "author once, then run". |
|
Instantiate the quantifiers a run should build for the selected quantities. |
- itasc.contact_analysis.pipeline.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.pipeline.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.pipeline.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.pipeline.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.pipeline.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.pipeline.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).