Changelog
0.2.0 (unreleased)
Major changes
General changes
- Reworked the scaling workflow, which should now be broadly automated rather than relying on two pipeline runs
- Added cross-batch scaling consensus (
sc_reference_scaling_index). Given one or more previous batches'scaling_index.tsv, a newconsensus_scaling_factorsstep pools them with the current batch's own index and recomputes the scaling factors over the combined plate set, so the output dynamic range is comparable between batches. The recompute reproduces exactly what a single run over all the pooled plates would have produced, rather than averaging the per-batch factors (which is not meaningful - each batch'sbase_scalecarries its own plate-offset anchor). Outputs go torr__scaling/consensusand supersede those inrr__scaling, and aconsensus_diagnostics.tsvreports the per-plate values behind the pooled scale. - Added
rn_stop_after_scaling_factors, which ends the run once the scaling factors exist - skipping rescale, cellcrops and cellprofiler while still producing the full QC report from the unscaled images. Together withsc_reference_scaling_indexthis enables a two-step workflow: characterise each batch cheaply, then re-run against the other batches' indices. - The QC report step now also writes a per-well QC table (
rr__qc/well_qc.tsv): one row per well withplate/row/col/well, the value behind each check, amissing_cyclescolumn,qc_flags_fail/qc_flags_warncolumns naming whatever tripped at each level, and a singleqc_verdict. Three measurement checks contribute - segmented cell count (fail belowqc_min_cells_per_well), percentage of cells clearing the registration threshold (fail belowqc_min_pct_registered), and percentage of cells whose signal (qc_signal_stat, default the per-cell q95) sits near their own field's background (warn aboveqc_max_pct_low_signal, per channel, withqc_intensity_skip_channelsto exclude channels like brightfield). Two further checks fail wells that never reached the measurements:missing_cycle:<plates>for a well absent from one of its registration group's cycle plates (previously dropped silently by the channel joins), andnot_measuredfor a well imaged in every cycle but with no measurements (e.g. a task failing under an ignore errorStrategy). The verdict takes the worst consequence across the checks (blacklisted > fail > warn > pass); blacklisted wells are listed from the blacklist file, since they were excluded before anything was measured. The table is also shown in the QC report as a Well QC tab (sortable, filterable by verdict), and the General QC tab reports the number of failed and warned wells. - The scaling steps now write a
scaling_warnings.tsvalongside their other outputs, and the QC report surfaces it as a warnings panel in Tab 6 - previously these warnings only reached the task's.command.err. calculate_scaling_factorsnow also writessigmoid_inputs.tsv(inrr__scaling): the per control image values ofsigmoid_lower_feature/sigmoid_upper_featurethat each plate's sigmoid x1/x2 are the quantiles of. The QC report draws them in Tab 6 as densities behind each plate's sigmoid curve, peak-scaled to 1, with the chosen x1/x2 marked, so it is visible whether a curve sits between background and signal.- Plate offsets are now estimated with a two-stage mean by default (
sc_offset_mode="well"): control cells are averaged within each well first, then across wells, instead of pooling every control cell on the plate. The well is the experimental unit, so the previous flat mean implicitly weighted each well by its cell count and let a single dense well dominate a plate's offset.sc_offset_min_cells_per_well(default 10) drops sparse wells, which would otherwise carry full weight under the new scheme. Setsc_offset_mode="cell"to reproduce the old numbers.scaling_index.tsvgainsplate_nwellsand records the mode used, and the consensus step refuses to pool indices whose modes disagree. - Updated syntax to support the latest Nextflow (26.04), which enforces strict syntax by default; required a lot of refactoring
- Added a validation routine for input files
- Moved processes downstream of finalize from storeDir to publishDir. Folders that are populated this way (i.e. their contents are symlinked back to the cached files in the workdir, rather than being independent copies) are prefixed with
rr__. This means these will now be re-run if their input changes. Old caching style is maintained for cellpose, decon, images, flatfields and registration, so these will still need to manually be removed to force a rerun. - Removed the subcell workflow, it was out of date
- Cellprofiler features now published as parquet files aggregated per plate (when cpr_no_zip=false (default))
- Intensity measurement (
measure_intensity) and the QC debris overlays now support full 3D mode (rn_cache_images=truewithoutrn_max_project/rn_hybrid), which previously failed on multi-plane stacks. Stats are computed over voxels rather than a projection, so autoscale factors are fitted on the same distributionrescaleapplies them to; debris overlays are displayed as a max projection.object_featuresgains acentroid_zcolumn (0 for 2D input), andareais a voxel count for 3D input.
Breaking changes
- Channel numbering is now 0-indexed everywhere, replacing a previous mix of conventions (1-indexed manifests/
channel_map/ch<N>__output columns vs. 0-indexed internal state). Affected: the main manifest'sff_channels/cp_nucl_channel/cp_cell_channel/dc_psfs/mask_channelscolumns, the registration manifest'sreference_channel/query_channels,sc_channel_map'schannelcolumn, theff_channelsoverride param, and everych<N>__statoutput column (object_features/image_features parquet, QC report labels/columns). Existing manifests/channel_maps must be updated (subtract 1 from every channel value) before re-running against this version. sc_channel_map'splatecolumn is nowcycle, holding an imaging cycle number (1= the reference cycle,2= the first merged query cycle, ...) instead of a manifest plate name. One channel map now covers every reference-plate group in a run, since each group has its own cycle 1/2/...; previously you had to write the rows for one arbitrary group and rely on the others matching.update_channel_mapnow checks the groups genuinely share a channel layout rather than assuming it. Existing channel maps must rename the column and replace each plate name with its cycle number.sc_channel_maphas two new required columns,sigmoid_lower_quantileandsigmoid_upper_quantile(0-1), setting which quantile ofsigmoid_lower_feature/sigmoid_upper_featureacross a plate's control images gives the sigmoid's lower/upper point. These were previously fixed at the 95th percentile and the median. Existing channel maps must add both columns; set them to0.95and0.5on every row that fits a sigmoid to reproduce the previous results exactly. Rows that don't fit a sigmoid can leave them blank.
Installation & dependencies
- Eased install process, added enviroment.yml, now support a single enviroment
- Updated to Python 3.11
- Updated cellprofiler to 5.0, nightly build (pinned to 5.0.0.dev690 for stability)
- Migrated from AICSimageio to bioio
- Updated to Nextflow 26.04
Input & parameter changes
- Added
ff_seedto seed the random image sampling in flatfield estimation, so flatfields are reproducible between runs. Defaults to 42, set to null for the previous unseeded behaviour - Added
ff_threshold_modeto set the threshold used withff_thresholdfor POLY flatfield fitting and validation. Defaults tootsu_log(Otsu on log intensities, same assc_debris_methodOtsu_log), which replaces the previous 2 class Otsu divided by 4. The old threshold let most background through when the signal is dim; setff_threshold_mode="otsu"for the previous behaviour - POLY flatfields are now fit on one value per spatial bin (
ff_bin_stat, defaultmean), pooling the foreground pixels of all training images perff_bin_sizebin, instead of on the 4x4 block means of every image. Every region gets equal weight, which gave a closer fit to the true flatfield in testing and uses far less memory.medianandtrimmed(ff_bin_trim) ignore bright debris,ff_bin_min_pixelsdrops sparse bins, and abinned_fit.pngdiagnostic is written with--plot. Setff_bin_stat="none"for the previous behaviour - Dropped
-entry(no longer supported by NF > 26.04), added--workflowto control which workflow gets executed - Changed how PSFs are specified in the manifest, now in
<channel>=<path>format; droppeddc_channelsas it is no longer needed - Dropped
channelscolumn in manifest, it wasn't used - Several configurations have been renamed, please see the parameters header below.
sc_channel_map's four*_featurecolumns now name just the measured statistic (max,background_mean, ...) instead of the full output column name.update_channel_mapprefixes each with that row's resolved channel, so cycle 2 channel 1'smaxbecomesch4__max- the final index isn't knowable when writing the map. Writing a value out in full (ch0__background_mean) still works and opts out, which is how a row points at another channel's feature deliberately.update_channel_mapno longer requires a registration manifest to resolve--ref-nucl-channel/--qry-nucl-channel. Without one it resolves every plate that names acp_nucl_channel(skippingnone, and plates absent fromchannel_indices.tsv), requires them to agree, and falls back to channel 0 with a warning if no plate names one. Previously a run with no registration manifest failed unless the manifest had exactly one plate whosecp_nucl_channelwas set.- Added an optional
sigmoid_from_channelcolumn tosc_channel_map, naming another row (by itsname) whose fitted sigmoid that channel should reuse instead of fitting its own. Intended for the:in/:exmask inclusive/exclusive channels, where masking zeroes the background sosigmoid_lower_featurehas nothing meaningful to measure. Only the sigmoid is copied - the channel is still scaled to its own measured dynamic range.
Bugfixes
- Fixed index_images & index_cellcrops re-triggering unnecessarily due to
.last(); now uses a fingerprint-based approach that checks modification times without needing to stage every input file - Fixed the per-cell channel correlations (
corr_<ref>_<qry>) in cellcrops. With a nuclear mask, the region was selected withnucl_mask == cell_mask, which also included every pixel in the crop outside the cell (where both masks are 0), inflating the correlation; it now uses only the nucleus pixels, matching CellProfiler's per-object Pearson. Without a nuclear mask, the uint8 cell mask was used as integer indices rather than a boolean mask, so the correlation was always NaN; it is now computed over the cell region - Fixed cellcrops skipping the highest-numbered cell in every field (and fields containing a single cell) due to an off-by-one in the label loop
- Fixed cellcrops truncating irregular cells. The square crop was centred on the centre of mass but sized from the bounding box, so for asymmetric cells (e.g. with a long protrusion) part of the cell fell outside the crop, and every crop lost 1-2 edge pixels. The crop is still centred on the centre of mass, but its half-size is now the furthest any cell pixel lies from it in y or x, so the whole cell is always contained. Crops are larger for irregular cells, slightly more cells near the field border are skipped, and
diameternow reports the (odd) crop side length
Minor changes
- Plates are now automatically renamed during staging to the plate name provided in the manifest, instead of the name from the PE index file
- basicpy is now an optional dependency, only needed for
ff_mode=BASICPY - Fixed
-stub-runto fire properly after recent updates - Added a script to perform a stub run, useful for testing that the wiring is working properly
- Updated the cellcrops process to produce a single parquet file per well instead of one CSV per field
- Cellcrop indexing now aggregates into a single parquet file instead of a CSV
- Added new configuration for the Sanger CUB cluster
- Updated the GPU queue for the Sanger farm22 cluster
- Renamed the manifest parameter
bp_channelstoff_channels - General code cleanup, removed deperacted scripts and comments
- By default, per well cellprofiler is not added to publishDir
- Unscaled images can optionally be skipped in publishDir
- Added creation of field matrix to stage workflow detailling how fields are organized spatially
measure_intensitynow also computesch<N>__q25/ch<N>__q75at the cell level (25th/75th percentile intensity); the QC report's intensity tab (Tab 5) gained q25/q75 as feature options and now defaults to median instead of min- Added a
manifest.versiontonextflow.config(currently0.2.0) - read at runtime viaworkflow.manifest.versionand shown in the QC report footer. Bump this by hand on meaningful releases; there's no automated tagging yet
Parameters
-
Added
--workflow -
Added
--cpr_publish_features_per_well(defaultfalse) to make staging of well level CellProfiler feature outputs (rr__features/cellprofiler) optional -
Added
--sc_publish_unscaled(defaulttrue) to make staging of the unscaled processed images (rr__processed_images/unscaled) optional -
Added
--cpr_run_concat(defaulttrue),--cpr_merge_strategy,--cpr_parent_coland--cpr_child_patternto control the new per-plate CellProfiler aggregation step (rr__features/cellprofiler) -
Added
--sc_skip_debris_removal(defaultfalse) to force sigmoid fitting to always use the bare (non-debris-removed) image feature;calculate_scaling_factorsnow automatically prefers an image's debris-removed (_dbrm) feature variant for sigmoid fitting whenever that image's own debris QC passessc_debris_min_ratio/sc_debris_max_pct -
Added
sc_debris_max_pct/sc_debris_min_ratio(Scaling section) -
Added
sc_debris_method(defaultOtsu_log) andsc_cellmask_expansion(default0) to set the debris thresholding method and cell mask expansion used bymeasure_intensityand the QC debris overlays -
Added
--qc_n_sample_debris(default10) - number of highest-debris example images shown per channel in Tab 7 -
Added
--qc_label(defaultnormal) - resource label for the QC report's own processes, replacing a hardcodedtinylabel that was undersized once real images/masks are loaded (debris sample selection/rendering, report assembly) -
Added
--qc_decon_crop_pct(default25) - center-crops Tab 4's before/after decon images to this % of the original width/height, since decon's effect is often too subtle to see in a full, shrunk-to-thumbnail field -
Removed subcell parameters
-
sc_prefix now used for scaling parameters -
bp_prefix (basicpy) renamed toff_(flatfield) -
tg_prefix (tglow) renamed torn_(run); applies totg_conda_envandtg_container -
Removed
cp_cell_power,cp_nucl_power,rn_dummy_mode,rn_thresholdandcp_dont_post_processoptions -
Removed
executor.poolSizefrom the LSF definition -
Removed
dc_channelsfrom the manifest
Documentation
- Fixed small documentation issues that didn't match actual behaviour
- Documentation hosted on trynkalab.github.io instead of wiki
0.0.1-beta and earlier
No changelog was kept for these versions.