Skip to content

label tool rework and vision bugs fix - #161

Draft
SimoneMartino98 wants to merge 20 commits into
GMPavanLab:mainfrom
SimoneMartino98:vision/label-tool-rework
Draft

label tool rework and vision bugs fix#161
SimoneMartino98 wants to merge 20 commits into
GMPavanLab:mainfrom
SimoneMartino98:vision/label-tool-rework

Conversation

@SimoneMartino98

Copy link
Copy Markdown
Collaborator

Hi all, I’m preparing this for the next dynsight hands-on (11 September 2026). We already knew that vision and label_tools had some issues working together, so in this PR I’m fixing everything.

The label_tool GUI has been rewritten from scratch, and its output is now
directly usable by VisionInstance without any manual fix-up.

What changed

  • New canvas-based GUI: boxes can be selected, moved, resized and deleted
    (not only "clear last/all"); zoom and pan; drag & drop; video import with
    frame extraction; progress bars for every long operation.
  • Datasets are written to disk by the backend, with an absolute path in
    dataset.yaml, so set_training_dataset() accepts them as they are.
  • Class IDs are stable: they follow the order of the label list instead of
    the order in which annotations happen to be met during the export.
  • Sessions are explicit: labels and boxes are saved only when asked, to a
    file chosen by the user, and can be loaded back. Quitting with unsaved
    changes asks first.
  • No new dependencies: standard-library HTTP server plus vanilla JS (the JSZip
    CDN script is gone, so the tool also works offline).

Bugs fixed

  • Reloading the page no longer shuts the server down.
  • dataset.yaml no longer needs to be edited by hand after the export.
  • Labels without annotations no longer disappear from the exported classes.
  • track_xyz now accepts .xyz files without the atom name column (closes track_xyz is not working with name less xyz formats. #150).

SimoneMartino98 and others added 9 commits July 16, 2026 15:30
- Backend: stdlib HTTP server with JSON API; session autosave on disk,
  image/video upload (frame extraction via OpenCV), dataset export and
  synthetic dataset generation written directly to disk with absolute
  paths in dataset.yaml, fully compatible with VisionInstance.
- Stable YOLO class IDs from the label list order; every image gets a
  label file and every class appears in dataset.yaml.
- New canvas-based frontend: box draw/select/move/resize/delete, zoom
  and pan, video import, drag & drop, export/synthesize dialogs, no CDN
  dependencies; page reload no longer kills the server.
- Add pytest coverage for workspace, export, synthesize and HTTP API.
- Update docs and screenshot.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Progress bars for every long operation: image uploads (per-file),
  video upload (byte-level) and frame extraction, dataset export and
  synthesis (server-side progress polled via /api/progress).
- Replace the text brand with the dynsight logo in the top bar.
- Sessions are no longer saved to disk automatically: edits are only
  mirrored to server memory (/api/sync). Saving requires an explicit
  file path via the Save session dialog; Load restores a saved file;
  quitting with unsaved changes asks whether to save first.
- Fix sidebar panel collapse with long image lists; topbar wraps on
  narrow windows.
- Update tests and docs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- If a project-local ./.venv exists, its tools are used automatically
  (no activation needed); otherwise the active environment (e.g.
  conda) is used.
- just dev autodetects the installer: uv into ./.venv when available,
  pip inside an active conda env, plain pip as fallback; on macOS it
  also clears the hidden flag on .pth files, which Python >= 3.11
  silently skips.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- lens.py: numba prange loops are not understood by mypy; silence the
  false-positive attr-defined errors.
- vision.py: newer ultralytics annotates predict() with a wider return
  union; cast to list[Results] (always true without stream=True).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- The check recipe used 'trap error=1 ERR', which bash 3.2 (the macOS
  default shell) never runs for a failing subshell: a failing step left
  the exit code at 0, so broken checks looked green. Failures are now
  collected explicitly and the failing steps are listed.
- Import the package from ./src via PYTHONPATH. The editable install
  relies on a .pth file that Python >= 3.11 skips when it carries the
  macOS 'hidden' flag, which some setups keep re-applying to the venv.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
just dev now installs into whichever project venv exists instead of
always assuming ./.venv, so a venv named ./venv is not silently
bypassed (and recreated as ./.venv). On macOS some setups keep marking
dot-directories as hidden, which makes Python skip the .pth file of the
editable install; a venv named ./venv avoids that entirely.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- ruff 0.16 promoted new rules that 'select = ALL' picks up: ignore
  CPY001 (the licence lives in LICENSE, not in every file header) and
  PLR0917 (positional-argument counterpart of the already ignored
  PLR0913), and move None to the end of the unions flagged by RUF036.
- mypy skips dot-directories, so a project venv named ./venv was being
  type checked; exclude it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
track_xyz always read the input as '<name> <x> <y> <z>', so files
written as '<x> <y> <z>' (a layout its own docstring documents) ended
up with no positions at all and were rejected as malformed. The column
layout is now taken from the first atom line of the file.

The name column is also always written to the output: without it the
resulting file was not a readable .xyz, and reading it back shifted the
coordinates by one column. Objects with no name in the input get the
placeholder name 'C'.

Closes GMPavanLab#150

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@SimoneMartino98 SimoneMartino98 self-assigned this Aug 27, 2026
@SimoneMartino98 SimoneMartino98 added bug Something isn't working enhancement New feature or request labels Aug 27, 2026
- Backend: stdlib HTTP server with JSON API; session autosave on disk,
  image/video upload (frame extraction via OpenCV), dataset export and
  synthetic dataset generation written directly to disk with absolute
  paths in dataset.yaml, fully compatible with VisionInstance.
- Stable YOLO class IDs from the label list order; every image gets a
  label file and every class appears in dataset.yaml.
- New canvas-based frontend: box draw/select/move/resize/delete, zoom
  and pan, video import, drag & drop, export/synthesize dialogs, no CDN
  dependencies; page reload no longer kills the server.
- Add pytest coverage for workspace, export, synthesize and HTTP API.
- Update docs and screenshot.
- Progress bars for every long operation: image uploads (per-file),
  video upload (byte-level) and frame extraction, dataset export and
  synthesis (server-side progress polled via /api/progress).
- Replace the text brand with the dynsight logo in the top bar.
- Sessions are no longer saved to disk automatically: edits are only
  mirrored to server memory (/api/sync). Saving requires an explicit
  file path via the Save session dialog; Load restores a saved file;
  quitting with unsaved changes asks whether to save first.
- Fix sidebar panel collapse with long image lists; topbar wraps on
  narrow windows.
- Update tests and docs.
- If a project-local ./.venv exists, its tools are used automatically
  (no activation needed); otherwise the active environment (e.g.
  conda) is used.
- just dev autodetects the installer: uv into ./.venv when available,
  pip inside an active conda env, plain pip as fallback; on macOS it
  also clears the hidden flag on .pth files, which Python >= 3.11
  silently skips.
- lens.py: numba prange loops are not understood by mypy; silence the
  false-positive attr-defined errors.
- vision.py: newer ultralytics annotates predict() with a wider return
  union; cast to list[Results] (always true without stream=True).
- The check recipe used 'trap error=1 ERR', which bash 3.2 (the macOS
  default shell) never runs for a failing subshell: a failing step left
  the exit code at 0, so broken checks looked green. Failures are now
  collected explicitly and the failing steps are listed.
- Import the package from ./src via PYTHONPATH. The editable install
  relies on a .pth file that Python >= 3.11 skips when it carries the
  macOS 'hidden' flag, which some setups keep re-applying to the venv.
just dev now installs into whichever project venv exists instead of
always assuming ./.venv, so a venv named ./venv is not silently
bypassed (and recreated as ./.venv). On macOS some setups keep marking
dot-directories as hidden, which makes Python skip the .pth file of the
editable install; a venv named ./venv avoids that entirely.
- ruff 0.16 promoted new rules that 'select = ALL' picks up: ignore
  CPY001 (the licence lives in LICENSE, not in every file header) and
  PLR0917 (positional-argument counterpart of the already ignored
  PLR0913), and move None to the end of the unions flagged by RUF036.
- mypy skips dot-directories, so a project venv named ./venv was being
  type checked; exclude it.
track_xyz always read the input as '<name> <x> <y> <z>', so files
written as '<x> <y> <z>' (a layout its own docstring documents) ended
up with no positions at all and were rejected as malformed. The column
layout is now taken from the first atom line of the file.

The name column is also always written to the output: without it the
resulting file was not a readable .xyz, and reading it back shifted the
coordinates by one column. Objects with no name in the input get the
placeholder name 'C'.

Closes GMPavanLab#150
# Number of columns of an atom line without the atom name.
_COORDS_ONLY = 3
# Name given to objects read from a file without the name column.
_DEFAULT_NAME = "C"

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better to use another letter

with the tracked particle ID.
The output file lists the tracked particle ID at the end of each
line. Objects read from a file without the name column are written
with the placeholder name ``C``, so that the output is always a

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better to change the default letter.

All four surfaced while writing hands-on tutorials against the public API.
Regression tests for each are in tests/test_regressions.py.

- orientational_order_param() and velocity_alignment() looped over the
  full universe trajectory while the neighbour list only covered the
  slice, so they raised IndexError on any Trj built with with_slice().
  Both now take a trajslice argument, which Trj forwards, and a
  mismatched neighbour list raises a clear ValueError instead.

- spatialaverage() indexed the descriptor with the trajectory's frame
  count. Descriptors defined on pairs of frames (LENS, timeSOAP) are one
  frame shorter, so passing the unsliced Trj gave a bare IndexError from
  inside a worker process. The frame counts are now checked up front.

- compute_lens() inferred a box from the coordinate bounding box when
  the universe has none. A planar system - anything coming out of
  dynsight.vision - has zero extent along z, and the zero-length box
  side made the cell-list construction divide by zero. Every side is now
  padded by r_cut, as list_neighbours_along_trajectory already did.

- track_xyz() returned a Trj built on a file whose frames may hold
  different numbers of objects, which is not a readable trajectory: it
  raised EOFError on the first descriptor. It now returns None, logging
  the min and max object count, when no trajectory exists. The output
  file is still written in both cases.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

track_xyz is not working with name less xyz formats.

1 participant