arrayview 0.31.0__tar.gz → 0.31.1__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.31.0 → arrayview-0.31.1}/PKG-INFO +1 -1
- {arrayview-0.31.0 → arrayview-0.31.1}/pyproject.toml +1 -1
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_analysis.py +9 -2
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_overlays.py +2 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_render.py +37 -19
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_routes_rendering.py +1 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_routes_websocket.py +12 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_session.py +96 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/test_api.py +33 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/test_nifti_series.py +111 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/uv.lock +1 -1
- {arrayview-0.31.0 → arrayview-0.31.1}/.agents/skills/frontend-designer/SKILL.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.agents/skills/invocation-consistency/SKILL.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.agents/skills/modes-consistency/SKILL.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.agents/skills/playwright-cli/SKILL.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.agents/skills/playwright-cli/references/element-attributes.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.agents/skills/playwright-cli/references/playwright-tests.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.agents/skills/playwright-cli/references/request-mocking.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.agents/skills/playwright-cli/references/running-code.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.agents/skills/playwright-cli/references/session-management.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.agents/skills/playwright-cli/references/storage-state.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.agents/skills/playwright-cli/references/test-generation.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.agents/skills/playwright-cli/references/tracing.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.agents/skills/playwright-cli/references/video-recording.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.agents/skills/todo-workflow/SKILL.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.agents/skills/ui-consistency-audit/SKILL.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.agents/skills/viewer-ui-checklist/SKILL.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.agents/skills/visual-bug-fixing/SKILL.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.github/copilot-instructions.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.github/workflows/docs.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.github/workflows/launch-contracts.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.github/workflows/python-publish.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.gitignore +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.ignore +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.mex/AGENTS.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.mex/ROUTER.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.mex/SETUP.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.mex/SYNC.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.mex/context/architecture.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.mex/context/conventions.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.mex/context/decisions.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.mex/context/frontend.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.mex/context/lifecycle.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.mex/context/project-state.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.mex/context/render-pipeline.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.mex/context/setup.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.mex/context/stack.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.mex/patterns/INDEX.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.mex/patterns/README.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.mex/patterns/add-file-format.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.mex/patterns/add-server-endpoint.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.mex/patterns/animation-verify.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.mex/patterns/debug-render.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.mex/patterns/debug-vscode-extension-python.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.mex/patterns/extend-compare-mode.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.mex/patterns/extract-server-route-module.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.mex/patterns/frontend-change.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.mex/setup.sh +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.mex/sync.sh +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.opencode/opencode.json +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-06T18-46-49-737Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-06T18-48-21-979Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-06T18-51-35-665Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-06T19-07-01-393Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-06T19-14-37-969Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-06T19-21-30-940Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-06T19-23-08-126Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-06T19-29-33-155Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-06T19-31-25-336Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-06T19-31-53-789Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-06T19-39-12-257Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-06T19-39-16-449Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-06T20-15-25-513Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-06T20-25-13-179Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-06T20-39-01-435Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-06T21-01-27-659Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-06T21-01-41-283Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-06T21-03-00-625Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-06T21-04-12-887Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-06T21-33-39-044Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-06T21-38-01-530Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-06T21-45-20-383Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-06T21-55-11-545Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-06T21-56-03-307Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-06T21-56-35-733Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-06T21-57-12-181Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-06T21-57-37-748Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-06T21-58-13-679Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-06T22-37-23-895Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-07T00-39-18-637Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-07T01-41-46-243Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-07T04-31-48-472Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-07T12-14-15-632Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-07T12-14-47-582Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-07T12-16-23-471Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-07T12-17-10-247Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-07T12-18-24-707Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-07T12-20-06-164Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-07T12-20-28-342Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-07T12-21-54-962Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-07T12-22-34-666Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-07T12-23-11-336Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-07T12-23-36-260Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-07T12-24-09-267Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-07T12-24-35-434Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-07T12-25-57-010Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-07T12-34-48-823Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-07T12-46-46-468Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-07T12-48-17-930Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-07T12-49-26-400Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-07T12-50-31-563Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/page-2026-05-07T12-56-45-568Z.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.playwright-cli/theme-dark.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.python-version +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/.vscode/settings.json +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/AGENTS.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/CONTRIBUTING.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/DESIGN.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/LICENSE +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/README.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/docs/comparing.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/docs/configuration.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/docs/display.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/docs/foreign-hosts.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/docs/index.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/docs/launch-routing-refactor.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/docs/lifecycle.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/docs/loading.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/docs/logo.png +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/docs/measurement.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/docs/remote.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/docs/stylesheets/extra.css +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/docs/viewing.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/docs/vscode-window-routing-plan.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/experiments/ws_tunnel_diag/ws_tunnel_diag.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/matlab/arrayview.m +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/mkdocs.yml +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/plans/2026-04-14-immersive-animation.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/plans/2026-05-07-unified-colormap-picker.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/plans/arrayview_tool_menu_fix_prompt.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/plans/arrayview_tool_menu_implementation_plan.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/plans/egg-placement-mockup.html +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/plans/refactoring_plan.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/plans/roi-analysis-requirements.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/plans/webview/LOG.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/scripts/demo.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/scripts/release.sh +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/ARCHITECTURE.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/__init__.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/__main__.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_app.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_codex_open.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_config.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_diff.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_icon.png +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_imaging.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_instance_registry.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_io.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_launch_plan.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_launcher.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_lifecycle.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_platform.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_routes_analysis.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_routes_export.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_routes_loading.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_routes_persistence.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_routes_preload.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_routes_query.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_routes_segmentation.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_routes_state.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_routes_vectorfield.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_segmentation.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_server.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_session_spec.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_shell.html +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_synthetic_mri.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_torch.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_vectorfield.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_viewer.html +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_vscode.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_vscode_browser.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_vscode_extension.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/_vscode_signal.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/arrayview-opener.vsix +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/src/arrayview/gsap.min.js +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/capture_v_animation.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/conftest.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/lifecycle_matrix.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/make_vectorfield_test_arrays.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/test_backend_shared.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/test_browser.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/test_cli.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/test_colorbar_hover_highlight.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/test_command_reachability.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/test_config.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/test_cross_mode_parametrized.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/test_display_opener_results.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/test_doctor_commands.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/test_instance_registry.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/test_interactions.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/test_invocation_contract_matrix.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/test_io.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/test_large_arrays.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/test_launch_diagnostics.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/test_launch_plan.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/test_lifecycle_contract.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/test_loading_server.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/test_mode_consistency.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/test_mode_matrix.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/test_mode_roundtrip.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/test_nifti_meta.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/test_rgb_pixel_art.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/test_safe_server_stop.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/test_server_identity_status.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/test_session_spec.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/test_torch.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/test_view_component_integration.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/test_view_component_unit.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/test_view_handle_lifecycle.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/test_view_launch_execution.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/test_vscode_ack_protocol.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/ui_audit.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/v_anim_frames/.gitkeep +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/tests/visual_smoke.py +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/vscode-extension/AGENTS.md +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/vscode-extension/LICENSE +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/vscode-extension/extension.js +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/vscode-extension/lifecycle_helpers.js +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/vscode-extension/package.json +0 -0
- {arrayview-0.31.0 → arrayview-0.31.1}/vscode-extension/test_lifecycle_helpers.js +0 -0
|
@@ -34,7 +34,15 @@ def _build_metadata(session) -> dict:
|
|
|
34
34
|
"is_rgb": session.rgb_axis is not None,
|
|
35
35
|
"has_source_file": bool(getattr(session, "filepath", None)),
|
|
36
36
|
}
|
|
37
|
-
|
|
37
|
+
collection_spatial_ndim = getattr(session, "collection_spatial_ndim", None)
|
|
38
|
+
default_shape = target_shape
|
|
39
|
+
if collection_spatial_ndim is not None:
|
|
40
|
+
spatial_ndim = int(collection_spatial_ndim)
|
|
41
|
+
if 2 <= spatial_ndim <= len(target_shape):
|
|
42
|
+
# Collection axes are appended after the image dimensions. They
|
|
43
|
+
# select a case; they must not influence the startup plane.
|
|
44
|
+
default_shape = target_shape[:spatial_ndim]
|
|
45
|
+
default_dims = _session_mod._startup_dims_for_data(session.data, default_shape)
|
|
38
46
|
if default_dims is not None:
|
|
39
47
|
meta["default_dims"] = [int(default_dims[0]), int(default_dims[1])]
|
|
40
48
|
if getattr(session, "spatial_meta", None) is not None:
|
|
@@ -49,7 +57,6 @@ def _build_metadata(session) -> dict:
|
|
|
49
57
|
)
|
|
50
58
|
if getattr(session, "array_keys", None):
|
|
51
59
|
meta["array_keys"] = session.array_keys
|
|
52
|
-
collection_spatial_ndim = getattr(session, "collection_spatial_ndim", None)
|
|
53
60
|
if collection_spatial_ndim is not None:
|
|
54
61
|
meta["collection_spatial_ndim"] = int(collection_spatial_ndim)
|
|
55
62
|
if getattr(session.data, "_av_ragged", False):
|
|
@@ -36,6 +36,7 @@ def _composite_overlays(
|
|
|
36
36
|
dim_y: int,
|
|
37
37
|
idx_tuple: tuple[int, ...],
|
|
38
38
|
shape_hw: tuple[int, int],
|
|
39
|
+
base_shape: tuple[int, ...] | None = None,
|
|
39
40
|
) -> np.ndarray:
|
|
40
41
|
"""Composite one or more overlay masks onto RGBA pixels."""
|
|
41
42
|
if not overlay_sid_str:
|
|
@@ -62,6 +63,7 @@ def _composite_overlays(
|
|
|
62
63
|
dim_y,
|
|
63
64
|
idx_tuple,
|
|
64
65
|
expected_shape=shape_hw,
|
|
66
|
+
base_shape=base_shape,
|
|
65
67
|
)
|
|
66
68
|
rgba = _composite_overlay_mask(
|
|
67
69
|
rgba,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Rendering pipeline: colormaps, LUTs, slice extraction, RGBA, mosaic, RGB, preload."""
|
|
2
2
|
|
|
3
|
+
import itertools
|
|
3
4
|
import threading
|
|
4
5
|
import time
|
|
5
6
|
|
|
@@ -527,6 +528,7 @@ def _extract_overlay_mask(
|
|
|
527
528
|
dim_y: int,
|
|
528
529
|
idx_tuple: tuple[int, ...],
|
|
529
530
|
expected_shape: tuple[int, int],
|
|
531
|
+
base_shape: tuple[int, ...] | None = None,
|
|
530
532
|
) -> np.ndarray | None:
|
|
531
533
|
"""Return the raw overlay slice (float32 H×W) for compositing, or None.
|
|
532
534
|
|
|
@@ -538,27 +540,43 @@ def _extract_overlay_mask(
|
|
|
538
540
|
if ov_session is None:
|
|
539
541
|
return None
|
|
540
542
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
+
ov_shape = tuple(int(size) for size in ov_session.shape)
|
|
544
|
+
main_shape = tuple(int(size) for size in (base_shape or ov_shape))
|
|
545
|
+
if len(ov_shape) > len(main_shape):
|
|
543
546
|
return None
|
|
544
547
|
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
548
|
+
# An overlay may omit one or more non-spatial dimensions from the base.
|
|
549
|
+
# Match its axes to equal-sized base axes, then index only those axes. This
|
|
550
|
+
# broadcasts the overlay over every omitted axis without allocating a tiled
|
|
551
|
+
# copy (important for masks next to multi-echo or multi-channel data).
|
|
552
|
+
map_key = (main_shape, dim_x, dim_y)
|
|
553
|
+
axis_maps = getattr(ov_session, "_overlay_axis_maps", None)
|
|
554
|
+
if axis_maps is None:
|
|
555
|
+
axis_maps = {}
|
|
556
|
+
ov_session._overlay_axis_maps = axis_maps
|
|
557
|
+
if map_key not in axis_maps:
|
|
558
|
+
axis_maps[map_key] = next(
|
|
559
|
+
(
|
|
560
|
+
base_axes
|
|
561
|
+
for base_axes in itertools.combinations(range(len(main_shape)), len(ov_shape))
|
|
562
|
+
if dim_x in base_axes
|
|
563
|
+
and dim_y in base_axes
|
|
564
|
+
and tuple(main_shape[axis] for axis in base_axes) == ov_shape
|
|
565
|
+
),
|
|
566
|
+
None,
|
|
567
|
+
)
|
|
568
|
+
base_axes = axis_maps[map_key]
|
|
569
|
+
if base_axes is None:
|
|
570
|
+
return None
|
|
571
|
+
ov_dim_x = base_axes.index(dim_x)
|
|
572
|
+
ov_dim_y = base_axes.index(dim_y)
|
|
573
|
+
ov_idx = [int(idx_tuple[axis]) for axis in base_axes]
|
|
574
|
+
try:
|
|
575
|
+
ov_raw = extract_slice(ov_session, ov_dim_x, ov_dim_y, ov_idx)
|
|
576
|
+
except Exception:
|
|
577
|
+
return None
|
|
578
|
+
if ov_raw.shape == expected_shape:
|
|
579
|
+
return ov_raw.astype(np.float32)
|
|
562
580
|
return None
|
|
563
581
|
|
|
564
582
|
|
|
@@ -25,6 +25,7 @@ from arrayview._session import (
|
|
|
25
25
|
SESSIONS,
|
|
26
26
|
SHELL_SOCKETS,
|
|
27
27
|
_render,
|
|
28
|
+
_schedule_overlay_prefetch,
|
|
28
29
|
_schedule_prefetch,
|
|
29
30
|
_vprint,
|
|
30
31
|
wait_for_session_ready,
|
|
@@ -340,6 +341,7 @@ def register_websocket_routes(app) -> None:
|
|
|
340
341
|
dim_y,
|
|
341
342
|
idx_tuple,
|
|
342
343
|
(h, w),
|
|
344
|
+
session.shape,
|
|
343
345
|
)
|
|
344
346
|
|
|
345
347
|
render_ms = (time.perf_counter() - render_t0) * 1000.0
|
|
@@ -414,6 +416,16 @@ def register_websocket_routes(app) -> None:
|
|
|
414
416
|
collection_axis,
|
|
415
417
|
collection_direction,
|
|
416
418
|
)
|
|
419
|
+
_schedule_overlay_prefetch(
|
|
420
|
+
session,
|
|
421
|
+
msg.get("overlay_sid"),
|
|
422
|
+
msg.get("overlay_alphas"),
|
|
423
|
+
dim_x,
|
|
424
|
+
dim_y,
|
|
425
|
+
list(idx_tuple),
|
|
426
|
+
collection_axis,
|
|
427
|
+
collection_direction,
|
|
428
|
+
)
|
|
417
429
|
previous_indices = idx_tuple
|
|
418
430
|
except Exception as _ws_exc:
|
|
419
431
|
import traceback
|
|
@@ -101,6 +101,7 @@ def _ensure_render_thread() -> None:
|
|
|
101
101
|
# Neighbor prefetch thread pool (Phase 3)
|
|
102
102
|
# ---------------------------------------------------------------------------
|
|
103
103
|
_PREFETCH_POOL = None
|
|
104
|
+
_OVERLAY_PREFETCH_POOL = None
|
|
104
105
|
_PREFETCH_LOCK = threading.Lock()
|
|
105
106
|
|
|
106
107
|
|
|
@@ -116,6 +117,19 @@ def _get_prefetch_pool():
|
|
|
116
117
|
return _PREFETCH_POOL
|
|
117
118
|
|
|
118
119
|
|
|
120
|
+
def _get_overlay_prefetch_pool():
|
|
121
|
+
"""Return the small pool reserved for collection overlay lookahead."""
|
|
122
|
+
global _OVERLAY_PREFETCH_POOL
|
|
123
|
+
with _PREFETCH_LOCK:
|
|
124
|
+
if _OVERLAY_PREFETCH_POOL is None or _OVERLAY_PREFETCH_POOL._shutdown:
|
|
125
|
+
import concurrent.futures
|
|
126
|
+
|
|
127
|
+
_OVERLAY_PREFETCH_POOL = concurrent.futures.ThreadPoolExecutor(
|
|
128
|
+
max_workers=2, thread_name_prefix="arrayview-overlay-prefetch"
|
|
129
|
+
)
|
|
130
|
+
return _OVERLAY_PREFETCH_POOL
|
|
131
|
+
|
|
132
|
+
|
|
119
133
|
def _schedule_prefetch(session, dim_x, dim_y, idx_list, slice_dim, direction):
|
|
120
134
|
"""Warm raw_cache for the next PREFETCH_NEIGHBORS slices in *direction*.
|
|
121
135
|
|
|
@@ -170,6 +184,85 @@ def _schedule_prefetch(session, dim_x, dim_y, idx_list, slice_dim, direction):
|
|
|
170
184
|
pass # pool shutting down
|
|
171
185
|
|
|
172
186
|
|
|
187
|
+
def _schedule_overlay_prefetch(
|
|
188
|
+
session,
|
|
189
|
+
overlay_sid_str,
|
|
190
|
+
overlay_alphas_str,
|
|
191
|
+
dim_x,
|
|
192
|
+
dim_y,
|
|
193
|
+
idx_list,
|
|
194
|
+
collection_axis,
|
|
195
|
+
direction,
|
|
196
|
+
):
|
|
197
|
+
"""Warm the next collection volume for visible overlays.
|
|
198
|
+
|
|
199
|
+
Overlay work uses its own bounded pool so a long mask decompression cannot
|
|
200
|
+
hold up the main image's single-worker prefetch lane. New navigation
|
|
201
|
+
supersedes overlay jobs that have not started loading a volume yet.
|
|
202
|
+
"""
|
|
203
|
+
if not overlay_sid_str:
|
|
204
|
+
return
|
|
205
|
+
|
|
206
|
+
sids = [sid.strip() for sid in overlay_sid_str.split(",") if sid.strip()]
|
|
207
|
+
alphas = [a.strip() for a in (overlay_alphas_str or "").split(",")]
|
|
208
|
+
visible_sids = []
|
|
209
|
+
for i, sid in enumerate(sids):
|
|
210
|
+
try:
|
|
211
|
+
alpha = float(alphas[i]) if i < len(alphas) and alphas[i] else 1.0
|
|
212
|
+
except ValueError:
|
|
213
|
+
alpha = 1.0
|
|
214
|
+
if alpha > 0.0:
|
|
215
|
+
visible_sids.append(sid)
|
|
216
|
+
if not visible_sids:
|
|
217
|
+
return
|
|
218
|
+
|
|
219
|
+
target = idx_list[collection_axis] + direction
|
|
220
|
+
if not 0 <= target < session.shape[collection_axis]:
|
|
221
|
+
return
|
|
222
|
+
|
|
223
|
+
request_key = (collection_axis, target, tuple(visible_sids))
|
|
224
|
+
if request_key == getattr(session, "_overlay_prefetch_request", None):
|
|
225
|
+
return
|
|
226
|
+
session._overlay_prefetch_request = request_key
|
|
227
|
+
generation = getattr(session, "_overlay_prefetch_generation", 0) + 1
|
|
228
|
+
session._overlay_prefetch_generation = generation
|
|
229
|
+
|
|
230
|
+
def _warm(overlay_sid):
|
|
231
|
+
if generation != getattr(session, "_overlay_prefetch_generation", 0):
|
|
232
|
+
return
|
|
233
|
+
overlay = SESSIONS.get(overlay_sid)
|
|
234
|
+
if overlay is None or collection_axis >= len(overlay.shape):
|
|
235
|
+
return
|
|
236
|
+
overlay_stack_axes = tuple(getattr(overlay.data, "_stack_axes", ()))
|
|
237
|
+
if collection_axis not in overlay_stack_axes or target >= overlay.shape[collection_axis]:
|
|
238
|
+
return
|
|
239
|
+
overlay_idx = list(idx_list[: len(overlay.shape)])
|
|
240
|
+
overlay_idx[collection_axis] = target
|
|
241
|
+
# Sparse --overlay-dir collections represent a missing patient with a
|
|
242
|
+
# None filepath. Avoid allocating a fresh full-size zero volume merely
|
|
243
|
+
# to prefetch an overlay that will be shown empty.
|
|
244
|
+
file_matrix = getattr(overlay.data, "_file_matrix", None)
|
|
245
|
+
if file_matrix is not None:
|
|
246
|
+
modality = 0
|
|
247
|
+
if len(overlay_stack_axes) > 1:
|
|
248
|
+
modality = overlay_idx[overlay_stack_axes[1]]
|
|
249
|
+
if not file_matrix[target][modality]:
|
|
250
|
+
return
|
|
251
|
+
try:
|
|
252
|
+
from arrayview._render import extract_slice
|
|
253
|
+
|
|
254
|
+
extract_slice(overlay, dim_x, dim_y, overlay_idx)
|
|
255
|
+
except Exception:
|
|
256
|
+
pass
|
|
257
|
+
|
|
258
|
+
try:
|
|
259
|
+
pool = _get_overlay_prefetch_pool()
|
|
260
|
+
for overlay_sid in visible_sids:
|
|
261
|
+
pool.submit(_warm, overlay_sid)
|
|
262
|
+
except RuntimeError:
|
|
263
|
+
pass # pool shutting down
|
|
264
|
+
|
|
265
|
+
|
|
173
266
|
async def _render(loop: asyncio.AbstractEventLoop, func) -> object:
|
|
174
267
|
"""Await *func()* in the render thread without using concurrent.futures."""
|
|
175
268
|
_ensure_render_thread()
|
|
@@ -476,9 +569,12 @@ __all__ = [
|
|
|
476
569
|
"_render",
|
|
477
570
|
# Prefetch
|
|
478
571
|
"_PREFETCH_POOL",
|
|
572
|
+
"_OVERLAY_PREFETCH_POOL",
|
|
479
573
|
"_PREFETCH_LOCK",
|
|
480
574
|
"_get_prefetch_pool",
|
|
575
|
+
"_get_overlay_prefetch_pool",
|
|
481
576
|
"_schedule_prefetch",
|
|
577
|
+
"_schedule_overlay_prefetch",
|
|
482
578
|
# Session
|
|
483
579
|
"Session",
|
|
484
580
|
"SESSIONS",
|
|
@@ -100,6 +100,14 @@ class TestHealth:
|
|
|
100
100
|
|
|
101
101
|
assert body["default_dims"] == [0, 1]
|
|
102
102
|
|
|
103
|
+
def test_metadata_prefers_trailing_plane_when_it_has_the_two_largest_axes(self, client, tmp_path):
|
|
104
|
+
path = tmp_path / "startup_dims_volume.npy"
|
|
105
|
+
np.save(path, np.zeros((48, 224, 224), dtype=np.float32))
|
|
106
|
+
|
|
107
|
+
sid = client.post("/load", json={"filepath": str(path)}).json()["sid"]
|
|
108
|
+
|
|
109
|
+
assert client.get(f"/metadata/{sid}").json()["default_dims"] == [1, 2]
|
|
110
|
+
|
|
103
111
|
def test_sessions_lists_registered_sid(self, client, sid_2d):
|
|
104
112
|
r = client.get("/sessions")
|
|
105
113
|
assert r.status_code == 200
|
|
@@ -4593,6 +4601,31 @@ class TestCropPersistence:
|
|
|
4593
4601
|
|
|
4594
4602
|
|
|
4595
4603
|
class TestMultipleOverlays:
|
|
4604
|
+
def test_overlay_broadcasts_over_missing_base_dimension(self):
|
|
4605
|
+
from arrayview._render import _extract_overlay_mask
|
|
4606
|
+
from arrayview._session import SESSIONS, Session
|
|
4607
|
+
|
|
4608
|
+
base = Session(np.zeros((48, 3, 224, 224), dtype=np.float32))
|
|
4609
|
+
overlay_data = np.zeros((48, 224, 224), dtype=np.uint8)
|
|
4610
|
+
overlay_data[12, 100, 150] = 1
|
|
4611
|
+
overlay = Session(overlay_data)
|
|
4612
|
+
SESSIONS[overlay.sid] = overlay
|
|
4613
|
+
try:
|
|
4614
|
+
for channel in range(3):
|
|
4615
|
+
result = _extract_overlay_mask(
|
|
4616
|
+
overlay.sid,
|
|
4617
|
+
dim_x=2,
|
|
4618
|
+
dim_y=3,
|
|
4619
|
+
idx_tuple=(12, channel, 112, 112),
|
|
4620
|
+
expected_shape=(224, 224),
|
|
4621
|
+
base_shape=base.shape,
|
|
4622
|
+
)
|
|
4623
|
+
assert result is not None
|
|
4624
|
+
assert result[150, 100] == 1
|
|
4625
|
+
assert overlay.data is overlay_data
|
|
4626
|
+
finally:
|
|
4627
|
+
SESSIONS.pop(overlay.sid, None)
|
|
4628
|
+
|
|
4596
4629
|
def test_single_overlay_with_color(self, client, sid_2d):
|
|
4597
4630
|
"""A single binary mask overlay with explicit hex color renders without error."""
|
|
4598
4631
|
from arrayview._app import SESSIONS, Session
|
|
@@ -329,6 +329,108 @@ def test_stale_collection_prefetch_is_coalesced(monkeypatch):
|
|
|
329
329
|
assert warmed == [21]
|
|
330
330
|
|
|
331
331
|
|
|
332
|
+
def test_overlay_prefetch_only_warms_visible_next_patient(monkeypatch):
|
|
333
|
+
from arrayview import _session as session_mod
|
|
334
|
+
import arrayview._render as render_mod
|
|
335
|
+
|
|
336
|
+
warmed = []
|
|
337
|
+
main = SimpleNamespace(
|
|
338
|
+
shape=(32, 32, 20, 100),
|
|
339
|
+
_overlay_prefetch_generation=0,
|
|
340
|
+
)
|
|
341
|
+
overlays = {
|
|
342
|
+
"visible": SimpleNamespace(
|
|
343
|
+
shape=main.shape,
|
|
344
|
+
data=SimpleNamespace(_stack_axes=(3,)),
|
|
345
|
+
raw_cache={},
|
|
346
|
+
),
|
|
347
|
+
"hidden": SimpleNamespace(
|
|
348
|
+
shape=main.shape,
|
|
349
|
+
data=SimpleNamespace(_stack_axes=(3,)),
|
|
350
|
+
raw_cache={},
|
|
351
|
+
),
|
|
352
|
+
"missing": SimpleNamespace(
|
|
353
|
+
shape=main.shape,
|
|
354
|
+
data=SimpleNamespace(
|
|
355
|
+
_stack_axes=(3,),
|
|
356
|
+
_file_matrix=[["mask.nii.gz"] for _ in range(100)],
|
|
357
|
+
),
|
|
358
|
+
raw_cache={},
|
|
359
|
+
),
|
|
360
|
+
"not_collection": SimpleNamespace(
|
|
361
|
+
shape=main.shape,
|
|
362
|
+
data=SimpleNamespace(_stack_axes=()),
|
|
363
|
+
raw_cache={},
|
|
364
|
+
),
|
|
365
|
+
}
|
|
366
|
+
overlays["missing"].data._file_matrix[13][0] = None
|
|
367
|
+
|
|
368
|
+
class ImmediatePool:
|
|
369
|
+
def submit(self, fn, *args):
|
|
370
|
+
fn(*args)
|
|
371
|
+
|
|
372
|
+
monkeypatch.setattr(session_mod, "SESSIONS", overlays)
|
|
373
|
+
monkeypatch.setattr(session_mod, "_get_overlay_prefetch_pool", lambda: ImmediatePool())
|
|
374
|
+
monkeypatch.setattr(
|
|
375
|
+
render_mod,
|
|
376
|
+
"extract_slice",
|
|
377
|
+
lambda overlay, _dx, _dy, idx: warmed.append((overlay, idx[3])),
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
session_mod._schedule_overlay_prefetch(
|
|
381
|
+
main,
|
|
382
|
+
"visible,hidden,missing,not_collection,unknown",
|
|
383
|
+
"0.45,0,0.45,0.45,0.45",
|
|
384
|
+
0,
|
|
385
|
+
1,
|
|
386
|
+
[0, 0, 10, 12],
|
|
387
|
+
3,
|
|
388
|
+
1,
|
|
389
|
+
)
|
|
390
|
+
|
|
391
|
+
assert warmed == [(overlays["visible"], 13)]
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
def test_stale_overlay_prefetch_is_coalesced(monkeypatch):
|
|
395
|
+
from arrayview import _session as session_mod
|
|
396
|
+
import arrayview._render as render_mod
|
|
397
|
+
|
|
398
|
+
queued = []
|
|
399
|
+
warmed = []
|
|
400
|
+
main = SimpleNamespace(shape=(32, 32, 20, 100))
|
|
401
|
+
overlay = SimpleNamespace(
|
|
402
|
+
shape=main.shape,
|
|
403
|
+
data=SimpleNamespace(_stack_axes=(3,)),
|
|
404
|
+
raw_cache={},
|
|
405
|
+
)
|
|
406
|
+
|
|
407
|
+
class QueuedPool:
|
|
408
|
+
def submit(self, fn, *args):
|
|
409
|
+
queued.append((fn, args))
|
|
410
|
+
|
|
411
|
+
monkeypatch.setattr(session_mod, "SESSIONS", {"overlay": overlay})
|
|
412
|
+
monkeypatch.setattr(session_mod, "_get_overlay_prefetch_pool", lambda: QueuedPool())
|
|
413
|
+
monkeypatch.setattr(
|
|
414
|
+
render_mod,
|
|
415
|
+
"extract_slice",
|
|
416
|
+
lambda _overlay, _dx, _dy, idx: warmed.append(idx[3]),
|
|
417
|
+
)
|
|
418
|
+
|
|
419
|
+
session_mod._schedule_overlay_prefetch(
|
|
420
|
+
main, "overlay", "0.45", 0, 1, [0, 0, 10, 12], 3, 1
|
|
421
|
+
)
|
|
422
|
+
session_mod._schedule_overlay_prefetch(
|
|
423
|
+
main, "overlay", "0.45", 0, 1, [0, 0, 11, 12], 3, 1
|
|
424
|
+
)
|
|
425
|
+
session_mod._schedule_overlay_prefetch(
|
|
426
|
+
main, "overlay", "0.45", 0, 1, [0, 0, 10, 20], 3, 1
|
|
427
|
+
)
|
|
428
|
+
for fn, args in queued:
|
|
429
|
+
fn(*args)
|
|
430
|
+
|
|
431
|
+
assert warmed == [21]
|
|
432
|
+
|
|
433
|
+
|
|
332
434
|
# ---------------------------------------------------------------------------
|
|
333
435
|
# Non-NIfTI file series (.npy, .npz, etc.)
|
|
334
436
|
# ---------------------------------------------------------------------------
|
|
@@ -643,6 +745,15 @@ class TestDirCollection:
|
|
|
643
745
|
assert meta["collection_spatial_ndim"] == 3
|
|
644
746
|
assert meta["ragged_spatial_shapes"][1][1] == [3, 6, 6]
|
|
645
747
|
|
|
748
|
+
def test_metadata_ignores_case_axis_when_selecting_startup_plane(self):
|
|
749
|
+
from arrayview._analysis import _build_metadata
|
|
750
|
+
from arrayview._session import Session
|
|
751
|
+
|
|
752
|
+
session = Session(np.zeros((48, 3, 224, 224, 5), dtype=np.float32))
|
|
753
|
+
session.collection_spatial_ndim = 4
|
|
754
|
+
|
|
755
|
+
assert _build_metadata(session)["default_dims"] == [2, 3]
|
|
756
|
+
|
|
646
757
|
def test_ordered_pairing_mismatched_counts_error(self, tmp_path):
|
|
647
758
|
import arrayview._io as _io
|
|
648
759
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{arrayview-0.31.0 → arrayview-0.31.1}/.agents/skills/playwright-cli/references/element-attributes.md
RENAMED
|
File without changes
|
{arrayview-0.31.0 → arrayview-0.31.1}/.agents/skills/playwright-cli/references/playwright-tests.md
RENAMED
|
File without changes
|
{arrayview-0.31.0 → arrayview-0.31.1}/.agents/skills/playwright-cli/references/request-mocking.md
RENAMED
|
File without changes
|
{arrayview-0.31.0 → arrayview-0.31.1}/.agents/skills/playwright-cli/references/running-code.md
RENAMED
|
File without changes
|
{arrayview-0.31.0 → arrayview-0.31.1}/.agents/skills/playwright-cli/references/session-management.md
RENAMED
|
File without changes
|
{arrayview-0.31.0 → arrayview-0.31.1}/.agents/skills/playwright-cli/references/storage-state.md
RENAMED
|
File without changes
|
{arrayview-0.31.0 → arrayview-0.31.1}/.agents/skills/playwright-cli/references/test-generation.md
RENAMED
|
File without changes
|
|
File without changes
|
{arrayview-0.31.0 → arrayview-0.31.1}/.agents/skills/playwright-cli/references/video-recording.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|