You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add per-shard CLI and Metadata_Imaging_ImageID propagation (#50)
* Add per-shard CLI and Metadata_Imaging_ImageID propagation
ZedProfiler is the feature extractor the NF1 pipeline dispatches per
well/FOV shard via SLURM sbatch. This commit adds the command that process
runs and the identifier column that makes shards warehouse-joinable.
CLI (src/zedprofiler/cli.py):
- "ZedProfiler run" subcommand (argparse): repeatable --image/--label
NAME=PATH flags, --anisotropy-spacing Z Y X, identifier fields
(--patient-tumor/--plate/--well/--field), --out-dir, a --features
selector, repeatable --feature TYPE[,key=value,...] advanced requests,
--skip-existing, and --force.
- Reuses the six compute_* featurizers; builds the shared loader via
ImageSetLoader.from_image_dict with the identifier fields.
- Restartable/idempotent: deterministic output paths, --skip-existing
filters before any image is read (a finished shard re-run skips I/O
entirely), and atomic writes (temp + os.replace) so a crashed shard
never leaves a partial file that --skip-existing would mistake for
complete.
- Fixes the orphaned/mis-cased console script to zedprofiler.cli:trigger.
Identifiers (src/zedprofiler/identifiers.py):
- build_image_id(patient_tumor, plate, well, field) -> deterministic
Metadata_Imaging_ImageID; single source of truth for the format.
Loaders (src/zedprofiler/IO/loading_classes.py):
- ImageSetConfig carries patient_tumor/plate/well/field with an image_id
property; ImageSetLoader exposes image_id (falls back to image_set_name).
- New from_image_dict classmethod builds a multi-channel loader from an
in-memory {key: ndarray} dict (the path the CLI needs); it derives
compartments/image names directly from the declared label keys so it is
self-contained and correct independent of get_compartments.
Featurizers (6 modules):
- Each emits Metadata_Imaging_ImageID before Metadata_Experiment_ImageSet.
Feature values are unchanged; only a metadata column is added.
Feature writing:
- save_features_as_parquet gains an opt-in atomic flag used by the CLI.
End-to-end CLI tests self-skip when the CellProfiler 3D tutorial data is
absent (it lands via a separate data commit), so the CLI test module stays
green everywhere and runs in full wherever the data is available.
* Add per-shard CLI and Metadata_Imaging_ImageID propagation
ZedProfiler is the feature extractor the NF1 pipeline dispatches per
well/FOV shard via SLURM sbatch. This commit adds the command that process
runs and the identifier column that makes shards warehouse-joinable.
CLI (src/zedprofiler/cli.py):
- "ZedProfiler run" subcommand (argparse): repeatable --image/--label
NAME=PATH flags, --anisotropy-spacing Z Y X, identifier fields
(--patient-tumor/--plate/--well/--field), --out-dir, a --features
selector, repeatable --feature TYPE[,key=value,...] advanced requests,
--skip-existing, and --force.
- Reuses the six compute_* featurizers; builds the shared loader via
ImageSetLoader.from_image_dict with the identifier fields.
- Restartable/idempotent: deterministic output paths, --skip-existing
filters before any image is read (a finished shard re-run skips I/O
entirely), and atomic writes (temp + os.replace) so a crashed shard
never leaves a partial file that --skip-existing would mistake for
complete.
- Fixes the orphaned/mis-cased console script to zedprofiler.cli:trigger.
Identifiers (src/zedprofiler/identifiers.py):
- build_image_id(patient_tumor, plate, well, field) -> deterministic
Metadata_Imaging_ImageID; single source of truth for the format.
Loaders (src/zedprofiler/IO/loading_classes.py):
- ImageSetConfig carries patient_tumor/plate/well/field with an image_id
property; ImageSetLoader exposes image_id (falls back to image_set_name).
- New from_image_dict classmethod builds a multi-channel loader from an
in-memory {key: ndarray} dict (the path the CLI needs); it derives
compartments/image names directly from the declared label keys so it is
self-contained and correct independent of get_compartments.
Featurizers (6 modules):
- Each emits Metadata_Imaging_ImageID before Metadata_Experiment_ImageSet.
Feature values are unchanged; only a metadata column is added.
Feature writing:
- save_features_as_parquet gains an opt-in atomic flag used by the CLI.
Tests:
- test_real_world_data.py colocalization loader switched to from_image_dict
so the new image_id column is populated for the existing colocalization
end-to-end test.
- CLI end-to-end tests run against the CellProfiler 3D tutorial data present
on main and self-skip if that data is absent on other branches.
* test coverage
* fov labeling
Co-Authored-By: Mike Lippincott <58147848+MikeLippincott@users.noreply.github.com>
* add cli docs to readme
Co-Authored-By: Mike Lippincott <58147848+MikeLippincott@users.noreply.github.com>
* feature specs
Co-Authored-By: Mike Lippincott <58147848+MikeLippincott@users.noreply.github.com>
* cli spec
Co-Authored-By: Mike Lippincott <58147848+MikeLippincott@users.noreply.github.com>
---------
Co-authored-by: Mike Lippincott <58147848+MikeLippincott@users.noreply.github.com>
`ZedProfiler run` extracts features for a single well/field-of-view (FOV) shard: it loads one image set from explicit file paths, runs a selected subset of featurizers, and writes one Parquet per feature table to an output directory. It is the command a workflow manager (for example Nextflow via SLURM `sbatch`) dispatches once per shard.
37
+
38
+
After `uv sync` (or `pip install .`) the `ZedProfiler` console script is available; from a checkout you can also use `uv run ZedProfiler run ...`. Run `ZedProfiler run --help` for the authoritative, up-to-date list of arguments.
|`--fov`| yes | Field-of-view index or identifier. |
64
+
|`--out-dir`| yes | Shard output directory (created if needed). |
65
+
|`--features`| no | Comma-separated feature types to run (selector). With no `--feature` flags, runs these types over the channel x compartment cross-product; with `--feature` flags, restricts those requests by type. Default: all single-channel types, plus `Colocalization` when >=2 channels are declared. |
66
+
|`--feature=TYPE[,key=value,...]`| no (repeatable) | An explicit feature request, e.g. `Intensity,channel=DNA,compartment=Nuclei` or `Colocalization,channel1=DNA1,channel2=DNA2,compartment=Nuclei,fast_costes=Faster`. |
67
+
|`--skip-existing`| no | Skip a feature request whose output Parquet already exists. |
68
+
|`--force`| no | Overwrite even when the output exists (writes are still atomic). |
69
+
70
+
### Feature types
71
+
72
+
`VolumeSizeShape`, `Intensity`, `Neighbors`, `Texture`, and `Granularity` are single-channel features run per channel x compartment. `Colocalization` is a two-channel feature run per ordered channel pair x compartment.
73
+
74
+
### Outputs
75
+
76
+
Each request writes `{compartment}_{channel}_{feature_type}_cpu_features.parquet` into `--out-dir`. Every table carries `Metadata_Imaging_ImageID` (deterministically built from the patient-tumor, plate, well, and FOV coordinates) and `Metadata_Experiment_ImageSet` so downstream tables can rejoin. Writes are atomic (temp file + replace), so a crashed shard never leaves a partial file that `--skip-existing` would mistake for a complete one.
0 commit comments