arrayview 0.26.2__tar.gz → 0.27.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {arrayview-0.26.2 → arrayview-0.27.0}/.mex/AGENTS.md +1 -1
- {arrayview-0.26.2 → arrayview-0.27.0}/.mex/ROUTER.md +1 -1
- {arrayview-0.26.2 → arrayview-0.27.0}/.mex/SETUP.md +1 -1
- {arrayview-0.26.2 → arrayview-0.27.0}/.mex/SYNC.md +1 -1
- {arrayview-0.26.2 → arrayview-0.27.0}/.mex/context/conventions.md +1 -1
- {arrayview-0.26.2 → arrayview-0.27.0}/.mex/context/decisions.md +1 -1
- {arrayview-0.26.2 → arrayview-0.27.0}/.mex/context/lifecycle.md +1 -1
- {arrayview-0.26.2 → arrayview-0.27.0}/.mex/context/project-state.md +4 -3
- {arrayview-0.26.2 → arrayview-0.27.0}/.mex/context/render-pipeline.md +1 -1
- {arrayview-0.26.2 → arrayview-0.27.0}/.mex/context/setup.md +2 -2
- {arrayview-0.26.2 → arrayview-0.27.0}/.mex/context/stack.md +1 -1
- {arrayview-0.26.2 → arrayview-0.27.0}/.mex/patterns/INDEX.md +2 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.mex/patterns/README.md +1 -1
- {arrayview-0.26.2 → arrayview-0.27.0}/.mex/patterns/add-server-endpoint.md +1 -1
- {arrayview-0.26.2 → arrayview-0.27.0}/.mex/patterns/animation-verify.md +1 -1
- {arrayview-0.26.2 → arrayview-0.27.0}/.mex/patterns/debug-render.md +1 -1
- {arrayview-0.26.2 → arrayview-0.27.0}/.mex/patterns/debug-vscode-extension-python.md +1 -1
- {arrayview-0.26.2 → arrayview-0.27.0}/.mex/patterns/extend-compare-mode.md +1 -1
- {arrayview-0.26.2 → arrayview-0.27.0}/.mex/patterns/extract-server-route-module.md +1 -1
- {arrayview-0.26.2 → arrayview-0.27.0}/.mex/patterns/frontend-change.md +1 -1
- {arrayview-0.26.2 → arrayview-0.27.0}/PKG-INFO +7 -7
- arrayview-0.27.0/README.md +21 -0
- arrayview-0.27.0/docs/launch-routing-refactor.md +167 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/docs/measurement.md +7 -3
- arrayview-0.27.0/plans/roi-analysis-requirements.md +126 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/pyproject.toml +1 -1
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_analysis.py +19 -4
- arrayview-0.27.0/src/arrayview/_launch_plan.py +285 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_launcher.py +133 -55
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_platform.py +22 -9
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_routes_analysis.py +442 -3
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_server.py +1 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_stdio_server.py +2 -1
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_viewer.html +3065 -576
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_vscode_browser.py +16 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_vscode_extension.py +1 -1
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_vscode_signal.py +31 -57
- arrayview-0.27.0/src/arrayview/arrayview-opener.vsix +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/tests/test_api.py +623 -5
- {arrayview-0.26.2 → arrayview-0.27.0}/tests/test_browser.py +1190 -38
- {arrayview-0.26.2 → arrayview-0.27.0}/tests/test_cli.py +62 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/tests/test_interactions.py +5 -5
- arrayview-0.27.0/tests/test_launch_plan.py +239 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/tests/test_lifecycle_contract.py +48 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/uv.lock +1 -1
- {arrayview-0.26.2 → arrayview-0.27.0}/vscode-extension/extension.js +121 -71
- {arrayview-0.26.2 → arrayview-0.27.0}/vscode-extension/package.json +1 -1
- arrayview-0.26.2/README.md +0 -21
- arrayview-0.26.2/src/arrayview/arrayview-opener.vsix +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.agents/skills/frontend-designer/SKILL.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.agents/skills/invocation-consistency/SKILL.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.agents/skills/modes-consistency/SKILL.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.agents/skills/playwright-cli/SKILL.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.agents/skills/playwright-cli/references/element-attributes.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.agents/skills/playwright-cli/references/playwright-tests.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.agents/skills/playwright-cli/references/request-mocking.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.agents/skills/playwright-cli/references/running-code.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.agents/skills/playwright-cli/references/session-management.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.agents/skills/playwright-cli/references/storage-state.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.agents/skills/playwright-cli/references/test-generation.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.agents/skills/playwright-cli/references/tracing.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.agents/skills/playwright-cli/references/video-recording.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.agents/skills/todo-workflow/SKILL.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.agents/skills/ui-consistency-audit/SKILL.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.agents/skills/viewer-ui-checklist/SKILL.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.agents/skills/visual-bug-fixing/SKILL.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.github/copilot-instructions.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.github/workflows/docs.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.github/workflows/python-publish.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.gitignore +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.ignore +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.mex/context/architecture.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.mex/context/frontend.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.mex/patterns/add-file-format.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.mex/setup.sh +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.mex/sync.sh +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.opencode/opencode.json +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-06T18-46-49-737Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-06T18-48-21-979Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-06T18-51-35-665Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-06T19-07-01-393Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-06T19-14-37-969Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-06T19-21-30-940Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-06T19-23-08-126Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-06T19-29-33-155Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-06T19-31-25-336Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-06T19-31-53-789Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-06T19-39-12-257Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-06T19-39-16-449Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-06T20-15-25-513Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-06T20-25-13-179Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-06T20-39-01-435Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-06T21-01-27-659Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-06T21-01-41-283Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-06T21-03-00-625Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-06T21-04-12-887Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-06T21-33-39-044Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-06T21-38-01-530Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-06T21-45-20-383Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-06T21-55-11-545Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-06T21-56-03-307Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-06T21-56-35-733Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-06T21-57-12-181Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-06T21-57-37-748Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-06T21-58-13-679Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-06T22-37-23-895Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-07T00-39-18-637Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-07T01-41-46-243Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-07T04-31-48-472Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-07T12-14-15-632Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-07T12-14-47-582Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-07T12-16-23-471Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-07T12-17-10-247Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-07T12-18-24-707Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-07T12-20-06-164Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-07T12-20-28-342Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-07T12-21-54-962Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-07T12-22-34-666Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-07T12-23-11-336Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-07T12-23-36-260Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-07T12-24-09-267Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-07T12-24-35-434Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-07T12-25-57-010Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-07T12-34-48-823Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-07T12-46-46-468Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-07T12-48-17-930Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-07T12-49-26-400Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-07T12-50-31-563Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/page-2026-05-07T12-56-45-568Z.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.playwright-cli/theme-dark.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.python-version +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/.vscode/settings.json +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/AGENTS.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/CONTRIBUTING.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/DESIGN.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/LICENSE +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/docs/comparing.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/docs/configuration.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/docs/display.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/docs/index.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/docs/lifecycle.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/docs/loading.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/docs/logo.png +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/docs/remote.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/docs/stylesheets/extra.css +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/docs/viewing.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/matlab/arrayview.m +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/mkdocs.yml +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/plans/2026-04-14-immersive-animation.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/plans/2026-05-07-unified-colormap-picker.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/plans/arrayview_tool_menu_fix_prompt.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/plans/arrayview_tool_menu_implementation_plan.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/plans/egg-placement-mockup.html +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/plans/refactoring_plan.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/plans/webview/LOG.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/scripts/demo.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/scripts/release.sh +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/ARCHITECTURE.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/__init__.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/__main__.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_app.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_codex_open.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_config.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_diff.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_icon.png +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_imaging.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_io.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_lifecycle.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_overlays.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_render.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_routes_export.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_routes_loading.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_routes_persistence.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_routes_preload.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_routes_query.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_routes_rendering.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_routes_segmentation.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_routes_state.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_routes_vectorfield.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_routes_websocket.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_segmentation.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_session.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_shell.html +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_synthetic_mri.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_torch.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_vectorfield.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_vscode.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/_vscode_shm.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/src/arrayview/gsap.min.js +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/tests/capture_v_animation.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/tests/conftest.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/tests/lifecycle_matrix.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/tests/make_vectorfield_test_arrays.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/tests/test_backend_shared.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/tests/test_colorbar_hover_highlight.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/tests/test_command_reachability.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/tests/test_config.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/tests/test_cross_mode_parametrized.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/tests/test_io.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/tests/test_large_arrays.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/tests/test_loading_server.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/tests/test_mode_consistency.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/tests/test_mode_entry_batching.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/tests/test_mode_matrix.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/tests/test_mode_roundtrip.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/tests/test_nifti_meta.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/tests/test_rgb_pixel_art.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/tests/test_stdio_server.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/tests/test_torch.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/tests/test_view_component_integration.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/tests/test_view_component_unit.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/tests/ui_audit.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/tests/v_anim_frames/.gitkeep +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/tests/visual_smoke.py +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/vscode-extension/AGENTS.md +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/vscode-extension/LICENSE +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/vscode-extension/lifecycle_helpers.js +0 -0
- {arrayview-0.26.2 → arrayview-0.27.0}/vscode-extension/test_lifecycle_helpers.js +0 -0
|
@@ -24,7 +24,7 @@ edges:
|
|
|
24
24
|
condition: when starting a task — check the pattern index for a matching pattern file
|
|
25
25
|
- target: ../DESIGN.md
|
|
26
26
|
condition: when the task touches design philosophy — new features, UI changes, mode additions, or interaction model decisions
|
|
27
|
-
last_updated: 2026-06-
|
|
27
|
+
last_updated: 2026-06-19
|
|
28
28
|
---
|
|
29
29
|
|
|
30
30
|
# arrayview — Router
|
|
@@ -18,7 +18,7 @@ edges:
|
|
|
18
18
|
condition: when applying frontend conventions (section separators, reconcilers, command registry)
|
|
19
19
|
- target: context/render-pipeline.md
|
|
20
20
|
condition: when applying render pipeline conventions (pipeline order, cache patterns, LUT usage)
|
|
21
|
-
last_updated: 2026-
|
|
21
|
+
last_updated: 2026-06-19
|
|
22
22
|
---
|
|
23
23
|
|
|
24
24
|
# Conventions
|
|
@@ -14,7 +14,7 @@ edges:
|
|
|
14
14
|
condition: when a decision relates to technology choice
|
|
15
15
|
- target: context/frontend.md
|
|
16
16
|
condition: when a decision relates to the frontend architecture or viewer modes
|
|
17
|
-
last_updated: 2026-
|
|
17
|
+
last_updated: 2026-06-19
|
|
18
18
|
---
|
|
19
19
|
|
|
20
20
|
# Decisions
|
|
@@ -16,7 +16,7 @@ edges:
|
|
|
16
16
|
condition: when component boundaries or display routing need broader context
|
|
17
17
|
- target: context/stack.md
|
|
18
18
|
condition: when VS Code, FastAPI, WebSocket, or packaging details are needed
|
|
19
|
-
last_updated: 2026-06-
|
|
19
|
+
last_updated: 2026-06-19
|
|
20
20
|
---
|
|
21
21
|
|
|
22
22
|
# Lifecycle
|
|
@@ -25,8 +25,9 @@ last_updated: 2026-06-05
|
|
|
25
25
|
- Colormap picker: `c` opens an expanded colorbar-island grid without changing the colormap; subsequent `c` taps cycle, hover/hjkl/arrows live-preview, Enter/click commits, Esc cancels, and auto-dismiss pauses while hovered
|
|
26
26
|
- Cold-start loading spinner in VS Code and native shell
|
|
27
27
|
- Tool menu (`/` menu) supports multi-select where allowed: spacebar toggles tools, Enter applies selection. Mutual exclusion enforced (ROI ↔ Segmentation, and overlay/vectorfield ↔ everything else). Cursor indicator shows focused tile via yellow background + left accent bar
|
|
28
|
-
- Dynamic island renders sections for
|
|
29
|
-
- ROI mode
|
|
28
|
+
- Dynamic island renders sections for active plugins such as qMRI and segmentation, replacing the old single-plugin priority chain
|
|
29
|
+
- ROI mode is a lightweight measurement tool: `Shift+R` shows/hides session ROIs, defaults to true circles, uses slim colorbar controls for shape/stats/hide/clear, and manages stats/rename/delete/export from the ROI manager modal
|
|
30
|
+
- ROI mode works alongside qMRI: drawing on any pane mirrors the ROI to all panes in real-time via per-pane overlay canvases; stats are fetched per visible parameter map and shown in the ROI manager
|
|
30
31
|
- qMRI map toggle (`_islandToggleQmriMap`) fade animation now covers dimbar and array-name in addition to panes and colorbars
|
|
31
32
|
- Segmentation menu shares the ROI layout (yellow accent, magnifier action icon, common `#export-overlay` modal). Pre-activation shows a pulsing "nnInteractive · connecting" row that morphs into the normal shape toolbar once `/seg/activate` resolves
|
|
32
33
|
- Overlays are a plugin tile (`OV`): per-overlay row with colour swatch, editable label, eye toggle, × delete; shared opacity slider; `+ add overlay` opens a filesystem picker rooted at the launched file's directory
|
|
@@ -44,7 +45,7 @@ last_updated: 2026-06-05
|
|
|
44
45
|
- Crossfade animation added to rotate/transpose transitions
|
|
45
46
|
- `--version` flag and version string in help overlay
|
|
46
47
|
- In-viewer array picker for multi-array `.mat` and `.npz` files
|
|
47
|
-
- ROI
|
|
48
|
+
- ROI manager modal for qMRI canvases (per-parameter-map stats rows, CSV export, label-mask export)
|
|
48
49
|
- Invocation lifecycle contract defined and hardened: local VS Code CLI launches use transient daemon shutdown, remote/tunnel launches remain persistent only where transport requires it, URL webview backend checks run in the extension host against `/ping`, URL panel disposal releases all sessions encoded in the viewer URL, quick viewer connect/disconnect races detected by monotonic connection counter, ambiguous multi-window tunnel routing fails closed, stale viewer SID retry state cleared on WebSocket disconnect, bundled opener extension rebuilt as v0.14.12
|
|
49
50
|
- Hover info wrong values fixed
|
|
50
51
|
- Native launcher startup restored
|
|
@@ -20,7 +20,7 @@ edges:
|
|
|
20
20
|
condition: when writing new render functions or extending the pipeline
|
|
21
21
|
- target: patterns/debug-render.md
|
|
22
22
|
condition: when a render produces wrong output or the wrong cache is hit
|
|
23
|
-
last_updated: 2026-
|
|
23
|
+
last_updated: 2026-06-19
|
|
24
24
|
---
|
|
25
25
|
|
|
26
26
|
# Render Pipeline
|
|
@@ -13,7 +13,7 @@ edges:
|
|
|
13
13
|
condition: when specific technology versions or library details are needed
|
|
14
14
|
- target: context/architecture.md
|
|
15
15
|
condition: when understanding how components connect during setup
|
|
16
|
-
last_updated: 2026-
|
|
16
|
+
last_updated: 2026-06-19
|
|
17
17
|
---
|
|
18
18
|
|
|
19
19
|
# Setup
|
|
@@ -62,7 +62,7 @@ No `.env` file is needed. All env vars are optional overrides; the server runs w
|
|
|
62
62
|
|
|
63
63
|
**Port already in use:** The server binds to a random free port by default. If you see a port conflict, check for orphan `uvicorn` processes: `lsof -i :<port>`. Kill with `kill -9 <PID>`. The server is supposed to shut down automatically when all viewer windows close.
|
|
64
64
|
|
|
65
|
-
**VS Code extension not loading:** Signal-file IPC can fail if the extension version is mismatched. Check `_VSCODE_EXT_VERSION` in `
|
|
65
|
+
**VS Code extension not loading:** Signal-file IPC can fail if the extension version is mismatched. Check `_VSCODE_EXT_VERSION` in `_vscode_extension.py` matches the installed extension.
|
|
66
66
|
|
|
67
67
|
**Playwright tests fail on CI:** Ensure `uv run playwright install chromium` has been run. Browser tests require a display; on headless servers they need `DISPLAY=:0` or Xvfb.
|
|
68
68
|
|
|
@@ -14,7 +14,7 @@ edges:
|
|
|
14
14
|
condition: when understanding how to use a technology in this codebase
|
|
15
15
|
- target: context/architecture.md
|
|
16
16
|
condition: when understanding how a library fits into the overall system
|
|
17
|
-
last_updated: 2026-
|
|
17
|
+
last_updated: 2026-06-19
|
|
18
18
|
---
|
|
19
19
|
|
|
20
20
|
# Stack
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Pattern Index
|
|
2
2
|
|
|
3
|
+
Last reviewed: 2026-06-19
|
|
4
|
+
|
|
3
5
|
Lookup table for all pattern files in this directory. Check here before starting any task — if a pattern exists, follow it.
|
|
4
6
|
|
|
5
7
|
<!-- This file is populated during setup (Pass 2) and updated whenever patterns are added.
|
|
@@ -16,7 +16,7 @@ edges:
|
|
|
16
16
|
condition: when the endpoint triggers a render (slice, mosaic, projection)
|
|
17
17
|
- target: context/conventions.md
|
|
18
18
|
condition: for lazy import rules and Verify Checklist
|
|
19
|
-
last_updated: 2026-
|
|
19
|
+
last_updated: 2026-06-19
|
|
20
20
|
---
|
|
21
21
|
|
|
22
22
|
# Add Server Endpoint
|
|
@@ -22,7 +22,7 @@ edges:
|
|
|
22
22
|
condition: only after Step 1 points to `_viewer.html` rather than the Python pipeline
|
|
23
23
|
- target: context/conventions.md
|
|
24
24
|
condition: for the Verify Checklist after fixing
|
|
25
|
-
last_updated: 2026-
|
|
25
|
+
last_updated: 2026-06-19
|
|
26
26
|
---
|
|
27
27
|
|
|
28
28
|
# Debug Render
|
|
@@ -13,7 +13,7 @@ edges:
|
|
|
13
13
|
condition: when the work is primarily a local `_viewer.html` edit
|
|
14
14
|
- target: context/render-pipeline.md
|
|
15
15
|
condition: when compare changes require backend render or diff parameter changes
|
|
16
|
-
last_updated: 2026-
|
|
16
|
+
last_updated: 2026-06-19
|
|
17
17
|
---
|
|
18
18
|
|
|
19
19
|
# Extend Compare Mode
|
|
@@ -11,7 +11,7 @@ edges:
|
|
|
11
11
|
condition: when deciding whether `_server.py` should keep or delegate a route cluster
|
|
12
12
|
- target: context/project-state.md
|
|
13
13
|
condition: when the extraction changes the active architecture workstream
|
|
14
|
-
last_updated: 2026-
|
|
14
|
+
last_updated: 2026-06-19
|
|
15
15
|
---
|
|
16
16
|
|
|
17
17
|
# Extract Server Route Module
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: arrayview
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.27.0
|
|
4
4
|
Summary: Fast multi-dimensional array viewer
|
|
5
5
|
Project-URL: Home, https://github.com/oscarvanderheide/arrayview
|
|
6
6
|
Project-URL: Source, https://github.com/oscarvanderheide/arrayview
|
|
@@ -38,20 +38,20 @@ Description-Content-Type: text/markdown
|
|
|
38
38
|
|
|
39
39
|
_This is my array viewer. There are many like it, but this one is mine._
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
through slices of multi-dimensional arrays. Feature rich with a modern, minimal UI that only shows what needs to be shown.
|
|
41
|
+
Arrayview lets you scroll through multi-dimensional arrays.
|
|
43
42
|
|
|
44
|
-
|
|
43
|
+
Open it from the shell, from Python, Julia, or Matlab, or inside a Jupyter notebook. Use it locally or over SSH.
|
|
45
44
|
|
|
46
|
-
VS Code
|
|
45
|
+
If you work in VS Code, you can open arrays directly from the explorer; with Remote SSH, it works the same way.
|
|
47
46
|
|
|
48
|
-
|
|
47
|
+
It is meant to feel simple but there's more to it than meets the eye.
|
|
49
48
|
|
|
50
49
|
Curious? Give it a try with
|
|
51
50
|
```bash
|
|
52
51
|
uvx arrayview your_array.npy
|
|
53
52
|
```
|
|
54
|
-
|
|
53
|
+
|
|
55
54
|
|
|
56
55
|
Check the [docs](https://oscarvanderheide.github.io/arrayview/) to learn more.
|
|
57
56
|
|
|
57
|
+
**Warning**: Arrayview is still under active development. Things may break or change without warning.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# <img src="docs/logo.png" height="36"> arrayview
|
|
2
|
+
|
|
3
|
+
_This is my array viewer. There are many like it, but this one is mine._
|
|
4
|
+
|
|
5
|
+
Arrayview lets you scroll through multi-dimensional arrays.
|
|
6
|
+
|
|
7
|
+
Open it from the shell, from Python, Julia, or Matlab, or inside a Jupyter notebook. Use it locally or over SSH.
|
|
8
|
+
|
|
9
|
+
If you work in VS Code, you can open arrays directly from the explorer; with Remote SSH, it works the same way.
|
|
10
|
+
|
|
11
|
+
It is meant to feel simple but there's more to it than meets the eye.
|
|
12
|
+
|
|
13
|
+
Curious? Give it a try with
|
|
14
|
+
```bash
|
|
15
|
+
uvx arrayview your_array.npy
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
Check the [docs](https://oscarvanderheide.github.io/arrayview/) to learn more.
|
|
20
|
+
|
|
21
|
+
**Warning**: Arrayview is still under active development. Things may break or change without warning.
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# Launch Routing Refactor
|
|
2
|
+
|
|
3
|
+
ArrayView currently opens displays through several partially overlapping paths:
|
|
4
|
+
CLI, `view()`, Jupyter, Julia, VS Code local, VS Code tunnel, SSH, native
|
|
5
|
+
pywebview, browser fallback, and stdio/direct webview mode. The same policy is
|
|
6
|
+
encoded in multiple places, so fixes in one path can leave another path broken.
|
|
7
|
+
|
|
8
|
+
This refactor makes launch routing explicit, shared, and inspectable.
|
|
9
|
+
|
|
10
|
+
## Problem
|
|
11
|
+
|
|
12
|
+
The brittle behavior comes from policy being split across:
|
|
13
|
+
|
|
14
|
+
- environment detection in `_platform.py`
|
|
15
|
+
- CLI planning in `_launcher.py`
|
|
16
|
+
- Python `view()` planning in `_launcher.py`
|
|
17
|
+
- VS Code signal/direct-mode fallback in `_vscode_browser.py` and `_vscode_signal.py`
|
|
18
|
+
- separate HTTP and stdio session registration paths
|
|
19
|
+
|
|
20
|
+
Symptoms seen recently:
|
|
21
|
+
|
|
22
|
+
- CLI diagnose says native pywebview should open, but runtime falls back to a browser.
|
|
23
|
+
- Linux native detection allows GTK systems while native launch forced Qt.
|
|
24
|
+
- `view()` and CLI had different native readiness checks.
|
|
25
|
+
- Existing-server remote behavior can accidentally switch from registered URL mode to direct stdio mode.
|
|
26
|
+
|
|
27
|
+
## Target Model
|
|
28
|
+
|
|
29
|
+
Create a single launch plan used by both CLI and `view()`.
|
|
30
|
+
|
|
31
|
+
The plan should be data-only:
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
Invocation = "cli" | "python" | "jupyter" | "julia" | "stdio" | "codex"
|
|
35
|
+
Environment = "terminal" | "vscode_local" | "vscode_remote" | "ssh" | "jupyter" | "julia"
|
|
36
|
+
Transport = "http" | "stdio_file" | "stdio_shm" | "none"
|
|
37
|
+
ServerOwner = "existing" | "spawned_daemon" | "in_process" | "persistent" | "external"
|
|
38
|
+
Display = "native" | "browser" | "vscode" | "inline" | "none"
|
|
39
|
+
Registration = "http_load" | "daemon_startup" | "in_process_session" | "stdio_register" | "relay"
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Executors may perform work, but should not invent policy. Browser fallback,
|
|
43
|
+
VS Code direct mode, native readiness, and remote behavior must be selected by
|
|
44
|
+
the plan.
|
|
45
|
+
|
|
46
|
+
## Phase 1: Snapshot And Diagnose
|
|
47
|
+
|
|
48
|
+
Add a launch environment snapshot:
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
snapshot_launch_environment(port, invocation, requested_window)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
It should capture:
|
|
55
|
+
|
|
56
|
+
- platform
|
|
57
|
+
- relevant environment variables
|
|
58
|
+
- config default
|
|
59
|
+
- native backend: `qt`, `gtk`, `""`, or `None`
|
|
60
|
+
- port busy / ArrayView server alive / server PID / hostname
|
|
61
|
+
- VS Code local vs remote/tunnel
|
|
62
|
+
- SSH state
|
|
63
|
+
- Jupyter and Julia state
|
|
64
|
+
|
|
65
|
+
`arrayview --diagnose` must print the same snapshot and plan used by real launch.
|
|
66
|
+
|
|
67
|
+
## Phase 2: Shared Planner
|
|
68
|
+
|
|
69
|
+
Add:
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
plan_launch(invocation, request, env) -> LaunchPlan
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The planner decides:
|
|
76
|
+
|
|
77
|
+
- transport: HTTP, stdio file, stdio SHM, or none
|
|
78
|
+
- display: native, browser, vscode, inline, none
|
|
79
|
+
- server owner: existing, spawned daemon, in-process, persistent, external
|
|
80
|
+
- registration: HTTP load, daemon startup, in-process session, stdio register, relay
|
|
81
|
+
- fallback policy: whether fallback is allowed and where it goes
|
|
82
|
+
|
|
83
|
+
CLI and `view()` should both call this planner.
|
|
84
|
+
|
|
85
|
+
## Phase 3: Native Readiness
|
|
86
|
+
|
|
87
|
+
Use one native readiness primitive everywhere:
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
open_native_shell(...)
|
|
91
|
+
wait_native_ready(shell_socket=True, viewer_socket=True, process_alive=True)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Rules:
|
|
95
|
+
|
|
96
|
+
- process crash is native launch failure
|
|
97
|
+
- shell WebSocket means the native window is usable
|
|
98
|
+
- viewer WebSocket means the content loaded
|
|
99
|
+
- missing viewer WebSocket alone is not native failure
|
|
100
|
+
- browser fallback happens only after native process/shell failure
|
|
101
|
+
|
|
102
|
+
## Phase 4: Remote Existing-Server Fix
|
|
103
|
+
|
|
104
|
+
Separate these cases explicitly:
|
|
105
|
+
|
|
106
|
+
- `Display=vscode`, `Transport=http`: open the registered HTTP URL in VS Code
|
|
107
|
+
- `Display=vscode`, `Transport=stdio_file`: open direct stdio file session
|
|
108
|
+
|
|
109
|
+
Do not let `_open_browser(..., filepath=...)` implicitly switch an existing
|
|
110
|
+
registered URL into direct stdio mode.
|
|
111
|
+
|
|
112
|
+
## Phase 5: VS Code Direct Mode
|
|
113
|
+
|
|
114
|
+
Consolidate SHM/direct mode:
|
|
115
|
+
|
|
116
|
+
- one `_open_direct_via_shm()` implementation
|
|
117
|
+
- one SHM wait loop
|
|
118
|
+
- Julia remote, Python remote, and tunnel notebook paths call the same helper
|
|
119
|
+
|
|
120
|
+
Remove or clearly deprecate duplicate direct-mode helpers.
|
|
121
|
+
|
|
122
|
+
## Phase 6: Registration Semantics
|
|
123
|
+
|
|
124
|
+
Align HTTP `/load` and stdio registration:
|
|
125
|
+
|
|
126
|
+
- shared file/key selection behavior
|
|
127
|
+
- shared RAM guard behavior where possible
|
|
128
|
+
- shared RGB/vectorfield/overlay/compare semantics where possible
|
|
129
|
+
- documented differences where transports genuinely diverge
|
|
130
|
+
|
|
131
|
+
## Contract Tests
|
|
132
|
+
|
|
133
|
+
Prefer contract tests over broad visual smoke for launch routing:
|
|
134
|
+
|
|
135
|
+
- macOS terminal CLI native
|
|
136
|
+
- Linux Qt native
|
|
137
|
+
- Linux GTK native
|
|
138
|
+
- Linux no display browser fallback
|
|
139
|
+
- plain SSH guidance
|
|
140
|
+
- VS Code local tab
|
|
141
|
+
- VS Code remote direct stdio
|
|
142
|
+
- VS Code remote existing HTTP URL
|
|
143
|
+
- Jupyter inline
|
|
144
|
+
- VS Code remote notebook direct
|
|
145
|
+
- Julia subprocess/direct
|
|
146
|
+
|
|
147
|
+
Execution contracts:
|
|
148
|
+
|
|
149
|
+
- existing server native shell does not fall back only because viewer socket is late
|
|
150
|
+
- spawned daemon native shell does not fall back only because viewer socket is late
|
|
151
|
+
- `view()` native shell does not fall back only because viewer socket is late
|
|
152
|
+
- remote existing server opens registered URL, not direct stdio
|
|
153
|
+
- GTK-only Linux passes `gui="gtk"` to pywebview
|
|
154
|
+
|
|
155
|
+
## Migration Order
|
|
156
|
+
|
|
157
|
+
1. Add launch data model and environment snapshot without behavior changes.
|
|
158
|
+
2. Make `--diagnose` use the snapshot and shared planner.
|
|
159
|
+
3. Move CLI planning into `plan_launch()`.
|
|
160
|
+
4. Move `view()` planning into `plan_launch()`.
|
|
161
|
+
5. Unify native readiness for CLI and `view()`.
|
|
162
|
+
6. Fix remote existing-server URL/direct ambiguity.
|
|
163
|
+
7. Consolidate SHM direct mode.
|
|
164
|
+
8. Align HTTP and stdio registration semantics.
|
|
165
|
+
|
|
166
|
+
Each step should have focused invocation tests and should avoid unrelated UI or
|
|
167
|
+
rendering changes.
|
|
@@ -2,15 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
## ROI
|
|
4
4
|
|
|
5
|
-
`Shift+R`
|
|
5
|
+
`Shift+R` shows or hides ROI mode. Hiding ROI mode keeps the session's ROIs.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Draw on the canvas to measure a region. The default shape is a circle.
|
|
8
|
+
|
|
9
|
+
Shapes: circle, rectangle, freehand, flood fill. Switch via the colorbar controls.
|
|
8
10
|
|
|
9
11
|
For flood fill, `[` / `]` adjusts tolerance.
|
|
10
12
|
|
|
11
13
|
Click an existing ROI to select it. `Delete` / `Backspace` removes it.
|
|
12
14
|
|
|
13
|
-
`
|
|
15
|
+
`Stats` opens the ROI manager: rename/delete ROIs, adjust extent, export CSV, or export a label mask.
|
|
16
|
+
|
|
17
|
+
`N` exports the active ROI or segmentation mask as `.npy`.
|
|
14
18
|
|
|
15
19
|
## Ruler
|
|
16
20
|
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# ROI Analysis Requirements
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
ROI analysis should be a lightweight MRI/qMRI measurement tool. It should make
|
|
6
|
+
quick measurements easy, support repeated phantom-well measurements, and export
|
|
7
|
+
the resulting statistics and label masks.
|
|
8
|
+
|
|
9
|
+
ROI analysis is not a replacement for segmentation. Full white matter / gray
|
|
10
|
+
matter segmentation, voxel-label editing, automatic well detection, and mask
|
|
11
|
+
roundtripping belong outside ROI v1.
|
|
12
|
+
|
|
13
|
+
The current uncommitted ROI upgrade work is superseded by this document. Useful
|
|
14
|
+
backend or mask-export ideas may be reused, but the UI and interaction model
|
|
15
|
+
should restart from these requirements.
|
|
16
|
+
|
|
17
|
+
## Primary Use Cases
|
|
18
|
+
|
|
19
|
+
- Draw a quick circular or freehand ROI in in-vivo MRI data to inspect mean,
|
|
20
|
+
standard deviation, minimum, and maximum values.
|
|
21
|
+
- Draw multiple true circular ROIs inside cylindrical gel phantoms in transverse
|
|
22
|
+
slices and compare their measurements.
|
|
23
|
+
- In qMRI mode, draw one ROI and measure the same region across visible
|
|
24
|
+
parameter maps.
|
|
25
|
+
- Export ROI statistics as CSV.
|
|
26
|
+
- Export a single integer `.npy` label mask matching the source array shape.
|
|
27
|
+
|
|
28
|
+
## Interaction Model
|
|
29
|
+
|
|
30
|
+
- `Shift+R` toggles ROI mode visibility and interaction.
|
|
31
|
+
- When ROI mode turns off, ROI shapes, buttons, and hover affordances disappear.
|
|
32
|
+
- Turning ROI mode back on restores the session's existing ROI shapes.
|
|
33
|
+
- ROI geometry persists only for the current viewer session.
|
|
34
|
+
- The default ROI shape is a true circle.
|
|
35
|
+
- Additional ROI shapes are rectangle/square, freehand, and flood fill.
|
|
36
|
+
- Click an existing ROI to select it.
|
|
37
|
+
- `Delete` or `Backspace` deletes the selected ROI.
|
|
38
|
+
- No automatic or suggest-only circle detection in ROI v1.
|
|
39
|
+
|
|
40
|
+
## UI Model
|
|
41
|
+
|
|
42
|
+
- Everyday ROI controls live on a colorbar flip surface, not in the right tool
|
|
43
|
+
drawer.
|
|
44
|
+
- The colorbar flip should expose only the common drawing controls: shape
|
|
45
|
+
picker, stats popup button, and minimal clear/hide actions if needed.
|
|
46
|
+
- Statistics open in a popup/modal.
|
|
47
|
+
- The stats popup is the ROI manager for v1:
|
|
48
|
+
- one row per ROI by default
|
|
49
|
+
- qMRI rows expand or reveal per-map measurements
|
|
50
|
+
- rename ROI
|
|
51
|
+
- delete ROI
|
|
52
|
+
- export CSV
|
|
53
|
+
- export label mask `.npy`
|
|
54
|
+
- advanced dimensional extent controls
|
|
55
|
+
- Do not put rename/delete controls directly on the canvas in v1.
|
|
56
|
+
- Keep the canvas visually quiet; ROI outlines and labels are the only persistent
|
|
57
|
+
ROI marks while ROI mode is active.
|
|
58
|
+
|
|
59
|
+
## Statistics and Dimensional Scope
|
|
60
|
+
|
|
61
|
+
- Normal mode default: a new ROI applies only to the current displayed slice.
|
|
62
|
+
- qMRI default: a new ROI applies to the visible qMRI parameter maps.
|
|
63
|
+
- Advanced dimensional extent controls live in the stats popup per ROI.
|
|
64
|
+
- Advanced controls must use plain-language labels, not debug-like labels such
|
|
65
|
+
as `d2:135` or `d3:all`.
|
|
66
|
+
- Stats should report at least count, mean, standard deviation, minimum, and
|
|
67
|
+
maximum.
|
|
68
|
+
- CSV export should include ROI name, shape, dimensional extent, and qMRI map
|
|
69
|
+
labels where applicable.
|
|
70
|
+
|
|
71
|
+
## Masks and Segmentation Boundary
|
|
72
|
+
|
|
73
|
+
- ROI mask export writes one `.npy` integer label mask matching the source array
|
|
74
|
+
shape.
|
|
75
|
+
- Label `0` is background.
|
|
76
|
+
- ROI labels are `1..N` in list order.
|
|
77
|
+
- ROI mask loading and roundtrip editing are out of scope for ROI v1.
|
|
78
|
+
- Segmentation remains the tool for voxel-label editing, external segmentation
|
|
79
|
+
workflows, brush/lasso editing, and future mask roundtripping.
|
|
80
|
+
|
|
81
|
+
## Visibility and Color
|
|
82
|
+
|
|
83
|
+
- ROI outlines must remain visible across colormaps, themes, and local image
|
|
84
|
+
brightness.
|
|
85
|
+
- Keep per-ROI identity colors, but do not rely on color alone for visibility.
|
|
86
|
+
- Use an adaptive high-contrast halo or dual-outline rendering for ROI borders.
|
|
87
|
+
- ROI labels should use contrast-aware text/halo rendering.
|
|
88
|
+
|
|
89
|
+
## Implementation Direction
|
|
90
|
+
|
|
91
|
+
- Rebuild ROI around a small session-local model:
|
|
92
|
+
`id`, `name`, `shape`, `geometry`, `scope`, `visible`, `selected`.
|
|
93
|
+
- Use true shape masks for stats and export. Do not fall back to bounding boxes
|
|
94
|
+
for circle, freehand, or flood fill.
|
|
95
|
+
- Route ROI visibility through existing UI reconcilers and colorbar flip
|
|
96
|
+
patterns.
|
|
97
|
+
- Update the command registry and `GUIDE_TABS` when finalizing shortcuts and
|
|
98
|
+
help text.
|
|
99
|
+
- Update `docs/measurement.md` only after implementation matches this spec.
|
|
100
|
+
|
|
101
|
+
## Test Plan
|
|
102
|
+
|
|
103
|
+
- Spec review first: confirm this document captures the intended ROI direction
|
|
104
|
+
before rebuilding the implementation.
|
|
105
|
+
- Backend tests:
|
|
106
|
+
- true circle mask stats
|
|
107
|
+
- freehand and floodfill mask stats
|
|
108
|
+
- qMRI per-map stats
|
|
109
|
+
- `.npy` label mask shape and label values
|
|
110
|
+
- Browser tests:
|
|
111
|
+
- `Shift+R` hide/show preserves session ROIs
|
|
112
|
+
- default drawing shape is circle
|
|
113
|
+
- stats popup supports rename, delete, CSV export, and mask export
|
|
114
|
+
- qMRI mode shows per-map stats
|
|
115
|
+
- ROI outlines remain readable across themes/colormaps
|
|
116
|
+
- Regression tests:
|
|
117
|
+
- simple ROI drawing does not require the right drawer
|
|
118
|
+
- no circle suggestion UI or API
|
|
119
|
+
- no cryptic dimensional labels
|
|
120
|
+
|
|
121
|
+
## Assumptions
|
|
122
|
+
|
|
123
|
+
- ROI and segmentation remain separate tools.
|
|
124
|
+
- ROI v1 prioritizes fast measurement and export over full mask management.
|
|
125
|
+
- Session-only ROI geometry is acceptable.
|
|
126
|
+
- Exported CSV and `.npy` masks are the persistence boundary for ROI v1.
|