MercaderLabAnatomy/napari-tmidas: v0.5.15
Abstract
Unreleased (since v0.5.14) Features Dimension Order is now a first-class control. Moved out of the inline parameter list into its own framed box above the function selector, with a live status line reporting the first file's rank and warning when "Auto" can't describe it. New helpers: probe_file_shape() (reads rank from the TIFF/Zarr header, no pixel load), suggest_dimension_order() (pre-selects only on trustworthy metadata, never overrides the user), confirm_dimension_order() (blocks Start once, not once per file). Six functions that asked the same question a second time (Cellpose-SAM, VisCy, Resize by YX Scale, HOCT, Trackastra, Merge Timepoints) had their duplicate dim_order registry entries removed. CZYX added to the dropdown. (0343f30) Bug fixes Silent data corruption Native OME-Zarr resize: three defects, two silent. zarr.storage.FSStore was removed in zarr 3 (which is pinned), so the lazy path never ran — a bare except fell back to a full in-memory load. The source pyramid level was picked with unordered array_keys()[0], so a random downsampled level got resized. Metadata was read/written via .zattrs, a no-op under zarr v3, so physical pixel size reverted to 1.0 and every micron measurement downstream was wrong. (53ef2f0) Timepoint merger: two axis-order bugs. An explicit TZYX hint produced the label "TTZYX" for a 4-axis array; and skimage.io.imread read a 3- or 4-slice leading Z axis as RGB(A) and moved it last, yielding (T,Y,X,Z) while the OME metadata still said TZYX. Now loads via tifffile. (0679d84) Merged channel TIFFs tagged as RGB. tifffile.memmap() without photometric="minisblack" wrote a 3- or 4-slice Z axis as colour samples. tifffile round-trips it fine from its own shaped metadata; ImageJ, bio-formats and PIL do not. (7f3749f) Chunked Dask TIFF writes lost all but the first timepoint on read. One TIFF series per block was written; imread() returns only the first. Switched to a single imwrite(data= , shape=, dtype=). (e4dfb0a) Slide and Acquifer conversions wrote a reciprocal pixel scale (0.25 µm/px stored as 4.0). Both loaders stored µm-per-pixel where every other loader stores px-per-µm. (e4dfb0a) _save_zarr rechunked the wrong axes — shrank Y for zyx input, T and C (never Z) for tczyx, contradicting its own comment. Now targets T/Z by real position and splits the reduction across however many are present. (e4dfb0a) omero metadata write clobbered the coordinate-transform repair. root.attrs["omero"] = ... re-serialises a stale in-memory snapshot, discarding the physical scale written moments earlier by raw file I/O, on every zarr source carrying an omero block. (dfa32ea) Colocalization results dict corrupted when channel 2 was intensity. The per-ROI dict assumed the channel2_is_labels=True row layout, so ch2 mean intensity landed under ch2_in_ch1_count and every ch3 key after it was shifted. CSV output was unaffected. Also fixed a header typo (C_not_in_B_in_A_median → ..._but_in_A_...). (1b2bf23) Regionprops summary CSV held stringified tuples. pandas ≥ 2 returns 1-tuple keys when grouping by a single-element list, so the T/C/Z column read "(0,)" instead of 0. Also replaced a locals()-by-string lookup for enabled intensity stats with an explicit dict. (34f0d66) Uniform image rendered as a black tile in the QC grid. (x-min)/(max-min) is 0/0 for a flat field; NaNs cast to 0. Now guards on the span. (10bb614) Ignored settings, crashes and leaks PyQt6 check-state comparisons were always False. Qt.Checked is a real enum under PyQt6 and never equals the plain int stateChanged delivers, so a ticked box read as unchecked: Batch Crop Anything discarded the labels you selected, frame removal inverted, use_cpu emitted False when on. The app ships PyQt5 (where it happens to work); the test suite resolves PyQt6. (85b8017) batch_label_based_cropping ignored label_suffix_priority and auto_detect_labels — both accepted and documented, neither ever read. (84b4358) trackastra_tracking crashed instead of returning unchanged — the "could not determine input file path" branch logged its intent then fell through to Path(os.path.dirname(None)). (e1c4640) Cellpose env management: three bugs. cancel_all_processes() left un-terminable processes tracked forever; a diagnostic int() ran before the try/except written to catch it; the zarr-direct path silently reinterpreted an out-of-range T axis as axis 0 (turning Z into T) where the in-memory path raised. (addfc53) Temp-file leaks in three env runners — ConvPaint (one try for three unlinks), Spotiflow (raise from inside the with, no finally), VisCy (ImportError before the cleanup block was entered). (b171e8a) Double del out_mm in merge_channels masked every mid-copy failure as UnboundLocalError. (e484cc0) Invalid-rank handling: resize_image_fixed_yx raised a raw IndexError from a helper before its own descriptive guard; _gaussian_filter_torch silently returned non-2D/3D input completely unfiltered. (ee8c75b) Tests Coverage 50.2% → 92.9% (8,948 → 16,597 of ~17.8k statements). 25 new suites across the env managers (Cellpose/CAREamics/Spotiflow/ConvPaint/VisCy/ Ultrack/SAM2), the OME-Zarr/TIFF conversion path, the file selector and its worker, Batch Crop Anything, label inspection, ROI colocalization, regionprops, label-based cropping, reader/writer/sample-data/UI. Heavy deps are mocked as collaborators, never the function under test. Every file was adversarially re-audited (22 tests rewritten, 0 deleted); those audits are what surfaced the bugs above. Full suite: 3,595 passed, 3 skipped, 8 xfailed, 0 failed. (9fc8dad, 8a91b0d, 83d9d18, 1f80335, c4743fb, 63c0048) Label-cropping widget GUI tests skipped on macOS CI — the real napari viewer segfaults in vispy's glGetParameter headless, killing pytest at ~45% and taking coverage.xml with it. (3af8b68) CI, docs and chores Docs-only pushes skipped and superseded runs cancelled — a README edit cost a full 4-job matrix (~20 min). pull_request deliberately left off; tags exempt from cancellation so a release upload can't abort mid-twine. (1db0907) README TODO refreshed against the memory audit; measured 3.15 GB RSS on the 52 GB reference acquisition replaces the "~8+ GB" estimate. Dimension Order guidance added; the FSStore known-issue retired as fixed. (1695f86, b43118d, 5827fe1) Dropped the unused colocalization.py module (its registration was already commented out; the live path is _roi_colocalization.py). (d2d4ce8) .gitignore: graphify-out/. (da3779c)
Publication details
- Journal / source
- Zenodo (CERN European Organization for Nuclear Research)
- Publication date
- 31 August 2026