Skip to content

feat: navigator widget, label features and URL reading, with the phase 1 and 2 review fixes (napari plugin phase 3) - #7

Open
aofei-liu wants to merge 9 commits into
aliu/napari-plugin-phase2from
aliu/napari-plugin-phase3
Open

feat: navigator widget, label features and URL reading, with the phase 1 and 2 review fixes (napari plugin phase 3)#7
aofei-liu wants to merge 9 commits into
aliu/napari-plugin-phase2from
aliu/napari-plugin-phase3

Conversation

@aofei-liu

Copy link
Copy Markdown
Collaborator

Summary

Phase 3 of napari_plugin/PLAN.md, stacked on #6. Adds the sp-ops navigator dock widget (a lazily expanded tree of the store with checkboxes and an add button), label features from a table joined by a computed edge in sp-ops:relationships, contrast limits from the lowest pyramid level, and HTTP/URL reading with detection, child opening and parquet all going through the store or fsspec. The second commit fixes every finding from the delegated reviews of #5 and #6; they land here because the four PRs are meant to merge together today. Per-PR review-outcome comments on #5 and #6 list what was fixed and where.

Acceptance criteria

  • a dock widget shows the store as a tree with checkboxes and an add button, so a user opens one well without re-dropping. test_navigator.py (tree model and an offscreen Qt smoke test)
  • a merged collection with a computed edge from a labels element to a table on value/label gives the labels layer the table's obs columns as features. test_labels_layer_carries_table_features, test_merged_collection_opens_over_http
  • contrast limits come from the lowest pyramid level. test_image_contrast_limits_come_from_the_lowest_level
  • opening by HTTP URL is exercised against an example store served locally. test_url.py (synthetic store; the real stores are 1 GB and not served in tests)

Decisions

D19 points and shapes coordinates are taken as written and the offset goes to translate. D20 features only from computed key edges, obs read through zarr. D21 detection claims sp-ops stores or a dropped collection and stops at the .zarr component. D22 Qt-free tree model under a thin Qt widget. Recorded in PLAN.md.

Deviations from plan

  • Rule 3: the widget was built by a parallel agent; its table test was pointed at the fixture's real table.
  • Commit separation is by module rather than strictly by concern: images.py carries both the contrast-limits feature and two review fixes.
  • tests/spops_store.py is 320 lines, over the soft limit, as the single fixture writer.

Verification

  • cd napari_plugin && QT_QPA_PLATFORM=offscreen UV_NO_SYNC=1 .venv/bin/python -m pytest tests -q → 51 passed, 7 skipped. Baseline on the phase 2 branch was 38 passed, 6 skipped.
  • With SP_OPS_PROCESSED_EXAMPLE and SP_OPS_RAW_EXAMPLE set → 58 passed.
  • uvx ruff check --select F,B,UP,SIM src tests → clean.

Self-check: PASSED

📋 Phase 3 of napari_plugin/PLAN.md
🤖 Generated with Claude Code

aofei-liu and others added 4 commits September 4, 2026 11:18
…avigator dock widget

A labels layer whose collection has a computed key edge to a table receives
the table's obs columns as napari features indexed by label value; obs is
read through zarr, decoding arrays, string arrays and categoricals. The
navigator widget renders a Qt-free lazily expanded tree of the store and
opens checked nodes through the reader.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…nd the features hookup

Review fixes: guard a None affine and pass rotation or shear to napari as
an affine; take node names and file URLs from the path string, not the
store repr; detect RGB on any channel position and move it last; fall back
to napari-ome-zarr for node kinds this plugin lacks; read axes from
coordinateSystems under ome.attributes; split paths on either separator;
claim only sp-ops stores or a dropped collection and stop the walk at the
.zarr component; open in-store children and tables through the parent
store with posixpath; resolve inline RFC-8 descriptors and the layout
Reference; skip missing children with a warning; read the layout once and
warn when a tile has no polygon; compose tile offsets with ancestor
offsets; count the budget at emission; parse settings leniently and match
prefer to its env name; handle channel-split or undeclared channels when
stacking rounds; draw one exterior ring per polygon part and honour the
GeoParquet primary column; read points row-group by row-group up to the
cap and put the offset in translate; select wells and plates on
descriptors before opening.

Phase 3 additions in the same modules: percentile contrast limits from the
lowest pyramid level, and label features attached in the traversal.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…essions

The synthetic screen gains an AnnData-style cells table joined to the
labels by a computed edge; the suite serves the store over HTTP.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ith D16 and D17

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
aofei-liu and others added 3 commits September 4, 2026 11:50
…ixel-frame points

Two collaborator stores written with ome-zarr-py encode every image as an
RFC-8 multiscale collection of singlescale levels with no multiscales list,
put all placement in a well-level scene, and store points in the image's
pixel frame. The reader now takes levels and axes from that form, pads
scale and translation scene transforms of any ancestor onto the image axes
by name, gives points the scale and translation of a sibling image, reads
nullable AnnData obs columns, tries every computed edge from any ancestor
collection when attaching label features, and warns about tables only when
one is dropped directly.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…lumns and the collaborator stores

The synthetic iss image is now written as singlescale levels behind a
well-level scene translation; two tests open the collaborator stores when
SP_OPS_OME_ZARR_PY_STORES points at them.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ts frame rule (D17, D19, D23)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@aofei-liu

aofei-liu commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator Author

Follow-up after opening two collaborator stores written with ome-zarr-py (commits on this branch after 2650bf2).

Correction to how this was first described: the collaborator stores follow the RFC-8 text, and the two example stores this plugin was developed against are the transitional ones. RFC-8 defines three node types, collection, multiscale and singlescale, and says the Multiscale node's nodes "MUST be an array of Singlescale objects" and that this interface "replaces the multiscale metadata defined in the previous versions". docs/extension.md line 26 names the same three types. The open-questions page raised exactly this in Q18 and Q28. The example stores keep a 0.5 multiscales list inside RFC-8 collections, which the reader must still accept because napari-ome-zarr and every existing 0.5 image use it.

What the reader lacked: the RFC-8 form (no multiscales list, levels as singlescale nodes with per-level coordinateTransformations, axes only in the node's coordinateSystems), so it classified every image as unknown and every collection came back empty. Placement in a well-level scene was reported and ignored; points in the image pixel frame had no scale; one table uses AnnData's nullable-string encoding; one labels edge is declared on the plate.

Fixed: levels and axes are read from the RFC-8 form as well as the 0.5 list (D23); scale/translation/sequence scene transforms from any ancestor are padded onto the image axes by name (D17 revised); points sharing a collection with an image take its scale and translation (D19 revised); nullable obs columns decode; label features try every computed edge from every ancestor collection and skip endpoints that are not tables; table warnings fire only for a directly dropped table.

One note for the store writer: RFC-8 says a singlescale transform's input references the id of the singlescale node itself; these levels have no id and reference a per-level coordinate system instead. The reader does not use input, so nothing breaks, but a strict validator would flag it.

Result: biohub store root opens as 21 layers at the scene's 15600 µm offset with cell_seg features from the plate-level cells table; scallops store root opens as 14 layers with a 9-step round slider, scaled peaks and reads, and features on nuclei, cells and cytosol. Suite: 63 passed with all three store sets, 54 passed and 9 skipped without.

…le stores are transitional

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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