Skip to content

[3/3] Add make_stitched_labels (materialise stitched labels)#1207

Open
timtreis wants to merge 5 commits into
scverse:mainfrom
timtreis:feature/stitched-labels
Open

[3/3] Add make_stitched_labels (materialise stitched labels)#1207
timtreis wants to merge 5 commits into
scverse:mainfrom
timtreis:feature/stitched-labels

Conversation

@timtreis

@timtreis timtreis commented Jun 14, 2026

Copy link
Copy Markdown
Member

Completes the tile-cut stitching arc ([1/3] #1188, [2/3] #1193) with the materialisation step.

Usage

sq.experimental.tl.calculate_tiling_qc(sdata, labels_key="labels")
sq.experimental.tl.assign_stitch_groups(sdata, labels_key="labels")
sq.experimental.im.make_stitched_labels(sdata, labels_key="labels")
# sdata.labels["labels_stitched"]      -> pieces of a cut cell share one ID (original untouched)
# sdata.tables["labels_stitched_table"] -> one row per stitched cell

Knobs: merge_strategy (how additive user features aggregate across pieces; default "sum"), join_labels (close the seam so a group is one connected component; stays lazy on dask), write_table, inplace.

Also in this PR

  • De-bloat of the merged arc: inlined the single-use utils/_geometry.py helpers into their one caller (module deleted) and routed _resolve_qc_params through the shared resolve_params. No behaviour change.

Closes the #1170 arc.

timtreis and others added 4 commits June 12, 2026 16:35
Lock the validation-sweep outcome: at min_confidence=0.5 the deterministic
fixture recovers >=50% of cut pieces with no intact false-merges. min_confidence
default stays 0.7 (full attainable recall, zero false merges); gap_proximity
kept in the 5-feature score.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…bels)

PR-C of the scverse#1170 split. Adds sq.experimental.im.make_stitched_labels: reads
the stitch_group_id mapping written by assign_stitch_groups and registers a new
labels element where each stitched group shares one ID (original labels left
untouched), plus an optional collapsed AnnData (one row per group) with
configurable merge_strategy.

Stacks on PR-B (feature/tiling-stitch-algo) and reuses its full-pipeline tests.

Scale rework (must handle 100k x 100k, never materialise the full array):
- LUT remap stays lazy; labels present in the image but absent from the QC
  table (e.g. min_area-filtered cells) pass through instead of indexing OOB.
- join_labels is now chunk-aware via dask map_overlap (depth = close_radius+2),
  never computing the whole image or running a full-frame regionprops.
- group aggregation vectorised (argsort+split, pandas groupby) instead of the
  O(cells x groups) per-group np.where scan.
- X aggregation is sparse-safe: sum/mean via sparse matmul, first via sparse
  gather, other reducers per-group-bounded; the full matrix is never densified.
- validate label_id/is_stitched up front; squeeze a leading singleton dim.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…our change

- inline equivalent_diameter + largest_contour (single consumer _tiling_stitch)
  into their call site and delete utils/_geometry.py; keep both guards (1px pad
  precondition + empty-contour skip).
- route _resolve_qc_params through the shared resolve_params helper instead of a
  duplicated Mapping-validation block; drop the now-dead _QC_FIELDS and unused
  fields import. utils/_params.py now has two genuine callers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…le + validation

Addresses a max-effort review of the stitched-labels path:

- collapsed table no longer sums QC-contract columns: centroid_y/x take the
  mean of the pieces (a merged cell's position), the per-piece cut-artifact
  scores take the max (worst piece); merge_strategy now applies only to genuine
  additive user features. Drops the dtype-restore that re-narrowed/truncated
  promoted sums and means.
- _aggregate_X: sum no longer treated as integer-preserving, so an integer .X
  promotes to float64 instead of wrapping (uint16 200000 -> 3392); a callable
  strategy is now applied to singleton groups too (obs/X parity).
- multiscale: parse the new element with the resolved scale's transform (not the
  DataTree base/Identity), so the output overlays correctly; documented as a
  single-scale element at the QC scale's resolution.
- validate label_id (positive, unique, non-NaN) and merge_strategy up front, so
  bad input fails fast even with write_table=False.
- preserve varm (var axis is unchanged); correct the join_labels docstring (it is
  lazy via map_overlap and bridges seams up to 2*close_radius px, not "forces
  materialisation").
- add TestReviewFixes regression locks (each fails on the pre-fix code).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@timtreis timtreis requested a review from selmanozleyen June 14, 2026 17:25
@codecov

codecov Bot commented Jun 14, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 84.72222% with 33 lines in your changes missing coverage. Please review.
✅ Project coverage is 75.61%. Comparing base (e8d3618) to head (83c0e32).

Files with missing lines Patch % Lines
src/squidpy/experimental/im/_stitched_labels.py 84.61% 13 Missing and 19 partials ⚠️
src/squidpy/experimental/tl/_tiling_stitch.py 80.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1207      +/-   ##
==========================================
+ Coverage   75.29%   75.61%   +0.31%     
==========================================
  Files          59       59              
  Lines        8429     8620     +191     
  Branches     1395     1434      +39     
==========================================
+ Hits         6347     6518     +171     
- Misses       1527     1530       +3     
- Partials      555      572      +17     
Files with missing lines Coverage Δ
src/squidpy/experimental/tl/_tiling_qc.py 70.66% <100.00%> (-0.67%) ⬇️
src/squidpy/experimental/tl/_tiling_stitch.py 75.29% <80.00%> (ø)
src/squidpy/experimental/im/_stitched_labels.py 84.61% <84.61%> (ø)

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant