Skip to content

Notebook: tags per header block, colour pictures, one-click axes (PR 17b-1) - #247

Merged
guijacquemet merged 6 commits into
mainfrom
claude/notebook-17b
Nov 9, 2026
Merged

guijacquemet merged 6 commits into
mainfrom
claude/notebook-17b

Conversation

@guijacquemet

@guijacquemet guijacquemet commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

PR 17b of the notebook UX re-evaluation (owner decisions 2026-11-09, docs/restart/designs/ux-proposal-2026-11-09.md on MorphoFeature claude/restart-doc). It follows #244 (17a, merged; this branch has main merged in, so the diff is 17b only).

Split: 17b came out at about 2,000 changed lines, so it is in two PRs:

  • 17b-1 (this PR): items 2-6, which are the RGB colour composite, one tag answer per header block, the one-click axes confirm, the old step names, natural replicate order, and "uncalibrated".
  • 17b-2: item 1, folding unchanged rows on reopen. It is Notebook: fold unchanged rows on reopen (PR 17b-2) #248, stacked on this branch (base claude/notebook-17b). Merge it after this one.

Summary (by module)

  • preview_render.colour_composite (pure, new function): turns the three panels of one plane into one colour picture. Channel 1 is red, 2 green and 3 blue, and each keeps its own 0.5-99.5 percentile contrast. It is display only and never changes a source pixel.
    • A flat channel stays mid-grey and the note names it.
    • A channel with non-finite values is refused (ValueError), so it is shown channel by channel, never coloured.
    • It is reusable for 17c through Thumbnails.colour(layout, detail=) and Thumbnails.picture(layout, colour) (notebook_channel_thumbs). Thumbnails now caches the panels and makes PNGs on demand.
  • Where colour is drawn (a folder that is answered RGB, or pre-ticked from an RGB header):
    • Tag channels shows one colour picture per folder, R/G/B chips in red, green and blue, and Enlarge at 1024 px.
    • Image type now shows one picture per folder.
    • The pairing on Replicates, and the replicate blocks on Check and save.
  • notebook_channels_grid.TagGrid, one answer per header block (owner Q5):
    • Folders whose headers are identical, exactly, form one block. That means the same channel count, every raw header name present and equal (no case folding, no trimming), and the same colour flag.
    • The user sets one dropdown per C index for the block. Every folder of the block keeps its pictures below, for checking.
    • Nothing is grouped by guessing. These folders each get a block of their own:
      • a header with a missing channel name;
      • other names (DAPI ≠ dapi);
      • other saved tags;
      • a folder the user takes out with Tag this folder on its own (session only, never saved).
    • A block answer applies with_tags to each folder and saves once. It writes the same per-folder answers as individual confirms, and a test compares the draft bytes.
    • A label used twice is refused for the whole block.
    • The header-proposal confirm is now once per block.
    • The folder rows moved to the new notebook_channels_rows (ui).
  • Double RGB confirm removed: in the stepper the colour pre-tick is confirmed only on Image type (ImageTypeRows). The tag page restates the block's answer: "Answered colour (RGB) (Image type, step 7)", or "confirm it on Image type (step 7)". The classic channels_step() (no stepper) keeps its single confirm in the grid, because there is no image-type page there.
  • notebook_axes_quick (new, ui): one-click axes confirm (owner Q3).
    • The roles are offered only when all of these hold:
      • the axis review has no message at all;
      • every readable image fits the roles, with no missing axis to state;
      • every image names its axes in its header. A plain stack is offered only when the earlier run's confirmation still covers it unchanged (unchanged_confirmation).
    • The card shows the roles, the preview and Confirm these axes. The role boxes are folded under Look closer, or change the roles.
    • The click sets preview_checked and then calls the existing _toggle_confirmation, so it records exactly what the two clicks record. A test compares it with the manual path.
    • Nothing is ever confirmed without the click. Editing a role withdraws the offer.
    • On a reopen with unchanged folders, the earlier run's recorded roles are offered. After the click the stepper opens the first step still to do (Run on a saved experiment), so the reopen no longer stalls on Axes.
  • notebook_stepper / notebook_step_states:
    • StepState.note, and a new "noted" chip style (light green with a green border).
    • Pixel sizes says "✓ 3 Pixel sizes · uncalibrated", and the summary says "uncalibrated (pixels): no pixel size in the headers or stated", or "stated as pixels". Mixed sets say "N of them uncalibrated".
  • Natural replicate order (notebook_values.natural_key), display only:
    • rep2 comes before rep10, and the folder name breaks a tie.
    • It applies to RunLabels.order (run box plots and legends), the replicate blocks and short names of Check and save (description_review), the names rows, the step summaries, and the folder order of the tag grid and the image-type page.
  • Old step names (grepped): the results page is "Calculate the statistics (optional)" in a described run (no "Step 4"). "step 3" becomes "the run" in the results page, the stats status, the mask step and the design card. Pixel sizes is no longer said to be in step 1. The described axes "what next" no longer says "Your channels". The dataset/design messages say "Replicates in the notebook", not "step 1 of the notebook". The card headers lose their "A." and "B." prefixes. The classic hidden "What next" boxes keep their classic numbering, which is still right for embedders.
  • Docs: CHANGELOG, the AGENTS.md map, and the user guide (one-click axes). pyproject declares the two new modules as ui.

Decisions / for the owner

  • New display convention: replicate IDs are shown in natural order (rep2 before rep10, the folder name breaking a tie) in the run plots and legends, the names tables and the replicate blocks. Nothing is stored in this order.
  • A header without every channel name is not grouped. Two such folders say nothing about which channel is which, so each is tagged on its own. This is the same rule as physical_check.LayoutGroup.batch_confirmable.
  • The axis-step preview (before the axes are confirmed) is still one grey plane per C. A colour composite there would need the C role and the image type, which are not answered yet.

Notes for review

  • Size: 39 files, +1271/−248 against main, about 380 of them tests.
  • Not verified: the pages were driven headless and rendered with embed_minimal_html in Playwright chromium (1180 px, deviceScaleFactor 2), not in a live JupyterLab or Colab. Standalone renders lack JupyterLab styles and icons.
  • The mask evidence on Masks still draws the mask on one grey channel for an RGB folder. That is a follow-up if wanted.
  • RELEASE_REF still pins v0.4.0, as in 17a.

Tests

  • New tests:
    • test_notebook_tag_blocks.py (8): blocks, draft bytes equal for block vs one-by-one, nameless headers, DAPI/dapi, split, duplicate refusal, one proposal confirm, one RGB confirm only on Image type.
    • test_notebook_colour.py (8): PNG pixel checks that the composite is really colour and leaves the planes unchanged; refusals; colour pictures on tags, image type, enlarge, pairing and check-and-save.
    • test_notebook_axes_quick.py (5): offer and preview; one click equals two clicks; a plain stack is not offered; an unchanged reopen offers the run's roles and opens Run; an edit withdraws the offer.
  • Additions to existing files:
    • stepper (uncalibrated chip; header sizes give a plain done);
    • check-and-save (rep2/rep10 order);
    • run labels (natural_key and RunLabels.order).
  • Updated tests: block-aware helpers (grid.split) in test_notebook_channels.py and test_notebook_check_save.py; text changes in test_notebook_ui.py and test_notebook_convert.py; the stepper's "noted" chip.
  • python tools/check.py (.[dev,notebook,zarr], Python 3.13): ruff, format and code rules pass; 4971 passed, 4 skipped. The 4 skips are environment-dependent: 3 for a case-sensitive file system and 1 for running as root, which ignores file modes.
  • Screenshots: 26 PNGs from structured synthetic images (tests/channel_images.py): a fluorescence set, an RGB set, a rep2/rep10 set with a run, an unchanged reopen and a mixed reopen. Each one was looked at; the R/G/B chip colours and the duplicated caption were fixed after looking.

Generated by Claude Code

…17b-1)

- Tag channels: folders with identical headers (exact: channel count, every
  raw name present and equal, colour flag) are one block tagged once; a
  block answer writes the same per-folder draft answers as one folder at a
  time. A folder can be taken out of its block.
- The colour pre-tick is confirmed only on Image type; Tag channels
  restates it.
- RGB folders are drawn as one colour picture (colour_composite,
  Thumbnails.colour): tags, image type, pairing, check and save.
- Axes: one-click Confirm these axes when the roles leave nothing to ask;
  an unchanged reopen offers the earlier run's roles and moves on.
- Pixel sizes say uncalibrated on the chip and summary.
- Replicate IDs in natural order (rep2 before rep10), display only.
- Texts no longer name the old steps 1-4.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G3qp9AxjpGPw9xfWAUJNqc
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G3qp9AxjpGPw9xfWAUJNqc
natural_key appended the tie-break text after the parts, so "rep" against "rep2" compared
the text with a number and raised TypeError (run plots, names, tag grid, image type, check and
save). The parts are now a tuple of their own; the order is unchanged otherwise.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G3qp9AxjpGPw9xfWAUJNqc
On a reopen the recorded roles were re-offered after every role change and written back into
the role boxes, so a user's edit was silently undone. The recorded roles now go into the boxes
once per check; a role changed after that is the user's, and the recorded roles are offered
again only when the boxes equal them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G3qp9AxjpGPw9xfWAUJNqc
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G3qp9AxjpGPw9xfWAUJNqc

# Conflicts:
#	CHANGELOG.md
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.

2 participants