arrayview 0.31.2__tar.gz → 0.32.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.
Files changed (235) hide show
  1. {arrayview-0.31.2 → arrayview-0.32.0}/.github/workflows/launch-contracts.yml +4 -4
  2. {arrayview-0.31.2 → arrayview-0.32.0}/.mex/context/lifecycle.md +12 -2
  3. {arrayview-0.31.2 → arrayview-0.32.0}/.mex/context/project-state.md +12 -6
  4. {arrayview-0.31.2 → arrayview-0.32.0}/PKG-INFO +5 -2
  5. {arrayview-0.31.2 → arrayview-0.32.0}/README.md +4 -1
  6. {arrayview-0.31.2 → arrayview-0.32.0}/docs/index.md +2 -0
  7. {arrayview-0.31.2 → arrayview-0.32.0}/docs/loading.md +31 -61
  8. arrayview-0.32.0/docs/stack-overlays.md +129 -0
  9. {arrayview-0.31.2 → arrayview-0.32.0}/mkdocs.yml +1 -0
  10. {arrayview-0.31.2 → arrayview-0.32.0}/pyproject.toml +1 -1
  11. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/__init__.py +1 -3
  12. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_io.py +376 -110
  13. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_launcher.py +286 -153
  14. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_routes_analysis.py +17 -0
  15. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_routes_loading.py +88 -5
  16. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_routes_query.py +59 -0
  17. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_session.py +10 -0
  18. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_session_spec.py +0 -4
  19. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_viewer.html +1016 -128
  20. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_vscode_browser.py +19 -7
  21. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_vscode_extension.py +195 -27
  22. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_vscode_signal.py +55 -1
  23. arrayview-0.32.0/src/arrayview/arrayview-opener.vsix +0 -0
  24. arrayview-0.32.0/src/arrayview/todo.md +12 -0
  25. arrayview-0.32.0/tests/capture_patient_loading.py +120 -0
  26. {arrayview-0.31.2 → arrayview-0.32.0}/tests/test_api.py +309 -0
  27. {arrayview-0.31.2 → arrayview-0.32.0}/tests/test_browser.py +286 -0
  28. {arrayview-0.31.2 → arrayview-0.32.0}/tests/test_cli.py +172 -0
  29. {arrayview-0.31.2 → arrayview-0.32.0}/tests/test_command_reachability.py +1 -0
  30. {arrayview-0.31.2 → arrayview-0.32.0}/tests/test_display_opener_results.py +20 -0
  31. {arrayview-0.31.2 → arrayview-0.32.0}/tests/test_lifecycle_contract.py +270 -4
  32. {arrayview-0.31.2 → arrayview-0.32.0}/tests/test_mode_roundtrip.py +183 -0
  33. {arrayview-0.31.2 → arrayview-0.32.0}/tests/test_nifti_series.py +235 -70
  34. {arrayview-0.31.2 → arrayview-0.32.0}/tests/test_session_spec.py +0 -2
  35. {arrayview-0.31.2 → arrayview-0.32.0}/tests/test_vscode_ack_protocol.py +61 -0
  36. {arrayview-0.31.2 → arrayview-0.32.0}/uv.lock +1 -1
  37. {arrayview-0.31.2 → arrayview-0.32.0}/vscode-extension/extension.js +465 -104
  38. {arrayview-0.31.2 → arrayview-0.32.0}/vscode-extension/lifecycle_helpers.js +40 -1
  39. {arrayview-0.31.2 → arrayview-0.32.0}/vscode-extension/package.json +1 -1
  40. {arrayview-0.31.2 → arrayview-0.32.0}/vscode-extension/test_lifecycle_helpers.js +24 -1
  41. arrayview-0.32.0/vscode-extension/test_tunnel_resolution.js +55 -0
  42. arrayview-0.31.2/src/arrayview/arrayview-opener.vsix +0 -0
  43. {arrayview-0.31.2 → arrayview-0.32.0}/.agents/skills/frontend-designer/SKILL.md +0 -0
  44. {arrayview-0.31.2 → arrayview-0.32.0}/.agents/skills/invocation-consistency/SKILL.md +0 -0
  45. {arrayview-0.31.2 → arrayview-0.32.0}/.agents/skills/modes-consistency/SKILL.md +0 -0
  46. {arrayview-0.31.2 → arrayview-0.32.0}/.agents/skills/playwright-cli/SKILL.md +0 -0
  47. {arrayview-0.31.2 → arrayview-0.32.0}/.agents/skills/playwright-cli/references/element-attributes.md +0 -0
  48. {arrayview-0.31.2 → arrayview-0.32.0}/.agents/skills/playwright-cli/references/playwright-tests.md +0 -0
  49. {arrayview-0.31.2 → arrayview-0.32.0}/.agents/skills/playwright-cli/references/request-mocking.md +0 -0
  50. {arrayview-0.31.2 → arrayview-0.32.0}/.agents/skills/playwright-cli/references/running-code.md +0 -0
  51. {arrayview-0.31.2 → arrayview-0.32.0}/.agents/skills/playwright-cli/references/session-management.md +0 -0
  52. {arrayview-0.31.2 → arrayview-0.32.0}/.agents/skills/playwright-cli/references/storage-state.md +0 -0
  53. {arrayview-0.31.2 → arrayview-0.32.0}/.agents/skills/playwright-cli/references/test-generation.md +0 -0
  54. {arrayview-0.31.2 → arrayview-0.32.0}/.agents/skills/playwright-cli/references/tracing.md +0 -0
  55. {arrayview-0.31.2 → arrayview-0.32.0}/.agents/skills/playwright-cli/references/video-recording.md +0 -0
  56. {arrayview-0.31.2 → arrayview-0.32.0}/.agents/skills/todo-workflow/SKILL.md +0 -0
  57. {arrayview-0.31.2 → arrayview-0.32.0}/.agents/skills/ui-consistency-audit/SKILL.md +0 -0
  58. {arrayview-0.31.2 → arrayview-0.32.0}/.agents/skills/viewer-ui-checklist/SKILL.md +0 -0
  59. {arrayview-0.31.2 → arrayview-0.32.0}/.agents/skills/visual-bug-fixing/SKILL.md +0 -0
  60. {arrayview-0.31.2 → arrayview-0.32.0}/.github/copilot-instructions.md +0 -0
  61. {arrayview-0.31.2 → arrayview-0.32.0}/.github/workflows/docs.yml +0 -0
  62. {arrayview-0.31.2 → arrayview-0.32.0}/.github/workflows/python-publish.yml +0 -0
  63. {arrayview-0.31.2 → arrayview-0.32.0}/.gitignore +0 -0
  64. {arrayview-0.31.2 → arrayview-0.32.0}/.ignore +0 -0
  65. {arrayview-0.31.2 → arrayview-0.32.0}/.mex/AGENTS.md +0 -0
  66. {arrayview-0.31.2 → arrayview-0.32.0}/.mex/ROUTER.md +0 -0
  67. {arrayview-0.31.2 → arrayview-0.32.0}/.mex/SETUP.md +0 -0
  68. {arrayview-0.31.2 → arrayview-0.32.0}/.mex/SYNC.md +0 -0
  69. {arrayview-0.31.2 → arrayview-0.32.0}/.mex/context/architecture.md +0 -0
  70. {arrayview-0.31.2 → arrayview-0.32.0}/.mex/context/conventions.md +0 -0
  71. {arrayview-0.31.2 → arrayview-0.32.0}/.mex/context/decisions.md +0 -0
  72. {arrayview-0.31.2 → arrayview-0.32.0}/.mex/context/frontend.md +0 -0
  73. {arrayview-0.31.2 → arrayview-0.32.0}/.mex/context/render-pipeline.md +0 -0
  74. {arrayview-0.31.2 → arrayview-0.32.0}/.mex/context/setup.md +0 -0
  75. {arrayview-0.31.2 → arrayview-0.32.0}/.mex/context/stack.md +0 -0
  76. {arrayview-0.31.2 → arrayview-0.32.0}/.mex/patterns/INDEX.md +0 -0
  77. {arrayview-0.31.2 → arrayview-0.32.0}/.mex/patterns/README.md +0 -0
  78. {arrayview-0.31.2 → arrayview-0.32.0}/.mex/patterns/add-file-format.md +0 -0
  79. {arrayview-0.31.2 → arrayview-0.32.0}/.mex/patterns/add-server-endpoint.md +0 -0
  80. {arrayview-0.31.2 → arrayview-0.32.0}/.mex/patterns/animation-verify.md +0 -0
  81. {arrayview-0.31.2 → arrayview-0.32.0}/.mex/patterns/debug-render.md +0 -0
  82. {arrayview-0.31.2 → arrayview-0.32.0}/.mex/patterns/debug-vscode-extension-python.md +0 -0
  83. {arrayview-0.31.2 → arrayview-0.32.0}/.mex/patterns/extend-compare-mode.md +0 -0
  84. {arrayview-0.31.2 → arrayview-0.32.0}/.mex/patterns/extract-server-route-module.md +0 -0
  85. {arrayview-0.31.2 → arrayview-0.32.0}/.mex/patterns/frontend-change.md +0 -0
  86. {arrayview-0.31.2 → arrayview-0.32.0}/.mex/setup.sh +0 -0
  87. {arrayview-0.31.2 → arrayview-0.32.0}/.mex/sync.sh +0 -0
  88. {arrayview-0.31.2 → arrayview-0.32.0}/.opencode/opencode.json +0 -0
  89. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-06T18-46-49-737Z.yml +0 -0
  90. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-06T18-48-21-979Z.yml +0 -0
  91. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-06T18-51-35-665Z.yml +0 -0
  92. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-06T19-07-01-393Z.yml +0 -0
  93. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-06T19-14-37-969Z.yml +0 -0
  94. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-06T19-21-30-940Z.yml +0 -0
  95. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-06T19-23-08-126Z.yml +0 -0
  96. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-06T19-29-33-155Z.yml +0 -0
  97. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-06T19-31-25-336Z.yml +0 -0
  98. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-06T19-31-53-789Z.yml +0 -0
  99. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-06T19-39-12-257Z.yml +0 -0
  100. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-06T19-39-16-449Z.yml +0 -0
  101. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-06T20-15-25-513Z.yml +0 -0
  102. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-06T20-25-13-179Z.yml +0 -0
  103. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-06T20-39-01-435Z.yml +0 -0
  104. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-06T21-01-27-659Z.yml +0 -0
  105. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-06T21-01-41-283Z.yml +0 -0
  106. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-06T21-03-00-625Z.yml +0 -0
  107. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-06T21-04-12-887Z.yml +0 -0
  108. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-06T21-33-39-044Z.yml +0 -0
  109. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-06T21-38-01-530Z.yml +0 -0
  110. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-06T21-45-20-383Z.yml +0 -0
  111. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-06T21-55-11-545Z.yml +0 -0
  112. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-06T21-56-03-307Z.yml +0 -0
  113. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-06T21-56-35-733Z.yml +0 -0
  114. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-06T21-57-12-181Z.yml +0 -0
  115. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-06T21-57-37-748Z.yml +0 -0
  116. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-06T21-58-13-679Z.yml +0 -0
  117. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-06T22-37-23-895Z.yml +0 -0
  118. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-07T00-39-18-637Z.yml +0 -0
  119. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-07T01-41-46-243Z.yml +0 -0
  120. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-07T04-31-48-472Z.yml +0 -0
  121. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-07T12-14-15-632Z.yml +0 -0
  122. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-07T12-14-47-582Z.yml +0 -0
  123. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-07T12-16-23-471Z.yml +0 -0
  124. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-07T12-17-10-247Z.yml +0 -0
  125. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-07T12-18-24-707Z.yml +0 -0
  126. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-07T12-20-06-164Z.yml +0 -0
  127. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-07T12-20-28-342Z.yml +0 -0
  128. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-07T12-21-54-962Z.yml +0 -0
  129. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-07T12-22-34-666Z.yml +0 -0
  130. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-07T12-23-11-336Z.yml +0 -0
  131. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-07T12-23-36-260Z.yml +0 -0
  132. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-07T12-24-09-267Z.yml +0 -0
  133. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-07T12-24-35-434Z.yml +0 -0
  134. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-07T12-25-57-010Z.yml +0 -0
  135. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-07T12-34-48-823Z.yml +0 -0
  136. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-07T12-46-46-468Z.yml +0 -0
  137. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-07T12-48-17-930Z.yml +0 -0
  138. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-07T12-49-26-400Z.yml +0 -0
  139. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-07T12-50-31-563Z.yml +0 -0
  140. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/page-2026-05-07T12-56-45-568Z.yml +0 -0
  141. {arrayview-0.31.2 → arrayview-0.32.0}/.playwright-cli/theme-dark.yml +0 -0
  142. {arrayview-0.31.2 → arrayview-0.32.0}/.python-version +0 -0
  143. {arrayview-0.31.2 → arrayview-0.32.0}/.vscode/settings.json +0 -0
  144. {arrayview-0.31.2 → arrayview-0.32.0}/AGENTS.md +0 -0
  145. {arrayview-0.31.2 → arrayview-0.32.0}/CONTRIBUTING.md +0 -0
  146. {arrayview-0.31.2 → arrayview-0.32.0}/DESIGN.md +0 -0
  147. {arrayview-0.31.2 → arrayview-0.32.0}/LICENSE +0 -0
  148. {arrayview-0.31.2 → arrayview-0.32.0}/docs/comparing.md +0 -0
  149. {arrayview-0.31.2 → arrayview-0.32.0}/docs/configuration.md +0 -0
  150. {arrayview-0.31.2 → arrayview-0.32.0}/docs/display.md +0 -0
  151. {arrayview-0.31.2 → arrayview-0.32.0}/docs/foreign-hosts.md +0 -0
  152. {arrayview-0.31.2 → arrayview-0.32.0}/docs/launch-routing-refactor.md +0 -0
  153. {arrayview-0.31.2 → arrayview-0.32.0}/docs/lifecycle.md +0 -0
  154. {arrayview-0.31.2 → arrayview-0.32.0}/docs/logo.png +0 -0
  155. {arrayview-0.31.2 → arrayview-0.32.0}/docs/measurement.md +0 -0
  156. {arrayview-0.31.2 → arrayview-0.32.0}/docs/remote.md +0 -0
  157. {arrayview-0.31.2 → arrayview-0.32.0}/docs/stylesheets/extra.css +0 -0
  158. {arrayview-0.31.2 → arrayview-0.32.0}/docs/viewing.md +0 -0
  159. {arrayview-0.31.2 → arrayview-0.32.0}/docs/vscode-window-routing-plan.md +0 -0
  160. {arrayview-0.31.2 → arrayview-0.32.0}/experiments/ws_tunnel_diag/ws_tunnel_diag.py +0 -0
  161. {arrayview-0.31.2 → arrayview-0.32.0}/matlab/arrayview.m +0 -0
  162. {arrayview-0.31.2 → arrayview-0.32.0}/plans/2026-04-14-immersive-animation.md +0 -0
  163. {arrayview-0.31.2 → arrayview-0.32.0}/plans/2026-05-07-unified-colormap-picker.md +0 -0
  164. {arrayview-0.31.2 → arrayview-0.32.0}/plans/arrayview_tool_menu_fix_prompt.md +0 -0
  165. {arrayview-0.31.2 → arrayview-0.32.0}/plans/arrayview_tool_menu_implementation_plan.md +0 -0
  166. {arrayview-0.31.2 → arrayview-0.32.0}/plans/egg-placement-mockup.html +0 -0
  167. {arrayview-0.31.2 → arrayview-0.32.0}/plans/refactoring_plan.md +0 -0
  168. {arrayview-0.31.2 → arrayview-0.32.0}/plans/roi-analysis-requirements.md +0 -0
  169. {arrayview-0.31.2 → arrayview-0.32.0}/plans/webview/LOG.md +0 -0
  170. {arrayview-0.31.2 → arrayview-0.32.0}/scripts/demo.py +0 -0
  171. {arrayview-0.31.2 → arrayview-0.32.0}/scripts/release.sh +0 -0
  172. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/ARCHITECTURE.md +0 -0
  173. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/__main__.py +0 -0
  174. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_analysis.py +0 -0
  175. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_app.py +0 -0
  176. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_codex_open.py +0 -0
  177. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_config.py +0 -0
  178. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_diff.py +0 -0
  179. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_icon.png +0 -0
  180. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_imaging.py +0 -0
  181. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_instance_registry.py +0 -0
  182. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_launch_plan.py +0 -0
  183. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_lifecycle.py +0 -0
  184. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_overlays.py +0 -0
  185. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_platform.py +0 -0
  186. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_render.py +0 -0
  187. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_routes_export.py +0 -0
  188. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_routes_persistence.py +0 -0
  189. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_routes_preload.py +0 -0
  190. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_routes_rendering.py +0 -0
  191. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_routes_segmentation.py +0 -0
  192. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_routes_state.py +0 -0
  193. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_routes_vectorfield.py +0 -0
  194. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_routes_websocket.py +0 -0
  195. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_segmentation.py +0 -0
  196. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_server.py +0 -0
  197. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_shell.html +0 -0
  198. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_synthetic_mri.py +0 -0
  199. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_torch.py +0 -0
  200. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_vectorfield.py +0 -0
  201. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/_vscode.py +0 -0
  202. {arrayview-0.31.2 → arrayview-0.32.0}/src/arrayview/gsap.min.js +0 -0
  203. {arrayview-0.31.2 → arrayview-0.32.0}/tests/capture_v_animation.py +0 -0
  204. {arrayview-0.31.2 → arrayview-0.32.0}/tests/conftest.py +0 -0
  205. {arrayview-0.31.2 → arrayview-0.32.0}/tests/lifecycle_matrix.py +0 -0
  206. {arrayview-0.31.2 → arrayview-0.32.0}/tests/make_vectorfield_test_arrays.py +0 -0
  207. {arrayview-0.31.2 → arrayview-0.32.0}/tests/test_backend_shared.py +0 -0
  208. {arrayview-0.31.2 → arrayview-0.32.0}/tests/test_colorbar_hover_highlight.py +0 -0
  209. {arrayview-0.31.2 → arrayview-0.32.0}/tests/test_config.py +0 -0
  210. {arrayview-0.31.2 → arrayview-0.32.0}/tests/test_cross_mode_parametrized.py +0 -0
  211. {arrayview-0.31.2 → arrayview-0.32.0}/tests/test_doctor_commands.py +0 -0
  212. {arrayview-0.31.2 → arrayview-0.32.0}/tests/test_instance_registry.py +0 -0
  213. {arrayview-0.31.2 → arrayview-0.32.0}/tests/test_interactions.py +0 -0
  214. {arrayview-0.31.2 → arrayview-0.32.0}/tests/test_invocation_contract_matrix.py +0 -0
  215. {arrayview-0.31.2 → arrayview-0.32.0}/tests/test_io.py +0 -0
  216. {arrayview-0.31.2 → arrayview-0.32.0}/tests/test_large_arrays.py +0 -0
  217. {arrayview-0.31.2 → arrayview-0.32.0}/tests/test_launch_diagnostics.py +0 -0
  218. {arrayview-0.31.2 → arrayview-0.32.0}/tests/test_launch_plan.py +0 -0
  219. {arrayview-0.31.2 → arrayview-0.32.0}/tests/test_loading_server.py +0 -0
  220. {arrayview-0.31.2 → arrayview-0.32.0}/tests/test_mode_consistency.py +0 -0
  221. {arrayview-0.31.2 → arrayview-0.32.0}/tests/test_mode_matrix.py +0 -0
  222. {arrayview-0.31.2 → arrayview-0.32.0}/tests/test_nifti_meta.py +0 -0
  223. {arrayview-0.31.2 → arrayview-0.32.0}/tests/test_rgb_pixel_art.py +0 -0
  224. {arrayview-0.31.2 → arrayview-0.32.0}/tests/test_safe_server_stop.py +0 -0
  225. {arrayview-0.31.2 → arrayview-0.32.0}/tests/test_server_identity_status.py +0 -0
  226. {arrayview-0.31.2 → arrayview-0.32.0}/tests/test_torch.py +0 -0
  227. {arrayview-0.31.2 → arrayview-0.32.0}/tests/test_view_component_integration.py +0 -0
  228. {arrayview-0.31.2 → arrayview-0.32.0}/tests/test_view_component_unit.py +0 -0
  229. {arrayview-0.31.2 → arrayview-0.32.0}/tests/test_view_handle_lifecycle.py +0 -0
  230. {arrayview-0.31.2 → arrayview-0.32.0}/tests/test_view_launch_execution.py +0 -0
  231. {arrayview-0.31.2 → arrayview-0.32.0}/tests/ui_audit.py +0 -0
  232. {arrayview-0.31.2 → arrayview-0.32.0}/tests/v_anim_frames/.gitkeep +0 -0
  233. {arrayview-0.31.2 → arrayview-0.32.0}/tests/visual_smoke.py +0 -0
  234. {arrayview-0.31.2 → arrayview-0.32.0}/vscode-extension/AGENTS.md +0 -0
  235. {arrayview-0.31.2 → arrayview-0.32.0}/vscode-extension/LICENSE +0 -0
@@ -30,12 +30,12 @@ jobs:
30
30
  os: [ubuntu-latest, macos-latest, windows-latest]
31
31
  runs-on: ${{ matrix.os }}
32
32
  steps:
33
- - uses: actions/checkout@v4
34
- - uses: actions/setup-python@v5
33
+ - uses: actions/checkout@v7
34
+ - uses: actions/setup-python@v6
35
35
  with:
36
36
  python-version: "3.12"
37
- - uses: astral-sh/setup-uv@v6
38
- - uses: actions/setup-node@v4
37
+ - uses: astral-sh/setup-uv@v8
38
+ - uses: actions/setup-node@v6
39
39
  with:
40
40
  node-version: "22"
41
41
  - run: uv sync --frozen --group dev --group test
@@ -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
19
+ last_updated: 2026-07-14
20
20
  ---
21
21
 
22
22
  # Lifecycle
@@ -60,8 +60,10 @@ This contract describes who owns the backend, when it starts, and what closes it
60
60
 
61
61
  - Remote or tunnel launches may persist when `--serve` or tunnel display ownership requires it.
62
62
  - VS Code tunnel display uses forwarded localhost URLs; the extension should configure the port, promote privacy when available, and resolve the URL with `asExternalUri`.
63
- - With multiple registered tunnel windows, a missing or stale `ARRAYVIEW_WINDOW_ID` uses the shared broadcast signal; only the focused VS Code window may claim it.
63
+ - With multiple registered tunnel windows, a missing `ARRAYVIEW_WINDOW_ID` first recovers the exact live registration from the terminal's IPC hook. Only when no exact registration exists does it use the shared focused-window broadcast fallback.
64
64
  - An exact registered `ARRAYVIEW_WINDOW_ID` wins; do not redirect it to a newer same-parent registration because live tunnel windows can share ancestry.
65
+ - Protocol request claims are atomic across extension hosts. Compatibility queue copies with the same request ID must never open in a sibling window or overwrite a terminal ACK.
66
+ - Tunnel `asExternalUri` results must be non-loopback. Remote-SSH may legitimately resolve to a local forwarded URL and must not be subjected to tunnel-only public-port commands.
65
67
  - Plain SSH should use `localhost` forwarding guidance and stay transient unless a shared server was explicitly requested.
66
68
 
67
69
  ## Shared Rules
@@ -70,6 +72,14 @@ This contract describes who owns the backend, when it starts, and what closes it
70
72
  - `release_session()` is the session-release primitive.
71
73
  - Viewer WebSocket connect/disconnect owns active viewer counts.
72
74
  - URL panel disposal must release every SID encoded in the URL: `sid`, `compare_sid`, `compare_sids`, and `overlay_sid`.
75
+ - Tunnel panel disposal posts release requests to the local backend immediately;
76
+ the forwarded public URL is display-only and is not the cleanup authority.
77
+ - Reused file and collection sessions acquire one lease per tab, so closing one
78
+ tab cannot invalidate another tab that shares the same SID.
79
+ - A VS Code readiness ACK includes the live opener version and is terminal only
80
+ after the requested SID exists and the viewer reports its first rendered frame.
81
+ - Existing-server tunnel loads publish a pending SID before loading large files, so port resolution can overlap disk I/O. Pending metadata probes return immediately and the WebSocket waits on the shared pending-session event.
82
+ - Older ArrayView packages must not delete or downgrade a newer installed opener.
73
83
  - Tunnel registration cleanup must not remove live same-tunnel sibling windows.
74
84
  - Explicit cleanup wins over implicit disappearance.
75
85
  - Any VS Code extension source change must rebuild `src/arrayview/arrayview-opener.vsix` and keep the packaged version in sync.
@@ -7,7 +7,7 @@ triggers:
7
7
  - "recent work"
8
8
  - "active feature"
9
9
  - "shipped recently"
10
- last_updated: 2026-06-30
10
+ last_updated: 2026-07-20
11
11
  ---
12
12
 
13
13
  # Project State
@@ -20,8 +20,8 @@ last_updated: 2026-06-30
20
20
  - Rendering pipeline: colormaps, complex modes, mosaic, RGB/RGBA, projections, overlays
21
21
  - Backend transport: FastAPI HTTP/WebSocket is the single viewer transport; shared helpers keep route modules small for metadata/analysis, compare/diff, overlay compositing, and vector field layout/arrow sampling.
22
22
  - NIfTI spatial metadata, RAS resampling
23
- - Directory collections are header-scanned and lazy by default: compatible files form a dense virtual stack, mixed shapes use a ragged collection, and `--load lazy|eager` plus `--stack-policy auto|dense|ragged` make both choices explicit. Compressed NIfTI volumes use a byte-bounded LRU cache; `view_dir()` exposes the same controls.
24
- - VS Code extension v0.14.27 — stable window ID via `EnvironmentVariableCollection`; `arrayview.openInFloatingWindow` setting moves new tabs to a floating window; `view(arr, floating=True)` and `arrayview file.npy --floating` open in a floating window per-call regardless of global setting; remote/tunnel display uses the same forwarded HTTP/WebSocket path as local VS Code; floating mode uses a single persistent shell hub panel (`_shell.html`) so all arrays share one floating window as tabs instead of opening separate windows; second CLI calls inject tabs via `new_tab` postMessage relay (extension -> hub wrapper -> shell iframe)
23
+ - Directory collections are header-scanned and lazy by default: compatible files form a dense virtual stack, mixed shapes use a ragged collection, and `--load lazy|eager` plus `--stack-policy auto|dense|ragged` make both choices explicit. Supported 3D `.nii.gz` stacks now return the requested axial plane while the same one-pass decode finishes in the byte-bounded LRU cache; unsupported layouts fall back safely. Patient changes show a centered loading card until the matching frame arrives. `view_dir()` exposes the same collection controls.
24
+ - VS Code extension v0.14.43 — exact tunnel-window recovery from the terminal IPC hook, atomic cross-window request claims, non-loopback tunnel URL enforcement, queued concurrent requests, remote-only tunnel claims, live opener-version ACKs, first-frame readiness, and immediate local-backend session release. Successful port-public promotion is cached per external tunnel URL, and existing-server tunnel loads overlap port setup with pending background data loading.
25
25
  - Colorbar refactor: `ColorBar` JS class partially migrated (in progress)
26
26
  - 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
27
27
  - Cold-start loading spinner in VS Code and native shell
@@ -48,9 +48,10 @@ last_updated: 2026-06-30
48
48
  patient/modality directory layouts pair automatically. `--case-regex` remains
49
49
  an override for unusual layouts. CLI header scans show an in-place file counter
50
50
  and elapsed time on interactive terminals.
51
- - Reused collection sessions are protected by per-tab leases, including their
52
- overlay sessions, and VS Code opener readiness now verifies the requested
53
- session metadata before acknowledging `backend_ready`.
51
+ - Reused file and collection sessions are protected by per-tab leases, including
52
+ collection overlay sessions. The VS Code opener verifies the local SID before
53
+ creating a panel and waits for the viewer's first rendered frame before
54
+ acknowledging `backend_ready`.
54
55
  - Filesystem picker endpoint (`GET /fs/list`) clamped to `$HOME`. Accepts `base_sid` + `mode` (`overlay` | `vectorfield`) to filter entries by a cheap header-shape peek (`.npy`, `.nii`/`.nii.gz`, `.h5`, `.zarr`); overlay mode requires identical shape, vectorfield mode requires base shape plus one axis of size 3
55
56
  - Island collapse affordance: inline `~` at the island's top-right animates the panel into the bottom-left `~` hint circle; external `~` hint only visible while the island is actually collapsed. New `/` hint circle at bottom-right opens the tool menu
56
57
  - Compare center tool menu: `/` now re-opens the last-used compare center mode from the tool menu, while compare pane header buttons select diff / overlay / wipe directly. Eligible two-array compare layouts can switch into a big-left arrangement with a wider center pane, and the diff colorbar now matches that center-pane width.
@@ -59,6 +60,10 @@ last_updated: 2026-06-30
59
60
 
60
61
  ## Recently Completed
61
62
 
63
+ - Jupyter inline viewports automatically fit ortho content and restore the
64
+ normal `height` on exit. `mode_heights` remains available for explicit
65
+ overrides. Direct, proxied, multi-array, and IJulia inline paths share the
66
+ same mode-change bridge.
62
67
  - ROI keybind changed from `r` to `Shift+R` (`R`); rotate/flip is now `r`, transpose is `t`
63
68
  - Crossfade animation added to rotate/transpose transitions
64
69
  - `--version` flag and version string in help overlay
@@ -85,6 +90,7 @@ last_updated: 2026-06-30
85
90
 
86
91
  ## In Progress
87
92
 
93
+ - VS Code tunnel opener v0.14.43 is installed on disk and fully covered by focused lifecycle/ACK tests; active 0.14.42 extension hosts still need one window reload before post-change live timing and multi-window verification.
88
94
  - Smooth immersive transition — stale scrub geometry handoff is fixed, immersive overlay fade-in is held until after the class switch, shared slim colorbar returns through `drawSlimColorbar()` on reverse, and active scrub suppresses minimap/overflow/drag side effects. Single-pane scrub now targets the actual centered immersive viewport rect instead of a hardcoded corner box, the dimbar stays above the pane during scrub, the shared colorbar sits behind the growing pane, and the phantom extra `av-view-wrap` footprint in normal mode was removed by rebinding `NormalLayout` to the real `#viewer` canvas. Cross-mode parity and deeper reverse-pinch validation still need manual verification.
89
95
  - ROI + qMRI integration refinements: floodfill not yet supported on qMRI panes; per-pane stats are re-fetched on each ROI draw but not updated on slice scroll
90
96
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: arrayview
3
- Version: 0.31.2
3
+ Version: 0.32.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
@@ -51,7 +51,10 @@ Curious? Give it a try with
51
51
  uvx arrayview your_array.npy
52
52
  ```
53
53
 
54
+ Press `v` for the three-plane ortho view. `Shift+3` replaces the current slice,
55
+ or all three ortho panes, with interactive 3D cutaway renders.
56
+
54
57
 
55
58
  Check the [docs](https://oscarvanderheide.github.io/arrayview/) to learn more.
56
59
 
57
- **Warning**: Arrayview is still under active development. Things may break or change without warning.
60
+ **Warning**: Arrayview is still under active development. Things may break or change without warning.
@@ -15,7 +15,10 @@ Curious? Give it a try with
15
15
  uvx arrayview your_array.npy
16
16
  ```
17
17
 
18
+ Press `v` for the three-plane ortho view. `Shift+3` replaces the current slice,
19
+ or all three ortho panes, with interactive 3D cutaway renders.
20
+
18
21
 
19
22
  Check the [docs](https://oscarvanderheide.github.io/arrayview/) to learn more.
20
23
 
21
- **Warning**: Arrayview is still under active development. Things may break or change without warning.
24
+ **Warning**: Arrayview is still under active development. Things may break or change without warning.
@@ -30,6 +30,8 @@ MATLAB and Julia setup: [MATLAB and Julia](foreign-hosts.md).
30
30
 
31
31
  Remote and tunnel setup: [Remote](remote.md).
32
32
 
33
+ Stacked patient collections and masks: [Stack and Overlay Collections](stack-overlays.md).
34
+
33
35
  ## Formats
34
36
 
35
37
  `.npy` `.npz` `.nii` `.nii.gz` `.zarr` `.pt` `.h5` `.tif` `.mat`
@@ -54,6 +54,8 @@ Key parameters:
54
54
  | `name` | str | Label shown in the viewer tab |
55
55
  | `port` | int | Server port (default 8123 for Python API, 8000 for CLI) |
56
56
  | `window` | str \| None | How to open the viewer (see below) |
57
+ | `height` | int | Default inline notebook height in pixels |
58
+ | `mode_heights` | dict | Inline height overrides, e.g. `{"ortho": 360, "qmri": 480}` |
57
59
  | `rgb` | bool | Treat last/first axis as RGB/RGBA channels |
58
60
  | `overlay` | array or list | Arrays composited as overlays |
59
61
 
@@ -67,6 +69,9 @@ Key parameters:
67
69
  | `"vscode"` | VS Code tab |
68
70
  | `"inline"` | Inline IFrame (Jupyter / VS Code notebook) |
69
71
 
72
+ Inline ortho view automatically removes unused height. `mode_heights` is only
73
+ needed to override the automatic size.
74
+
70
75
  ## File Picker
71
76
 
72
77
  `Cmd/Ctrl+O` or `P` opens the file picker.
@@ -85,7 +90,7 @@ Native windows also show a static preview while the live viewer warms up.
85
90
  ```bash
86
91
  uvx arrayview base.npy moving.npy # compare mode
87
92
  uvx arrayview volume.nii.gz --overlay mask.nii.gz
88
- uvx arrayview volume.nii.gz --overlay "ground truth=mask.nii.gz"
93
+ uvx arrayview volume.nii.gz --overlay "ground truth=mask_gt.nii.gz" --overlay "prediction=mask_pred.nii.gz"
89
94
  ```
90
95
 
91
96
  An unnamed overlay uses the filename stem as its display name (`mask` above).
@@ -99,8 +104,7 @@ shows all overlays at once.
99
104
 
100
105
  ## Directory Pattern Collections
101
106
 
102
- Use `--stack` when reviewing many arrays. Passing a directory scans supported
103
- files recursively; passing patterns keeps the aligned channel/overlay workflow.
107
+ Use `--stack` when reviewing many arrays.
104
108
 
105
109
  ```bash
106
110
  uvx arrayview --stack scans/
@@ -115,53 +119,14 @@ dense` requires matching shapes, while `--stack-policy ragged` forces collection
115
119
  semantics. `--load eager` is intended for small datasets that should be loaded
116
120
  up front.
117
121
 
118
- Positional patterns become a channel/modality axis:
119
-
120
- ```bash
121
- uvx arrayview --stack "data/**/*_0000.nii.gz" "data/**/*_0001.nii.gz"
122
- ```
123
-
124
- Overlays become named recursive patterns:
122
+ Pattern collections, named overlays, multiple overlays, and `--overlay-dir`:
123
+ [Stack and Overlay Collections](stack-overlays.md).
125
124
 
126
- ```bash
127
- uvx arrayview --stack \
128
- "data/**/*_0000.nii.gz" \
129
- "data/**/*_0001.nii.gz" \
130
- --overlay "gt=data/**/labels/**/*.nii.gz" \
131
- --overlay "pred=data/**/pred/**/*.nii.gz"
132
- ```
125
+ ## NIfTI Series
133
126
 
134
- When every case has a directory containing separately named masks,
135
- `--overlay-dir` discovers one overlay role per filename. Masks that are absent
136
- for a case are shown as empty. ArrayView infers the shared case directory from
137
- layouts such as `sub-0001/T1_W/` and `sub-0001/masks/`:
138
-
139
- ```bash
140
- uvx arrayview --stack "data/*/T1_W/*.nii.gz" \
141
- --overlay-dir "data/*/masks"
142
- ```
143
-
144
- Repeat `--overlay-dir` to combine masks from multiple per-case directories.
145
-
146
- ArrayView pairs files by sorted match order. The first match from each pattern
147
- belongs to the first case, the second match belongs to the second case, and so
148
- on. Use `--dry-run` to inspect matches without opening a viewer.
149
-
150
- ```bash
151
- uvx arrayview --stack "data/**/*_0000.nii.gz" --overlay "gt=data/**/labels/*.nii.gz" --dry-run
152
- ```
153
-
154
- For unusual or ambiguous layouts, pass a regex with a `case` group to override
155
- automatic directory inference:
156
-
157
- ```bash
158
- uvx arrayview --stack "data/**/*.nii.gz" --case-regex "(?P<case>patient-[0-9]+)"
159
- ```
160
-
161
- ## NIfTI Series (4D/5D from a directory)
162
-
163
- Stack a directory of NIfTI files into a single lazy 4D/5D array — only the
164
- viewed slice is loaded, so RAM stays bounded regardless of series size.
127
+ Stack a directory of NIfTI files into a single lazy 4D/5D array. Patient files
128
+ are loaded only when needed, and the memory cache stays bounded regardless of
129
+ series size.
165
130
 
166
131
  ```bash
167
132
  uvx arrayview patients/
@@ -173,27 +138,32 @@ Discovers `.nii`/`.nii.gz` recursively, groups by immediate parent folder
173
138
  One file per patient → 4D `(*vol, P)`. The viewer opens with X/Y on screen,
174
139
  Z as primary scroll, patient index as a slider.
175
140
 
176
- Multiple files per patient (e.g. `t1`, `t2`, `flair`) → use `--select`:
141
+ For multiple files per patient, use explicit `--stack` patterns:
177
142
 
178
143
  ```bash
179
- uvx arrayview patients/ --select '*t1*' --select '*t2*' --select '*flair*'
144
+ uvx arrayview --stack \
145
+ "patients/*/*t1*.nii.gz" \
146
+ "patients/*/*t2*.nii.gz" \
147
+ "patients/*/*flair*.nii.gz"
180
148
  ```
181
149
 
182
- Each `--select` pattern picks one file per patient (fnmatch on basename).
183
- Produces 5D `(*vol, P, M)` with modality as the last axis. Every patient
184
- must match exactly one file per pattern.
150
+ More examples: [Stack and Overlay Collections](stack-overlays.md).
185
151
 
186
- Python API:
152
+ Patient folders with no NIfTI files (e.g. only `.dcm`) raise an error —
153
+ convert DICOM to NIfTI first (e.g. `dcm2niix`).
187
154
 
188
- ```python
189
- from arrayview import view_dir
155
+ ### First image from compressed patients
190
156
 
191
- view_dir("patients/")
192
- view_dir("patients/", select=["*t1*", "*t2*", "*flair*"])
193
- ```
157
+ For a normal 3D `.nii.gz` patient, ArrayView shows the requested axial slice as
158
+ soon as that slice has been unpacked. It keeps unpacking the rest of the same
159
+ file in the background and saves the completed volume in the existing memory
160
+ cache. The file is not unpacked a second time.
194
161
 
195
- Patient folders with no NIfTI files (e.g. only `.dcm`) raise an error —
196
- convert DICOM to NIfTI first (e.g. `dcm2niix`).
162
+ This shortens the visible wait, but it does not make gzip random-access. A slice
163
+ near the middle still requires reading roughly the first half of the file.
164
+ Side views, 4D files, and unusual orientations fall back to loading the complete
165
+ volume first so their data remains correct. Moving quickly between patients
166
+ stops outdated background work instead of building a long loading queue.
197
167
 
198
168
  ## Zarr
199
169
 
@@ -0,0 +1,129 @@
1
+ # Stack and Overlay Collections
2
+
3
+ Review many arrays with aligned image and mask patterns.
4
+
5
+ ## Patient Stack
6
+
7
+ ```bash
8
+ uvx arrayview --stack "data/*/T1w.nii.gz"
9
+ ```
10
+
11
+ `*` matches one path segment. `**` matches recursively:
12
+
13
+ ```bash
14
+ uvx arrayview --stack "data/**/*.nii.gz"
15
+ ```
16
+
17
+ ArrayView sorts matches and adds a collection index dimension. Use `--dry-run`
18
+ to inspect pairings without opening the viewer:
19
+
20
+ ```bash
21
+ uvx arrayview --stack "data/*/T1w.nii.gz" --dry-run
22
+ ```
23
+
24
+ ## MR Contrasts
25
+
26
+ ```bash
27
+ uvx arrayview --stack \
28
+ "data/*/T1w.nii.gz" \
29
+ "data/*/T2w.nii.gz" \
30
+ "data/*/FLAIR.nii.gz"
31
+ ```
32
+
33
+ Each positional pattern becomes a contrast dimension. The first `T1w`, first
34
+ `T2w`, and first `FLAIR` belong to patient 1; the second match from each pattern
35
+ belongs to patient 2.
36
+
37
+ For ambiguous layouts, define the patient key:
38
+
39
+ ```bash
40
+ uvx arrayview --stack "data/**/*.nii.gz" \
41
+ --case-regex "(?P<case>sub-[0-9]+)"
42
+ ```
43
+
44
+ ## Ragged Shapes
45
+
46
+ ```bash
47
+ uvx arrayview --stack "data/*/T1w.nii.gz" --stack-policy ragged
48
+ ```
49
+
50
+ `--stack-policy auto` uses a dense stack when shapes match and ragged mode when
51
+ they do not. `--stack-policy dense` requires matching shapes.
52
+
53
+ ## One Overlay
54
+
55
+ ```bash
56
+ uvx arrayview --stack "data/*/T1w.nii.gz" \
57
+ --overlay "lesion=data/*/masks/lesion.nii.gz"
58
+ ```
59
+
60
+ Use `name=pattern` to control the overlay label. Without `name=`, the filename
61
+ stem is used.
62
+
63
+ ## Multiple Overlays
64
+
65
+ ```bash
66
+ uvx arrayview --stack "data/*/T1w.nii.gz" \
67
+ --overlay "gt=data/*/masks/gt.nii.gz" \
68
+ --overlay "pred=data/*/masks/pred.nii.gz"
69
+ ```
70
+
71
+ Overlays are paired to cases by sorted match order unless `--case-regex` is
72
+ provided.
73
+
74
+ ## Overlay Directories
75
+
76
+ ```bash
77
+ uvx arrayview --stack "data/*/T1w.nii.gz" \
78
+ --overlay-dir "data/*/masks"
79
+ ```
80
+
81
+ `--overlay-dir` creates one overlay role per mask filename inside each matched
82
+ directory. Missing masks are shown as empty overlays.
83
+
84
+ Repeat it to combine mask folders:
85
+
86
+ ```bash
87
+ uvx arrayview --stack "data/*/T1w.nii.gz" \
88
+ --overlay-dir "data/*/manual_masks" \
89
+ --overlay-dir "data/*/model_masks"
90
+ ```
91
+
92
+ ## Complete Example
93
+
94
+ ```text
95
+ data/
96
+ sub-001/
97
+ anat/T1w.nii.gz
98
+ anat/T2w.nii.gz
99
+ masks/lesion.nii.gz
100
+ masks/edema.nii.gz
101
+ sub-002/
102
+ anat/T1w.nii.gz
103
+ anat/T2w.nii.gz
104
+ masks/lesion.nii.gz
105
+ ```
106
+
107
+ ```bash
108
+ uvx arrayview --stack \
109
+ "data/*/anat/T1w.nii.gz" \
110
+ "data/*/anat/T2w.nii.gz" \
111
+ --overlay-dir "data/*/masks" \
112
+ --stack-policy auto \
113
+ --dry-run
114
+ ```
115
+
116
+ Remove `--dry-run` to open the viewer.
117
+
118
+ ## Compressed NIfTI Performance
119
+
120
+ `.nii.gz` files are lazy through nibabel, but gzip compression limits random
121
+ slice access. Large compressed collections can feel slower when scrolling across
122
+ many patients or contrasts.
123
+
124
+ For repeated review, prefer uncompressed `.nii`, chunked `.zarr`, or a local
125
+ fast disk cache. Use `--load eager` only for small collections that fit in RAM:
126
+
127
+ ```bash
128
+ uvx arrayview --stack "data/*/T1w.nii.gz" --load eager
129
+ ```
@@ -24,6 +24,7 @@ extra_css:
24
24
  nav:
25
25
  - Home: index.md
26
26
  - Loading Arrays: loading.md
27
+ - Stack and Overlays: stack-overlays.md
27
28
  - Viewing: viewing.md
28
29
  - Comparing: comparing.md
29
30
  - Display: display.md
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "arrayview"
7
- version = "0.31.2"
7
+ version = "0.32.0"
8
8
  description = "Fast multi-dimensional array viewer"
9
9
  readme = { file = "README.md", content-type = "text/markdown" }
10
10
  requires-python = ">=3.12"
@@ -7,14 +7,12 @@ __all__ = [
7
7
  "arrayview",
8
8
  "view",
9
9
  "view_batch",
10
- "view_dir",
11
- "view_dir_patterns",
12
10
  "zarr_chunk_preset",
13
11
  ]
14
12
 
15
13
 
16
14
  def __getattr__(name: str):
17
- if name in {"arrayview", "view", "view_dir", "view_dir_patterns", "ViewHandle"}:
15
+ if name in {"arrayview", "view", "ViewHandle"}:
18
16
  from arrayview import _launcher
19
17
 
20
18
  return getattr(_launcher, name)