Skip to content

Run on a region in the browser: a box or the whole volume, saved as OME-Zarr in a folder on the machine - #135

Merged
davidackerman merged 6 commits into
mainfrom
run-region
Oct 19, 2026
Merged

davidackerman merged 6 commits into
mainfrom
run-region

Conversation

@davidackerman

@davidackerman davidackerman commented Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

This is part of the batch, #137. Merging #137 with a merge commit marks this PR merged too.

The browser app gets a Run tab. It computes the served models over a box, or over the whole volume, and saves each result as an OME-Zarr in a folder you pick on your machine. Until now, a model in the browser computed only the chunks the viewer asked for, and nothing was kept.

How to use it:

  1. Open the Run tab and click Draw a box.
  2. Hold Ctrl and click two opposite corners in the viewer. Scrolling between the two clicks gives the box depth. The offset and size fields fill in and can be edited. Whole volume also works.
  3. Click Choose folder…, pick a folder and allow writing.
  4. Click Run. A progress bar shows time left and has Cancel, and the viewer stays usable meanwhile.
  5. Click Show the saved predictions in the viewer to open each result as a "(saved)" layer, read back from the folder.

What it writes:

  • One <folder>/<model>.zarr per ticked model.
  • zarr v2 with OME-Zarr 0.4 metadata, at the model's own level, with its scale and translation.
  • The level's whole shape: chunks outside the box are missing, so zarr reads them as zero.
  • Empty chunks are skipped.
  • The model, chain, dataset, region and time are recorded under cellmap_flow in the attributes.
  • A Compression choice offers gzip (smaller) or None, for readers without gzip such as Fiji on a Mac.
  • Without the File System Access API (Firefox, Safari), the result downloads as a zip instead.

The engine work is chunkmirage's Engine.materialize (JaneliaSciComp/chunkmirage#39, merged): it walks the chunk grid in the background behind the viewer's requests, keeping a slot free for them. This PR pins web/chunkmirage.lock to its merge commit, 74ba52e. cellmap-flow only builds the panel, the region and the output folder:

  • web/src/run-region/region.ts: the box in voxels and chunks.
  • run.ts: one model's run.
  • output.ts: the folder or zip store.
  • panel.ts: the tab.

The box is drawn with Neuroglancer's legacy annotateBoundingBox tool set on the run_region layer. That's why it's Ctrl+click: a key binding for that tool is silently dropped by this Neuroglancer build.

Checked in headless Chromium against the merged chunkmirage:

  • A 4-chunk box of setup_53_2d on jrc_mus-liver was written in 14 s.
  • zarr-python read the output: gzip, 16 nm scale, 4 nm translation (voxel 0's centre), the level's full shape with the 3 channels first, values 0 to 0.999 in the box, zeros outside it, and the provenance under cellmap_flow.
  • The saved layer opened in the viewer.
  • npm run check passes (typecheck, 1465 tests, build).

…hole volume, saved as OME-Zarr in a folder on the machine

A browser-only Run tab. Tick the served models (all by default); draw a
box in the viewer (Draw a box adds a run_region annotation layer whose
tool is Neuroglancer's bounding box, two Ctrl+clicks at opposite corners;
a legacy annotation tool, which toolBindings cannot take), or pick Whole
volume, or type the offset and size in nm. The tab says each model's box
in voxels and chunks at the level it is served at and warns of a run of
more than 2,000 chunks. Choose folder... picks a folder with the File
System Access API (kept in IndexedDB, its write permission asked again in
the Run click after a reload). Run writes each model, one after another,
to <folder>/<model>.zarr through chunkmirage's Engine.materialize (the
layer's own view at its one level: what the viewer shows, postprocessing
applied), as zarr v2 with OME-Zarr 0.4 metadata, gzip or none
(Compression: None for Fiji, which reads no gzip), empty chunks left out,
with progress, time left and Cancel; the viewer's own chunks go first.
A <model>.zarr already there is replaced only after a confirm. The group
attributes record the model, variant, chain, dataset, region and time
under cellmap_flow. Show the saved predictions in the viewer opens each
zarr as a "<model> (saved)" layer read back through the service worker's
local/ route. Without File System Access (Firefox, Safari) a run of up to
256 MB is offered as a zip.

Nothing of the walk or the zarr writing is here: it is the engine's.
web/chunkmirage.lock still names 9eaf308, which has no materialize; it is
bumped once chunkmirage has the method.

Checked in headless Chromium: the box drawn with two Ctrl+clicks fills
the fields; a 4-chunk box of setup_53_2d written to a folder (the
origin's private file system standing in for the picker) in 15 s; the
result opened by zarr-python 2.18 (scale 16 nm, translation 4 nm, the
level's full shape, values in [0, 1], zero outside the box, provenance
in the attributes) and by the viewer as the saved layer.
… be dropped on it

Typing in the region's fields redraws the run_region layer's box to match
once typing pauses (400 ms; at once on change), as a box drawn fills the
fields: withBox writes the region into the layer's own coordinate space
(coordsFromNm, pointerNm backwards) as its one box, and a box read back a
little off (Neuroglancer keeps corners as 32-bit floats) is not taken as a
new one (sameRegion).

A folder dropped on the Output folder block is used as the picker's would
be, the browser asking to allow writing to it at Run. The note says Chrome
refuses Downloads and the home folder themselves ("it contains system
files"): a folder made inside one works.
davidackerman added a commit that referenced this pull request Oct 16, 2026
…ize, a folder can be dropped

# Conflicts:
#	web/test/unit/viewer-state.test.ts
… by its translation

The Run tab asks Engine.materialize for extent "box": the zarr is an array of
the region's voxels (hi − lo on the served level), not the level's whole shape
with the box's chunks in it, and its OME translation puts its voxel 0 on the
level's voxel lo, so Neuroglancer and napari still place it where the model's
layer is. chunkmirage stitches the saved chunks from the model's, so a box off
the chunks' edges computes more chunks than it saves: the plan says both
("saved as that box ...; computes N chunks"), its size is the saved chunks',
and the progress and time left go by the chunks computed.

Needs chunkmirage with extent "box" (feature/materialize-box); the lock is
bumped once that is merged.
… memory, and can snap its corner onto a chunk edge

A box whose corner is inside the model's chunks along several axes is
stitched from them, and chunkmirage holds up to a slab of the saved array's
chunks while it does. The tab asks Engine.materializePlan (computing
nothing) and, above 512 MB, says how much and what putting the corner on a
chunk edge along one axis would hold, with a button that does it
(snappedRegion: the corner moved back to its chunk's start, rounded up to a
whole nm so that a 10.48 nm voxel does not land it a voxel short, the far
side kept). On jrc_hela-2 with setup_53, a box over 90% of the volume held
953 MB; Snap z brought it to 12 MB. The lock is chunkmirage d6fd94a, with
#43's materializePlan.
@davidackerman
davidackerman merged commit aa072e8 into main Oct 19, 2026
7 checks passed
@davidackerman
davidackerman deleted the run-region branch October 19, 2026 14:40
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