Skip to content

Backend ROI: tensorstore + zarr-python + tunnel honor roiVoxel#19

Merged
davidackerman merged 1 commit into
mainfrom
feat-roi-backend
May 27, 2026
Merged

Backend ROI: tensorstore + zarr-python + tunnel honor roiVoxel#19
davidackerman merged 1 commit into
mainfrom
feat-roi-backend

Conversation

@davidackerman
Copy link
Copy Markdown
Owner

Summary

PR #16 wired ROI slicing into the local Pyodide worker only; the HF backend silently ignored the `roiVoxel` field, so any `runtime="backend"` analysis (which is the only option for N5) loaded the full array regardless of the ROI. That defeated the point of the feature — "smaller cube → finer scale reachable" can't happen if the whole volume comes back anyway. This PR threads ROI through every backend load path.

Changes

  • `LayerSpec` gains an optional `RoiVoxel { start, stop }` field (array-axis order, parallel to `axesOrder`). Matches the wire format the frontend was already sending; before this PR Pydantic was silently dropping it.
  • `_load_via_tensorstore` builds a per-axis slice tuple so chunks outside the ROI are never fetched (tensorstore native).
  • `_load_via_zarr_python` (fallback for CellMap's numcodecs extras) applies the same selection on the `zarr.Array` — numpy-style indexing pushes the slice down to chunk reads.
  • `read_zarr_scale` (`browser_store.py`, tunnel path) gains a `selection` kwarg; `_load_layer` constructs the slice tuple when `roiVoxel` is set so only chunks intersecting the cube come back over the WS tunnel — matters most for local-data layers.
  • `_layer_to_globals` shifts each per-axis offset by `roi.start * voxel_nm`. Without this, Python code reporting absolute centroids / fly_to targets would be in the ROI's local frame instead of the original layer's world frame.

What this unblocks

Running the trace from earlier ("measure mito properties in a 500³ nm ROI") against the macrophage dataset (n5, backend-only) now actually slices to the ROI — the agent's request stops being a no-op for the spatial restriction.

Deploy

Backend-only change. After merge, needs a `git subtree push --prefix hf-space …` to land on the running Space.

PR #16 wired up ROI slicing in the local Pyodide worker only; the HF
backend ignored the field, so runtime='backend' (the only option for
N5) would load the full array no matter what — defeating the
"finer scale on a smaller cube" point of the feature.

This patch threads roiVoxel through every backend load path:

- LayerSpec gains an optional RoiVoxel { start, stop } field
  (array-axis order, parallel to axesOrder, matching the wire
  format the frontend already sends).
- _load_via_tensorstore builds a per-axis slice tuple so chunks
  outside the ROI are never fetched.
- _load_via_zarr_python (fallback) does the same via numpy-style
  indexing on the zarr.Array.
- read_zarr_scale (tunnel path) gains a `selection` kwarg; _load_layer
  constructs one when roiVoxel is set so only chunks intersecting the
  cube come back over the WS tunnel.
- _layer_to_globals shifts each per-axis offset by roi.start *
  voxel_nm, so Python code reporting absolute centroids / fly_to
  targets stays in the original layer's world frame.

Net: ROI now actually saves backend memory AND bandwidth (matters
for tunneled local-data layers most), not just frontend coords.
@davidackerman davidackerman merged commit 6b946ac into main May 27, 2026
1 check was pending
@davidackerman davidackerman deleted the feat-roi-backend branch May 27, 2026 21:25
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