arrayview 0.26.3__tar.gz → 0.27.2__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.3 → arrayview-0.27.2}/.mex/AGENTS.md +1 -1
- {arrayview-0.26.3 → arrayview-0.27.2}/.mex/ROUTER.md +1 -1
- {arrayview-0.26.3 → arrayview-0.27.2}/.mex/SETUP.md +1 -1
- {arrayview-0.26.3 → arrayview-0.27.2}/.mex/SYNC.md +1 -1
- {arrayview-0.26.3 → arrayview-0.27.2}/.mex/context/conventions.md +1 -1
- {arrayview-0.26.3 → arrayview-0.27.2}/.mex/context/decisions.md +1 -1
- {arrayview-0.26.3 → arrayview-0.27.2}/.mex/context/lifecycle.md +1 -1
- {arrayview-0.26.3 → arrayview-0.27.2}/.mex/context/project-state.md +4 -3
- {arrayview-0.26.3 → arrayview-0.27.2}/.mex/context/render-pipeline.md +1 -1
- {arrayview-0.26.3 → arrayview-0.27.2}/.mex/context/setup.md +2 -2
- {arrayview-0.26.3 → arrayview-0.27.2}/.mex/context/stack.md +1 -1
- {arrayview-0.26.3 → arrayview-0.27.2}/.mex/patterns/INDEX.md +2 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.mex/patterns/README.md +1 -1
- {arrayview-0.26.3 → arrayview-0.27.2}/.mex/patterns/add-server-endpoint.md +1 -1
- {arrayview-0.26.3 → arrayview-0.27.2}/.mex/patterns/animation-verify.md +1 -1
- {arrayview-0.26.3 → arrayview-0.27.2}/.mex/patterns/debug-render.md +1 -1
- {arrayview-0.26.3 → arrayview-0.27.2}/.mex/patterns/debug-vscode-extension-python.md +1 -1
- {arrayview-0.26.3 → arrayview-0.27.2}/.mex/patterns/extend-compare-mode.md +1 -1
- {arrayview-0.26.3 → arrayview-0.27.2}/.mex/patterns/extract-server-route-module.md +1 -1
- {arrayview-0.26.3 → arrayview-0.27.2}/.mex/patterns/frontend-change.md +1 -1
- {arrayview-0.26.3 → arrayview-0.27.2}/PKG-INFO +7 -7
- arrayview-0.27.2/README.md +21 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/docs/measurement.md +7 -3
- {arrayview-0.26.3 → arrayview-0.27.2}/docs/viewing.md +4 -0
- arrayview-0.27.2/plans/roi-analysis-requirements.md +126 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/pyproject.toml +1 -1
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_analysis.py +19 -4
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_launcher.py +2 -1
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_platform.py +15 -7
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_routes_analysis.py +442 -3
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_routes_rendering.py +3 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_routes_websocket.py +3 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_stdio_server.py +5 -1
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_synthetic_mri.py +18 -1
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_viewer.html +3839 -668
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_vscode_browser.py +16 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_vscode_extension.py +1 -1
- arrayview-0.27.2/src/arrayview/arrayview-opener.vsix +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/tests/test_api.py +473 -2
- {arrayview-0.26.3 → arrayview-0.27.2}/tests/test_browser.py +1190 -38
- {arrayview-0.26.3 → arrayview-0.27.2}/tests/test_interactions.py +5 -5
- {arrayview-0.26.3 → arrayview-0.27.2}/tests/test_view_component_integration.py +79 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/tests/visual_smoke.py +11 -1
- {arrayview-0.26.3 → arrayview-0.27.2}/uv.lock +1 -1
- {arrayview-0.26.3 → arrayview-0.27.2}/vscode-extension/extension.js +121 -71
- {arrayview-0.26.3 → arrayview-0.27.2}/vscode-extension/package.json +1 -1
- arrayview-0.26.3/README.md +0 -21
- arrayview-0.26.3/src/arrayview/arrayview-opener.vsix +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.agents/skills/frontend-designer/SKILL.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.agents/skills/invocation-consistency/SKILL.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.agents/skills/modes-consistency/SKILL.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.agents/skills/playwright-cli/SKILL.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.agents/skills/playwright-cli/references/element-attributes.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.agents/skills/playwright-cli/references/playwright-tests.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.agents/skills/playwright-cli/references/request-mocking.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.agents/skills/playwright-cli/references/running-code.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.agents/skills/playwright-cli/references/session-management.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.agents/skills/playwright-cli/references/storage-state.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.agents/skills/playwright-cli/references/test-generation.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.agents/skills/playwright-cli/references/tracing.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.agents/skills/playwright-cli/references/video-recording.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.agents/skills/todo-workflow/SKILL.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.agents/skills/ui-consistency-audit/SKILL.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.agents/skills/viewer-ui-checklist/SKILL.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.agents/skills/visual-bug-fixing/SKILL.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.github/copilot-instructions.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.github/workflows/docs.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.github/workflows/python-publish.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.gitignore +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.ignore +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.mex/context/architecture.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.mex/context/frontend.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.mex/patterns/add-file-format.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.mex/setup.sh +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.mex/sync.sh +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.opencode/opencode.json +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-06T18-46-49-737Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-06T18-48-21-979Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-06T18-51-35-665Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-06T19-07-01-393Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-06T19-14-37-969Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-06T19-21-30-940Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-06T19-23-08-126Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-06T19-29-33-155Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-06T19-31-25-336Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-06T19-31-53-789Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-06T19-39-12-257Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-06T19-39-16-449Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-06T20-15-25-513Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-06T20-25-13-179Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-06T20-39-01-435Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-06T21-01-27-659Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-06T21-01-41-283Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-06T21-03-00-625Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-06T21-04-12-887Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-06T21-33-39-044Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-06T21-38-01-530Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-06T21-45-20-383Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-06T21-55-11-545Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-06T21-56-03-307Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-06T21-56-35-733Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-06T21-57-12-181Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-06T21-57-37-748Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-06T21-58-13-679Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-06T22-37-23-895Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-07T00-39-18-637Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-07T01-41-46-243Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-07T04-31-48-472Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-07T12-14-15-632Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-07T12-14-47-582Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-07T12-16-23-471Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-07T12-17-10-247Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-07T12-18-24-707Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-07T12-20-06-164Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-07T12-20-28-342Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-07T12-21-54-962Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-07T12-22-34-666Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-07T12-23-11-336Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-07T12-23-36-260Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-07T12-24-09-267Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-07T12-24-35-434Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-07T12-25-57-010Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-07T12-34-48-823Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-07T12-46-46-468Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-07T12-48-17-930Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-07T12-49-26-400Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-07T12-50-31-563Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/page-2026-05-07T12-56-45-568Z.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.playwright-cli/theme-dark.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.python-version +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/.vscode/settings.json +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/AGENTS.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/CONTRIBUTING.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/DESIGN.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/LICENSE +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/docs/comparing.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/docs/configuration.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/docs/display.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/docs/index.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/docs/launch-routing-refactor.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/docs/lifecycle.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/docs/loading.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/docs/logo.png +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/docs/remote.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/docs/stylesheets/extra.css +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/matlab/arrayview.m +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/mkdocs.yml +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/plans/2026-04-14-immersive-animation.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/plans/2026-05-07-unified-colormap-picker.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/plans/arrayview_tool_menu_fix_prompt.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/plans/arrayview_tool_menu_implementation_plan.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/plans/egg-placement-mockup.html +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/plans/refactoring_plan.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/plans/webview/LOG.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/scripts/demo.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/scripts/release.sh +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/ARCHITECTURE.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/__init__.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/__main__.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_app.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_codex_open.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_config.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_diff.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_icon.png +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_imaging.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_io.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_launch_plan.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_lifecycle.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_overlays.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_render.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_routes_export.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_routes_loading.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_routes_persistence.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_routes_preload.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_routes_query.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_routes_segmentation.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_routes_state.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_routes_vectorfield.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_segmentation.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_server.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_session.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_shell.html +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_torch.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_vectorfield.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_vscode.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_vscode_shm.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/_vscode_signal.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/src/arrayview/gsap.min.js +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/tests/capture_v_animation.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/tests/conftest.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/tests/lifecycle_matrix.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/tests/make_vectorfield_test_arrays.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/tests/test_backend_shared.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/tests/test_cli.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/tests/test_colorbar_hover_highlight.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/tests/test_command_reachability.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/tests/test_config.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/tests/test_cross_mode_parametrized.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/tests/test_io.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/tests/test_large_arrays.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/tests/test_launch_plan.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/tests/test_lifecycle_contract.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/tests/test_loading_server.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/tests/test_mode_consistency.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/tests/test_mode_entry_batching.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/tests/test_mode_matrix.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/tests/test_mode_roundtrip.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/tests/test_nifti_meta.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/tests/test_rgb_pixel_art.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/tests/test_stdio_server.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/tests/test_torch.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/tests/test_view_component_unit.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/tests/ui_audit.py +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/tests/v_anim_frames/.gitkeep +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/vscode-extension/AGENTS.md +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/vscode-extension/LICENSE +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/vscode-extension/lifecycle_helpers.js +0 -0
- {arrayview-0.26.3 → arrayview-0.27.2}/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.2
|
|
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.
|
|
@@ -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
|
|
|
@@ -38,6 +38,10 @@ Rendered as direct color via `--rgb` on the CLI or `rgb=True` in Python. The fir
|
|
|
38
38
|
|
|
39
39
|
`m` — cycles through magnitude, phase, real, and imaginary parts for complex-valued arrays.
|
|
40
40
|
|
|
41
|
+
## qMRI
|
|
42
|
+
|
|
43
|
+
`q` — opens qMRI for a parameter dimension. Hold Alt/Option while qMRI is active to choose quantitative parameters and synthesised contrasts. Synthetic contrasts show TE/TR/TI sliders below each pane when available.
|
|
44
|
+
|
|
41
45
|
## Navigation
|
|
42
46
|
|
|
43
47
|
Scroll through slices. `/` opens the tool launcher for ortho, compare, qMRI, ROI, segmentation, FFT, projections, and overlays. The direct keys still work. `0` resets the zoom. `?` shows the full key guide.
|
|
@@ -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.
|
|
@@ -67,7 +67,7 @@ def _safe_float(v) -> float | None:
|
|
|
67
67
|
return f if np.isfinite(f) else None
|
|
68
68
|
|
|
69
69
|
|
|
70
|
-
def _histogram_payload(finite: np.ndarray, bins: int) -> dict:
|
|
70
|
+
def _histogram_payload(finite: np.ndarray, bins: int, log_bins: bool = False) -> dict:
|
|
71
71
|
"""Build a histogram response from finite values."""
|
|
72
72
|
if finite.size == 0:
|
|
73
73
|
return {"counts": [], "edges": [], "vmin": 0.0, "vmax": 1.0}
|
|
@@ -81,7 +81,13 @@ def _histogram_payload(finite: np.ndarray, bins: int) -> dict:
|
|
|
81
81
|
"vmax": vmax,
|
|
82
82
|
}
|
|
83
83
|
bins = max(8, min(int(bins), 512))
|
|
84
|
-
|
|
84
|
+
if log_bins and vmin > 0:
|
|
85
|
+
log_data = np.log10(finite)
|
|
86
|
+
_, log_edges = np.histogram(log_data, bins=bins)
|
|
87
|
+
edges = np.power(10.0, log_edges)
|
|
88
|
+
counts, _ = np.histogram(finite, bins=edges)
|
|
89
|
+
else:
|
|
90
|
+
counts, edges = np.histogram(finite, bins=bins)
|
|
85
91
|
return {
|
|
86
92
|
"counts": counts.tolist(),
|
|
87
93
|
"edges": [float(e) for e in edges],
|
|
@@ -113,7 +119,8 @@ def _slice_histogram(
|
|
|
113
119
|
data = apply_complex_mode(raw, complex_mode)
|
|
114
120
|
finite = data.ravel()
|
|
115
121
|
finite = finite[np.isfinite(finite)]
|
|
116
|
-
|
|
122
|
+
log_bins = qmri_role in ("t1", "t2")
|
|
123
|
+
return _histogram_payload(finite, bins, log_bins=log_bins)
|
|
117
124
|
|
|
118
125
|
|
|
119
126
|
def _parse_fixed_indices(fixed_indices: str) -> dict[int, int]:
|
|
@@ -172,6 +179,7 @@ def _volume_histogram(
|
|
|
172
179
|
session, dim_x, dim_y, scroll_dim, scroll_dims
|
|
173
180
|
)
|
|
174
181
|
|
|
182
|
+
log_bins = qmri_role in ("t1", "t2")
|
|
175
183
|
cache_key = (
|
|
176
184
|
dim_x,
|
|
177
185
|
dim_y,
|
|
@@ -179,6 +187,8 @@ def _volume_histogram(
|
|
|
179
187
|
tuple(sorted(fixed.items())),
|
|
180
188
|
complex_mode,
|
|
181
189
|
qmri_role,
|
|
190
|
+
bins,
|
|
191
|
+
log_bins,
|
|
182
192
|
)
|
|
183
193
|
if not hasattr(session, "_volume_hist_cache"):
|
|
184
194
|
session._volume_hist_cache = {}
|
|
@@ -224,7 +234,7 @@ def _volume_histogram(
|
|
|
224
234
|
pixels.append(finite)
|
|
225
235
|
|
|
226
236
|
if pixels:
|
|
227
|
-
result = _histogram_payload(np.concatenate(pixels), bins)
|
|
237
|
+
result = _histogram_payload(np.concatenate(pixels), bins, log_bins=log_bins)
|
|
228
238
|
else:
|
|
229
239
|
result = {"counts": [], "edges": [], "vmin": 0.0, "vmax": 1.0}
|
|
230
240
|
session._volume_hist_cache[cache_key] = {
|
|
@@ -241,14 +251,19 @@ def _lebesgue_slice(
|
|
|
241
251
|
indices,
|
|
242
252
|
complex_mode: int = 0,
|
|
243
253
|
log_scale: bool = False,
|
|
254
|
+
qmri_role: str = "",
|
|
244
255
|
) -> np.ndarray:
|
|
245
256
|
"""Return float32 slice data for Lebesgue mode."""
|
|
257
|
+
from arrayview._synthetic_mri import normalize_relaxation_ms
|
|
258
|
+
|
|
246
259
|
idx_tuple = (
|
|
247
260
|
tuple(int(v) for v in indices.split(","))
|
|
248
261
|
if isinstance(indices, str)
|
|
249
262
|
else tuple(indices)
|
|
250
263
|
)
|
|
251
264
|
raw = extract_slice(session, dim_x, dim_y, list(idx_tuple))
|
|
265
|
+
if qmri_role:
|
|
266
|
+
raw = normalize_relaxation_ms(raw, qmri_role)
|
|
252
267
|
data = apply_complex_mode(raw, complex_mode).astype(np.float32)
|
|
253
268
|
if log_scale:
|
|
254
269
|
data = np.log10(np.abs(data) + 1).astype(np.float32)
|
|
@@ -1148,6 +1148,7 @@ def _handle_cli_spawned_daemon(
|
|
|
1148
1148
|
stdout=subprocess.DEVNULL,
|
|
1149
1149
|
stderr=subprocess.DEVNULL,
|
|
1150
1150
|
close_fds=True,
|
|
1151
|
+
start_new_session=(sys.platform != "win32"),
|
|
1151
1152
|
)
|
|
1152
1153
|
|
|
1153
1154
|
early_webview_opened = False
|
|
@@ -1245,7 +1246,7 @@ def _open_cli_spawned_view(
|
|
|
1245
1246
|
_print_viewer_location(url)
|
|
1246
1247
|
_open_browser(
|
|
1247
1248
|
url,
|
|
1248
|
-
blocking=
|
|
1249
|
+
blocking=(window_mode == "vscode"),
|
|
1249
1250
|
force_vscode=(window_mode == "vscode"),
|
|
1250
1251
|
title=f"ArrayView: {name}",
|
|
1251
1252
|
floating=floating,
|
|
@@ -419,19 +419,27 @@ def _can_native_window() -> bool:
|
|
|
419
419
|
|
|
420
420
|
|
|
421
421
|
def _native_window_gui() -> str | None:
|
|
422
|
-
"""Return the pywebview GUI backend name to use, or None if unavailable.
|
|
422
|
+
"""Return the pywebview GUI backend name to use, or None if unavailable.
|
|
423
|
+
|
|
424
|
+
On macOS/Windows and Linux we return ``""`` so pywebview uses its own
|
|
425
|
+
backend auto-detection, which is more robust than forcing a specific
|
|
426
|
+
backend: it probes each installed binding and falls back across them.
|
|
427
|
+
Forcing ``"qt"`` because ``find_spec("qtpy")`` succeeds is a bad probe —
|
|
428
|
+
qtpy being importable does not mean QtWebEngine can actually initialise
|
|
429
|
+
(missing libnss/libxkbcommon/QtWebEngineProcess is common on Linux), and
|
|
430
|
+
a failed forced backend hangs for ~10s before the watchdog falls back to a
|
|
431
|
+
browser. Letting pywebview pick avoids that. We still require a display
|
|
432
|
+
server on Linux and the webview package itself everywhere.
|
|
433
|
+
"""
|
|
423
434
|
if importlib.util.find_spec("webview") is None:
|
|
424
435
|
return None
|
|
425
436
|
if sys.platform in ("darwin", "win32"):
|
|
426
437
|
return ""
|
|
427
|
-
# Linux/BSD: need a display server
|
|
438
|
+
# Linux/BSD: need a display server. pywebview probes Qt/GTK/Tk backends
|
|
439
|
+
# itself, so we don't pin one — we only confirm a display is reachable.
|
|
428
440
|
if not (os.environ.get("DISPLAY") or os.environ.get("WAYLAND_DISPLAY")):
|
|
429
441
|
return None
|
|
430
|
-
|
|
431
|
-
return "qt"
|
|
432
|
-
if importlib.util.find_spec("gi") is not None:
|
|
433
|
-
return "gtk"
|
|
434
|
-
return None
|
|
442
|
+
return ""
|
|
435
443
|
|
|
436
444
|
|
|
437
445
|
# ---------------------------------------------------------------------------
|