napari-worm-neuron-annotator
napari-worm-neuron-annotator is a napari plugin for navigating and annotating
read-only neuron bounding-box ROIs on 3D or 4D Image volumes.
The plugin keeps each data source in a separate role:
- the Image layer supplies the spatial axes, world transform, and Z-navigation context;
- the ROI array supplies neuron identity and box geometry;
- runtime
VectorsandPointslayers show boxes and optional text without writing them into a dense mask.
The plugin does not modify Image or ROI source data. Ordinary napari Labels
layers may coexist in the viewer, but this plugin does not select, modify, or
synchronize them.
Features
- Image + ROI operation independent of Labels layers.
- Read-only loading of
(T,N,K)ROI NPY arrays. - Dynamic 2D bounding rectangles and 3D 12-edge wireframes.
- Stable per-neuron box colors derived from zero-based ROI identity.
- Checkable neuron list with a separate active neuron.
- Digital/biological multi-neuron search with explicit match selection.
- All/None controls, cumulative Q/W navigation, and checked-only Shift+Q/W.
- Optional Biological, Digital, or combined selected-box text.
- Fixed canvas shortcuts for Z-slice and time-frame navigation.
- Active-neuron highlighting and view centering.
- Session-only whole-viewer rotation and screen-axis flip controls.
- View-preserving Z-layer display synchronized across Image and ROI overlays.
- Zero-based ROI annotation with optional Excel import/export.
- Opt-in 2D proofreading of box centers, dimensions, missing observations, and added neurons using a non-destructive JSON sidecar.
Installation
Install into an existing napari environment:
pip install napari-worm-neuron-annotator
For a fresh environment, install napari with its default Qt 6 backend:
pip install "napari-worm-neuron-annotator[all]"
Excel support alone is available through:
pip install "napari-worm-neuron-annotator[excel]"
The base plugin does not install or select a Qt binding. The napari
environment owns the Qt backend; the convenience all extra delegates that
choice to napari.
This release targets Python 3.11–3.14 and napari 0.8.x. See the napari 0.8 migration notes for the dependency and compatibility decisions.
Image + ROI workflow
- Open an Image layer with
(z,y,x)or(t,z,y,x)axes. - Open
Plugins > Worm Neuron Annotator. - Select the Image layer, then load the ROI NPY file.
- Click a neuron row to check and activate that ID.
- Use the checkbox column to add or remove IDs from the persistent set.
- Use Q and W to check and activate the previous or next valid ID without clearing IDs already checked.
- Use All or None to check every ID or clear all checked/active IDs.
With the napari canvas focused, use G/H for the previous/next Z slice in 2D, J/K for the previous/next time frame of a 4D Image, and Shift-J/Shift-K to move backward/forward by 10 time frames. Navigation stops at the data bounds rather than wrapping. In an individual Z layer, G/H stays within that layer's half-open Z range.
The active row is bold and remains the current row. Unchecking the active ID clears the active state; unchecking another ID does not change the active neuron.
The ROI array defines the neuron list. Labels layers are not used for selection, box rendering, annotation, centering, time navigation, or Z-layer display.
Worm orientation
The Worm Orientation panel rotates the complete viewer clockwise by 0°, 90°, 180°, or 270° and can flip the final screen horizontally or vertically. Image, ROI boxes, optional text, and Z-layer views stay aligned because the controls change only napari's viewer axes and camera orientation. Source arrays and layer transforms are not modified.
Reset restores the viewer orientation captured for the current session. Closing the widget also restores that orientation. If you use napari's native transpose or camera-orientation controls, the resulting view becomes the new session baseline and the plugin controls return to their default state.
The legacy LabelManager Python and command aliases remain available for
compatibility. The public widget name is NeuronAnnotatorWidget, and napari
lists only that widget.
Neuron selection and search
The neuron tree keeps persistent checked identities separate from the one active identity. Q/W moves through valid neurons and checks each activated identity. Shift+Q/W moves only through already checked neurons that are valid at the current time and, in Layer mode, belong to the active Z range. Both forms of navigation wrap in zero-based digital-ID order.
The search field accepts comma-separated digital IDs and biological-name fragments. Numeric tokens match an ID exactly; other tokens use a case-insensitive biological-name substring match. Typing highlights every matching tree row without changing selection or moving the view. Enter cycles through matches one at a time, checking and making only that match active. Check matches adds all matches to the existing checked set without changing the active neuron.
Search covers all global ROI identities, including observations missing at the current time or outside the active Z range. Those results remain gray and cannot move the current view until they become navigable. Search highlighting is confined to the tree; image highlighting continues to use the existing selected and active overlay layers.
Z-layer display
The compact Z Layers panel separates a 3D volume along Z so individual depth ranges can be rendered without the other ranges obscuring them:
- Select a compatible Image layer.
- Inspect the current-time curve showing how many pixels in each Z slice are
strictly above the editable threshold (default
170). Click the curve to add or remove a cut, or enter explicit cuts such as4,10. - Click Split.
- Use Show to select
Allor one generated layer.
Cuts use half-open Python ranges. For a volume with 18 Z slices, 4,10
creates [0,4), [4,10), and [10,18). A boundary slice belongs to the
following layer.
All displays every generated Image layer using additive blending and all currently valid checked/active ROI overlays. Layer k displays only that Image range and the overlays whose box center Z belongs to the range. A box that crosses a cut is shown whole in the one layer containing its center.
Checked and active neuron identities remain global. In an individual layer, Q/W navigates only neurons assigned to that layer; other neurons remain in the list, are shown in gray, and keep operable checkboxes. Activating a gray row does not move the view outside the selected Z layer.
Generated Image layers use slices of NumPy arrays, memory maps, or Dask
arrays rather than full-size zero-filled copies. Direct Zarr arrays should
be wrapped as Dask arrays before splitting. The Image source must have
(z,y,x) or (t,z,y,x) axes, axis-aligned volume depiction, and no clipping
planes. Clear removes generated Image layers and restores the source Image
visibility captured before splitting. Normal napari eye icons may still
override visibility until the next Show selection.
Launch the validated 20260304_w3_immobile dataset
The repository includes a ready-to-use launcher for the git-ignored local
dataset at data/20260304_w3_immobile_npy:
pixi run launch-actual
It memory-maps volumes.npy and neuron_point_tuple.npy, opens napari, docks
the navigator, and loads all 120 ROI identities.
ROI input format
The ROI loader accepts a numeric NumPy array with shape:
(T, N, K), K >= 6
The first six fields are:
x_center, y_center, z_scaled, width, height, depth_scaled
Additional fields are ignored. The neuron ID is the index on the N axis:
neuron_id = 0 ... N - 1
NaN, infinite values, non-positive sizes, and time points outside the source array are treated as missing observations. Missing neurons remain in the checkable list so that their global identity is stable, but Q/W skips them at the current time point.
Coordinate and time mapping
The plugin requires the selected Image layer to have one of these axis orders:
(z, y, x)
(t, z, y, x)
z_divisor, defaulting to 5, converts source z and depth coordinates:
z_index = z_scaled / z_divisor
depth_in_slices = depth_scaled / z_divisor
For a viewer that displays a cropped or strided time range:
source_t = volume_start + viewer_t * volume_stride
Configure volume_start and volume_stride before loading the NPY.
The derived ROI overlay layers copy scale, translation, axis labels, and units from the Image layer. Do not apply the z scale a second time in the ROI coordinates.
2D and 3D box display
Two managed Vectors layers are created after loading an ROI file:
Neuron boxes – selected: checked, currently valid boxes colored by their stableneuron_idpalette;Neuron box – active: the active box with a thick yellow outline.
Initially only the first valid neuron is checked and active. All includes all IDs in the selected layer, while None empties both box layers and the optional text overlay. Checked identities that are missing at the current time remain checked but are temporarily omitted from the geometry.
Enable Show selected box labels to place one text label at the center of
each currently rendered checked box. Label text selects Biological,
Digital, or Digital + biological text. Biological is the default and falls
back to the zero-based neuron_id when empty; the combined form is written as
12 · AVA and also falls back to the ID. The third annotation column is not
used for box labels. The option is off by default. Use Text color to choose
a session-only label color that contrasts with the current Image colormap.
Use Show neuron overlays or F10 to temporarily hide/show the plugin's selected box, active box, and optional box-label layers while keeping Image, Z-derived Image, Labels, and user-created layers unchanged. This display-only toggle preserves checked and active neuron state and is disabled during proofreading.
In 2D mode, the plugin draws four rectangle edges only when the current z slice intersects the box's half-open z range.
In 3D mode, each box is represented by 12 vector edges. Overlapping boxes
remain independent vector records with a neuron_id feature. They may overlap
visually, but one box does not erase the identity of another.
Vectors and the transparent Points text layer are derived display data. They are removed when the ROI is unloaded or the widget closes and are not saved as a separate annotation format.
The proofreading target is a separate, session-only Vectors layer. It is drawn as two thin orthogonal line segments (rather than a Points marker), with a default half-length of 8 data units and an edge width of 1 pixel. These display constants are independent of the neuron box dimensions.
2D proofreading
Proofreading is off by default and is available only in napari's 2D display with Z view set to All. Select the source Image layer, turn proofreading on, then make an unmodified short left-click on the Image to lock a fixed crosshair target. Moving the pointer does not move this target. Then use:
- F7 to delete the active neuron's observation at the current volume;
- F8 to place a missing active observation at the locked target;
- F9 to add a provisional neuron at the locked target using the default
width/height/depth of
7/7/3; - F12 to discard an unapplied size draft and leave proofreading mode.
Successful F8/F9 placement clears the target. Changing time or Z, or leaving proofreading mode, also clears it. F8 never moves a box that is already present. Width, height, and depth accept positive floating-point values. Apply current t changes only the locked observation at the current Image time, preserving its center and leaving other volumes untouched. Apply to all existing… is an explicit opt-in operation that changes the size of every existing observation for that neuron; missing observations are not created and all centers remain unchanged. Delete-all is explicitly confirmed and removes the active ID's observations from every raw volume without deleting or renumbering its identity. Added IDs can be retired; retired numeric IDs remain reserved and are not reused.
The current-neuron line reports the final state relative to the raw ROI using
(moved), (resized), (moved + resized), (placed), (deleted), or
(added) markers. These markers remain visible after saving; the separate
Unsaved proof edits indicator only describes changes since the most recent
save/load snapshot. A size edit that has not yet been applied is shown as an
Unapplied size draft and is never written to a sidecar without an explicit
Apply/Discard decision.
Discard scope controls what Discard changes restores to the most recent
successful Save/Load state. It defaults to Current t · active neuron; the
other choices restore All t · active neuron or All unsaved edits. Current-t
discard uses the configured Image-time to raw-volume mapping. Discarding one
neuron does not affect unsaved edits belonging to other neurons. The two
broader scopes require confirmation.
Save proof edits writes canonical sparse edits to a schema-v2 JSON sidecar
(changed_fields records whether each patch changes presence, center, and/or
size). Existing schema-v1 sidecars are accepted and kept clean in memory; the
next explicit save upgrades the same file in place. The current sidecar path
is retained for subsequent saves, while Save As… switches that path.
Cancel or validation/permission failures leave the working state and path
unchanged. The original ROI NPY remains read-only. Export corrected NPY
creates a separate array with stable neuron indices; deleted geometry uses NaN
in the first six fields. If an Image's shape or spatial metadata changes,
proofreading pauses until a compatible Image is restored.
Applied unsaved edits are also protected automatically every 30 seconds for a
file-backed ROI. Recovery snapshots live beside the ROI in
<ROI filename>.proofread-recovery/; they contain both the complete working
state and the last saved/loaded baseline, but never an unapplied size draft.
The Recovery… dialog lists snapshots and requires an explicit Restore or
Delete—recovery is never loaded automatically. Protection continues while
proofreading is off or its Image is detached. If the ROI file changes on disk,
automatic writes pause and formal saves are refused until the ROI is reloaded.
The status line reports the last protected time or a write failure; recovery
does not clear the separate unsaved-edits indicator. With normal local I/O, a
crash can lose roughly the latest 30 seconds plus snapshot processing time.
Snapshots include the saved baseline, so they can be larger than the formal
JSON. Unresolved snapshots from other sessions are retained until handled.
Restoring a snapshot preserves provisional neuron IDs and Discard's saved baseline. If the original formal JSON has changed or disappeared, the next save requires Save As…. A read-only recovery directory is reported without repeated dialogs, and writes are retried on later timer ticks.
Before replacing an existing formal JSON, Save/Save As preserves its exact
previous bytes in <formal filename>.history/. The newest 10 distinct
versions are retained, duplicate/no-op saves do not create backups, and an
externally changed bound file must be saved with Save As…. History…
loads an older version as unsaved working state over the current saved
baseline; saving that rollback follows the same backup rules and never reuses
an added neuron ID.
History files cannot be overwritten even if opened through Load…. A backup
failure leaves the formal JSON and unsaved edits intact; a failure to prune old
history is reported separately after an otherwise successful save.
Annotation
The digital column stores the zero-based ROI neuron_id.
The table follows the loaded ROI identities. Existing biological names and
annotation text are preserved by identity when the ROI source changes.
Activating a neuron selects its annotation row. Selecting a table row checks
and activates the corresponding neuron without clearing other checked IDs.
The biological value is also displayed in the neuron list.
The complete navigator is vertically scrollable when the napari dock is shorter than its controls.
Excel operations support .xlsx workbooks. Saving and loading do not apply an
implicit +1 or -1 conversion.
Development
Run tests and lint from the repository root:
pixi run pytest -q
pixi run -e excel pytest -q
pixi run ruff check .
The repository uses a src layout. Pure ROI parsing and geometry live in
src/napari_worm_neuron_annotator/_roi.py; Qt and napari lifecycle behavior
live in src/napari_worm_neuron_annotator/_widget.py.
License
Distributed under the BSD-3-Clause license.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file napari_worm_neuron_annotator-0.4.3.tar.gz.
File metadata
- Download URL: napari_worm_neuron_annotator-0.4.3.tar.gz
- Upload date:
- Size: 201.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
915a6794195e3350af8658e3a6cf191859bca9bf74894b8c2cc3f1607587f98c
|
|
| MD5 |
57b40b25d14176298c0267b06bd10bb1
|
|
| BLAKE2b-256 |
0b58ac6b799dc8774cdbe154f220a10221bd3e44932c2aa7210fd986dde5b137
|
Provenance
The following attestation bundles were made for napari_worm_neuron_annotator-0.4.3.tar.gz:
Publisher:
release.yml on Wenlab/napari-worm-neuron-annotator
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
napari_worm_neuron_annotator-0.4.3.tar.gz -
Subject digest:
915a6794195e3350af8658e3a6cf191859bca9bf74894b8c2cc3f1607587f98c - Sigstore transparency entry: 2748115750
- Sigstore integration time:
-
Permalink:
Wenlab/napari-worm-neuron-annotator@152bc8f799981f030ef57597c86dcb0190183424 -
Branch / Tag:
refs/tags/v0.4.3 - Owner: https://github.com/Wenlab
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@152bc8f799981f030ef57597c86dcb0190183424 -
Trigger Event:
release
-
Statement type:
File details
Details for the file napari_worm_neuron_annotator-0.4.3-py3-none-any.whl.
File metadata
- Download URL: napari_worm_neuron_annotator-0.4.3-py3-none-any.whl
- Upload date:
- Size: 120.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
acc0832c27a92137bd55c00ac6d764c6aef478d5ffc3653bd1ef118d09f2d354
|
|
| MD5 |
f0127bb1aafca2661ce42adfeb3e4ada
|
|
| BLAKE2b-256 |
17370e634171299f8d9ecc3007aa0c8f2ee52ad165160a240415c99ae8262662
|
Provenance
The following attestation bundles were made for napari_worm_neuron_annotator-0.4.3-py3-none-any.whl:
Publisher:
release.yml on Wenlab/napari-worm-neuron-annotator
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
napari_worm_neuron_annotator-0.4.3-py3-none-any.whl -
Subject digest:
acc0832c27a92137bd55c00ac6d764c6aef478d5ffc3653bd1ef118d09f2d354 - Sigstore transparency entry: 2748115816
- Sigstore integration time:
-
Permalink:
Wenlab/napari-worm-neuron-annotator@152bc8f799981f030ef57597c86dcb0190183424 -
Branch / Tag:
refs/tags/v0.4.3 - Owner: https://github.com/Wenlab
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@152bc8f799981f030ef57597c86dcb0190183424 -
Trigger Event:
release
-
Statement type: