arrayview 0.22.0__tar.gz → 0.23.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 (205) hide show
  1. {arrayview-0.22.0 → arrayview-0.23.0}/.mex/AGENTS.md +1 -1
  2. {arrayview-0.22.0 → arrayview-0.23.0}/.mex/ROUTER.md +1 -1
  3. {arrayview-0.22.0 → arrayview-0.23.0}/.mex/SETUP.md +2 -0
  4. {arrayview-0.22.0 → arrayview-0.23.0}/.mex/SYNC.md +2 -0
  5. {arrayview-0.22.0 → arrayview-0.23.0}/.mex/context/conventions.md +1 -1
  6. {arrayview-0.22.0 → arrayview-0.23.0}/.mex/context/decisions.md +1 -1
  7. {arrayview-0.22.0 → arrayview-0.23.0}/.mex/context/frontend.md +1 -1
  8. {arrayview-0.22.0 → arrayview-0.23.0}/.mex/context/project-state.md +7 -2
  9. {arrayview-0.22.0 → arrayview-0.23.0}/.mex/context/render-pipeline.md +1 -1
  10. {arrayview-0.22.0 → arrayview-0.23.0}/.mex/context/setup.md +1 -1
  11. {arrayview-0.22.0 → arrayview-0.23.0}/.mex/context/stack.md +1 -1
  12. {arrayview-0.22.0 → arrayview-0.23.0}/.mex/patterns/INDEX.md +1 -0
  13. {arrayview-0.22.0 → arrayview-0.23.0}/.mex/patterns/README.md +2 -0
  14. {arrayview-0.22.0 → arrayview-0.23.0}/.mex/patterns/add-file-format.md +1 -1
  15. {arrayview-0.22.0 → arrayview-0.23.0}/.mex/patterns/add-server-endpoint.md +1 -1
  16. {arrayview-0.22.0 → arrayview-0.23.0}/.mex/patterns/animation-verify.md +1 -1
  17. {arrayview-0.22.0 → arrayview-0.23.0}/.mex/patterns/debug-render.md +1 -1
  18. {arrayview-0.22.0 → arrayview-0.23.0}/.mex/patterns/debug-vscode-extension-python.md +5 -5
  19. arrayview-0.23.0/.mex/patterns/extend-compare-mode.md +60 -0
  20. {arrayview-0.22.0 → arrayview-0.23.0}/.mex/patterns/extract-server-route-module.md +1 -1
  21. {arrayview-0.22.0 → arrayview-0.23.0}/.mex/patterns/frontend-change.md +1 -1
  22. {arrayview-0.22.0 → arrayview-0.23.0}/CONTRIBUTING.md +2 -2
  23. {arrayview-0.22.0 → arrayview-0.23.0}/PKG-INFO +11 -15
  24. arrayview-0.23.0/README.md +21 -0
  25. {arrayview-0.22.0 → arrayview-0.23.0}/docs/display.md +1 -1
  26. {arrayview-0.22.0 → arrayview-0.23.0}/pyproject.toml +1 -1
  27. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_config.py +1 -1
  28. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_diff.py +12 -3
  29. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_routes_rendering.py +8 -0
  30. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_routes_segmentation.py +270 -59
  31. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_server.py +1 -1
  32. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_stdio_server.py +7 -1
  33. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_viewer.html +1843 -609
  34. {arrayview-0.22.0 → arrayview-0.23.0}/tests/test_api.py +212 -0
  35. {arrayview-0.22.0 → arrayview-0.23.0}/tests/test_browser.py +195 -13
  36. {arrayview-0.22.0 → arrayview-0.23.0}/tests/test_colorbar_hover_highlight.py +31 -0
  37. {arrayview-0.22.0 → arrayview-0.23.0}/tests/ui_audit.py +1 -9
  38. {arrayview-0.22.0 → arrayview-0.23.0}/tests/visual_smoke.py +0 -4
  39. {arrayview-0.22.0 → arrayview-0.23.0}/uv.lock +1 -1
  40. arrayview-0.22.0/README.md +0 -25
  41. {arrayview-0.22.0 → arrayview-0.23.0}/.agents/skills/frontend-designer/SKILL.md +0 -0
  42. {arrayview-0.22.0 → arrayview-0.23.0}/.agents/skills/invocation-consistency/SKILL.md +0 -0
  43. {arrayview-0.22.0 → arrayview-0.23.0}/.agents/skills/modes-consistency/SKILL.md +0 -0
  44. {arrayview-0.22.0 → arrayview-0.23.0}/.agents/skills/playwright-cli/SKILL.md +0 -0
  45. {arrayview-0.22.0 → arrayview-0.23.0}/.agents/skills/playwright-cli/references/element-attributes.md +0 -0
  46. {arrayview-0.22.0 → arrayview-0.23.0}/.agents/skills/playwright-cli/references/playwright-tests.md +0 -0
  47. {arrayview-0.22.0 → arrayview-0.23.0}/.agents/skills/playwright-cli/references/request-mocking.md +0 -0
  48. {arrayview-0.22.0 → arrayview-0.23.0}/.agents/skills/playwright-cli/references/running-code.md +0 -0
  49. {arrayview-0.22.0 → arrayview-0.23.0}/.agents/skills/playwright-cli/references/session-management.md +0 -0
  50. {arrayview-0.22.0 → arrayview-0.23.0}/.agents/skills/playwright-cli/references/storage-state.md +0 -0
  51. {arrayview-0.22.0 → arrayview-0.23.0}/.agents/skills/playwright-cli/references/test-generation.md +0 -0
  52. {arrayview-0.22.0 → arrayview-0.23.0}/.agents/skills/playwright-cli/references/tracing.md +0 -0
  53. {arrayview-0.22.0 → arrayview-0.23.0}/.agents/skills/playwright-cli/references/video-recording.md +0 -0
  54. {arrayview-0.22.0 → arrayview-0.23.0}/.agents/skills/todo-workflow/SKILL.md +0 -0
  55. {arrayview-0.22.0 → arrayview-0.23.0}/.agents/skills/ui-consistency-audit/SKILL.md +0 -0
  56. {arrayview-0.22.0 → arrayview-0.23.0}/.agents/skills/viewer-ui-checklist/SKILL.md +0 -0
  57. {arrayview-0.22.0 → arrayview-0.23.0}/.agents/skills/visual-bug-fixing/SKILL.md +0 -0
  58. {arrayview-0.22.0 → arrayview-0.23.0}/.github/copilot-instructions.md +0 -0
  59. {arrayview-0.22.0 → arrayview-0.23.0}/.github/workflows/docs.yml +0 -0
  60. {arrayview-0.22.0 → arrayview-0.23.0}/.github/workflows/python-publish.yml +0 -0
  61. {arrayview-0.22.0 → arrayview-0.23.0}/.gitignore +0 -0
  62. {arrayview-0.22.0 → arrayview-0.23.0}/.ignore +0 -0
  63. {arrayview-0.22.0 → arrayview-0.23.0}/.mex/context/architecture.md +0 -0
  64. {arrayview-0.22.0 → arrayview-0.23.0}/.mex/setup.sh +0 -0
  65. {arrayview-0.22.0 → arrayview-0.23.0}/.mex/sync.sh +0 -0
  66. {arrayview-0.22.0 → arrayview-0.23.0}/.opencode/opencode.json +0 -0
  67. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-06T18-46-49-737Z.yml +0 -0
  68. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-06T18-48-21-979Z.yml +0 -0
  69. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-06T18-51-35-665Z.yml +0 -0
  70. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-06T19-07-01-393Z.yml +0 -0
  71. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-06T19-14-37-969Z.yml +0 -0
  72. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-06T19-21-30-940Z.yml +0 -0
  73. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-06T19-23-08-126Z.yml +0 -0
  74. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-06T19-29-33-155Z.yml +0 -0
  75. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-06T19-31-25-336Z.yml +0 -0
  76. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-06T19-31-53-789Z.yml +0 -0
  77. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-06T19-39-12-257Z.yml +0 -0
  78. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-06T19-39-16-449Z.yml +0 -0
  79. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-06T20-15-25-513Z.yml +0 -0
  80. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-06T20-25-13-179Z.yml +0 -0
  81. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-06T20-39-01-435Z.yml +0 -0
  82. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-06T21-01-27-659Z.yml +0 -0
  83. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-06T21-01-41-283Z.yml +0 -0
  84. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-06T21-03-00-625Z.yml +0 -0
  85. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-06T21-04-12-887Z.yml +0 -0
  86. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-06T21-33-39-044Z.yml +0 -0
  87. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-06T21-38-01-530Z.yml +0 -0
  88. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-06T21-45-20-383Z.yml +0 -0
  89. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-06T21-55-11-545Z.yml +0 -0
  90. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-06T21-56-03-307Z.yml +0 -0
  91. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-06T21-56-35-733Z.yml +0 -0
  92. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-06T21-57-12-181Z.yml +0 -0
  93. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-06T21-57-37-748Z.yml +0 -0
  94. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-06T21-58-13-679Z.yml +0 -0
  95. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-06T22-37-23-895Z.yml +0 -0
  96. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-07T00-39-18-637Z.yml +0 -0
  97. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-07T01-41-46-243Z.yml +0 -0
  98. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-07T04-31-48-472Z.yml +0 -0
  99. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-07T12-14-15-632Z.yml +0 -0
  100. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-07T12-14-47-582Z.yml +0 -0
  101. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-07T12-16-23-471Z.yml +0 -0
  102. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-07T12-17-10-247Z.yml +0 -0
  103. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-07T12-18-24-707Z.yml +0 -0
  104. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-07T12-20-06-164Z.yml +0 -0
  105. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-07T12-20-28-342Z.yml +0 -0
  106. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-07T12-21-54-962Z.yml +0 -0
  107. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-07T12-22-34-666Z.yml +0 -0
  108. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-07T12-23-11-336Z.yml +0 -0
  109. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-07T12-23-36-260Z.yml +0 -0
  110. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-07T12-24-09-267Z.yml +0 -0
  111. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-07T12-24-35-434Z.yml +0 -0
  112. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-07T12-25-57-010Z.yml +0 -0
  113. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-07T12-34-48-823Z.yml +0 -0
  114. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-07T12-46-46-468Z.yml +0 -0
  115. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-07T12-48-17-930Z.yml +0 -0
  116. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-07T12-49-26-400Z.yml +0 -0
  117. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-07T12-50-31-563Z.yml +0 -0
  118. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/page-2026-05-07T12-56-45-568Z.yml +0 -0
  119. {arrayview-0.22.0 → arrayview-0.23.0}/.playwright-cli/theme-dark.yml +0 -0
  120. {arrayview-0.22.0 → arrayview-0.23.0}/.python-version +0 -0
  121. {arrayview-0.22.0 → arrayview-0.23.0}/.vscode/settings.json +0 -0
  122. {arrayview-0.22.0 → arrayview-0.23.0}/AGENTS.md +0 -0
  123. {arrayview-0.22.0 → arrayview-0.23.0}/DESIGN.md +0 -0
  124. {arrayview-0.22.0 → arrayview-0.23.0}/LICENSE +0 -0
  125. {arrayview-0.22.0 → arrayview-0.23.0}/docs/comparing.md +0 -0
  126. {arrayview-0.22.0 → arrayview-0.23.0}/docs/configuration.md +0 -0
  127. {arrayview-0.22.0 → arrayview-0.23.0}/docs/index.md +0 -0
  128. {arrayview-0.22.0 → arrayview-0.23.0}/docs/loading.md +0 -0
  129. {arrayview-0.22.0 → arrayview-0.23.0}/docs/logo.png +0 -0
  130. {arrayview-0.22.0 → arrayview-0.23.0}/docs/measurement.md +0 -0
  131. {arrayview-0.22.0 → arrayview-0.23.0}/docs/remote.md +0 -0
  132. {arrayview-0.22.0 → arrayview-0.23.0}/docs/stylesheets/extra.css +0 -0
  133. {arrayview-0.22.0 → arrayview-0.23.0}/docs/viewing.md +0 -0
  134. {arrayview-0.22.0 → arrayview-0.23.0}/matlab/arrayview.m +0 -0
  135. {arrayview-0.22.0 → arrayview-0.23.0}/mkdocs.yml +0 -0
  136. {arrayview-0.22.0 → arrayview-0.23.0}/plans/2026-04-14-immersive-animation.md +0 -0
  137. {arrayview-0.22.0 → arrayview-0.23.0}/plans/2026-05-07-unified-colormap-picker.md +0 -0
  138. {arrayview-0.22.0 → arrayview-0.23.0}/plans/arrayview_tool_menu_fix_prompt.md +0 -0
  139. {arrayview-0.22.0 → arrayview-0.23.0}/plans/arrayview_tool_menu_implementation_plan.md +0 -0
  140. {arrayview-0.22.0 → arrayview-0.23.0}/plans/egg-placement-mockup.html +0 -0
  141. {arrayview-0.22.0 → arrayview-0.23.0}/plans/refactoring_plan.md +0 -0
  142. {arrayview-0.22.0 → arrayview-0.23.0}/plans/webview/LOG.md +0 -0
  143. {arrayview-0.22.0 → arrayview-0.23.0}/scripts/demo.py +0 -0
  144. {arrayview-0.22.0 → arrayview-0.23.0}/scripts/release.sh +0 -0
  145. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/ARCHITECTURE.md +0 -0
  146. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/__init__.py +0 -0
  147. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/__main__.py +0 -0
  148. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_analysis.py +0 -0
  149. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_app.py +0 -0
  150. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_codex_open.py +0 -0
  151. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_icon.png +0 -0
  152. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_imaging.py +0 -0
  153. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_io.py +0 -0
  154. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_launcher.py +0 -0
  155. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_overlays.py +0 -0
  156. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_platform.py +0 -0
  157. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_render.py +0 -0
  158. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_routes_analysis.py +0 -0
  159. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_routes_export.py +0 -0
  160. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_routes_loading.py +0 -0
  161. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_routes_persistence.py +0 -0
  162. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_routes_preload.py +0 -0
  163. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_routes_query.py +0 -0
  164. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_routes_state.py +0 -0
  165. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_routes_vectorfield.py +0 -0
  166. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_routes_websocket.py +0 -0
  167. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_segmentation.py +0 -0
  168. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_session.py +0 -0
  169. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_shell.html +0 -0
  170. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_synthetic_mri.py +0 -0
  171. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_torch.py +0 -0
  172. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_vectorfield.py +0 -0
  173. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_vscode.py +0 -0
  174. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_vscode_browser.py +0 -0
  175. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_vscode_extension.py +0 -0
  176. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_vscode_shm.py +0 -0
  177. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/_vscode_signal.py +0 -0
  178. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/arrayview-opener.vsix +0 -0
  179. {arrayview-0.22.0 → arrayview-0.23.0}/src/arrayview/gsap.min.js +0 -0
  180. {arrayview-0.22.0 → arrayview-0.23.0}/tests/capture_v_animation.py +0 -0
  181. {arrayview-0.22.0 → arrayview-0.23.0}/tests/conftest.py +0 -0
  182. {arrayview-0.22.0 → arrayview-0.23.0}/tests/make_vectorfield_test_arrays.py +0 -0
  183. {arrayview-0.22.0 → arrayview-0.23.0}/tests/test_backend_shared.py +0 -0
  184. {arrayview-0.22.0 → arrayview-0.23.0}/tests/test_cli.py +0 -0
  185. {arrayview-0.22.0 → arrayview-0.23.0}/tests/test_command_reachability.py +0 -0
  186. {arrayview-0.22.0 → arrayview-0.23.0}/tests/test_config.py +0 -0
  187. {arrayview-0.22.0 → arrayview-0.23.0}/tests/test_cross_mode_parametrized.py +0 -0
  188. {arrayview-0.22.0 → arrayview-0.23.0}/tests/test_interactions.py +0 -0
  189. {arrayview-0.22.0 → arrayview-0.23.0}/tests/test_large_arrays.py +0 -0
  190. {arrayview-0.22.0 → arrayview-0.23.0}/tests/test_loading_server.py +0 -0
  191. {arrayview-0.22.0 → arrayview-0.23.0}/tests/test_mode_consistency.py +0 -0
  192. {arrayview-0.22.0 → arrayview-0.23.0}/tests/test_mode_entry_batching.py +0 -0
  193. {arrayview-0.22.0 → arrayview-0.23.0}/tests/test_mode_matrix.py +0 -0
  194. {arrayview-0.22.0 → arrayview-0.23.0}/tests/test_mode_roundtrip.py +0 -0
  195. {arrayview-0.22.0 → arrayview-0.23.0}/tests/test_nifti_meta.py +0 -0
  196. {arrayview-0.22.0 → arrayview-0.23.0}/tests/test_rgb_pixel_art.py +0 -0
  197. {arrayview-0.22.0 → arrayview-0.23.0}/tests/test_stdio_server.py +0 -0
  198. {arrayview-0.22.0 → arrayview-0.23.0}/tests/test_torch.py +0 -0
  199. {arrayview-0.22.0 → arrayview-0.23.0}/tests/test_view_component_integration.py +0 -0
  200. {arrayview-0.22.0 → arrayview-0.23.0}/tests/test_view_component_unit.py +0 -0
  201. {arrayview-0.22.0 → arrayview-0.23.0}/tests/v_anim_frames/.gitkeep +0 -0
  202. {arrayview-0.22.0 → arrayview-0.23.0}/vscode-extension/AGENTS.md +0 -0
  203. {arrayview-0.22.0 → arrayview-0.23.0}/vscode-extension/LICENSE +0 -0
  204. {arrayview-0.22.0 → arrayview-0.23.0}/vscode-extension/extension.js +0 -0
  205. {arrayview-0.22.0 → arrayview-0.23.0}/vscode-extension/package.json +0 -0
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: agents
3
3
  description: Lightweight pointer to ROUTER.md for task routing.
4
- last_updated: 2026-05-01
4
+ last_updated: 2026-05-16
5
5
  ---
6
6
 
7
7
  # arrayview
@@ -22,7 +22,7 @@ edges:
22
22
  condition: when starting a task — check the pattern index for a matching pattern file
23
23
  - target: ../DESIGN.md
24
24
  condition: when the task touches design philosophy — new features, UI changes, mode additions, or interaction model decisions
25
- last_updated: 2026-05-02
25
+ last_updated: 2026-05-16
26
26
  ---
27
27
 
28
28
  # arrayview — Router
@@ -1,5 +1,7 @@
1
1
  # Setup — Populate This Scaffold
2
2
 
3
+ Last reviewed: 2026-05-16
4
+
3
5
  This file contains the prompts to populate the scaffold. It is NOT the dev environment setup — for that, see `context/setup.md` after population.
4
6
 
5
7
  This scaffold is currently empty. Follow the steps below to populate it for your project.
@@ -1,5 +1,7 @@
1
1
  # Sync — Realign This Scaffold
2
2
 
3
+ Last reviewed: 2026-05-16
4
+
3
5
  ## Recommended: Use sync.sh
4
6
 
5
7
  ```bash
@@ -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-04-29
21
+ last_updated: 2026-05-16
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-04-29
17
+ last_updated: 2026-05-16
18
18
  ---
19
19
 
20
20
  # Decisions
@@ -18,7 +18,7 @@ edges:
18
18
  condition: when writing new frontend code and need section separator conventions
19
19
  - target: patterns/frontend-change.md
20
20
  condition: when making a concrete change to _viewer.html
21
- last_updated: 2026-05-01
21
+ last_updated: 2026-05-16
22
22
  ---
23
23
 
24
24
  # Frontend (_viewer.html)
@@ -7,7 +7,7 @@ triggers:
7
7
  - "recent work"
8
8
  - "active feature"
9
9
  - "shipped recently"
10
- last_updated: 2026-05-11
10
+ last_updated: 2026-05-13
11
11
  ---
12
12
 
13
13
  # Project State
@@ -36,12 +36,17 @@ last_updated: 2026-05-11
36
36
  - 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
37
37
  - 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.
38
38
  - Compare center + ortho auto-layout: layout choice is now auto-picked once on entry from a shared viewport-profile helper, stays stable across resize, and becomes sticky only after manual `G` / `g` override. Compare big-left also now supports in-pane A/B source badges and a shared source colorbar parked in the gap between the stacked source panes.
39
+ - Detached compare-on-X: with a single array and a non-spatial active dimension, `X` now enters compare mode by treating two indices from that dimension as A/B sources. Pane titles switch to index-over-total labels, the dimbar marks the detached dimension with a purple `X`, `[` / `]` scrub the left pane index, `{` / `}` scrub the right pane index, and repeated `X` presses cycle the existing compare-center modes before exiting back to normal view. The split-index diff path now works in both FastAPI and stdio transports.
39
40
 
40
41
  ## Recently Completed
41
42
 
43
+ - Shift+C colormap picker redesign: the old centered shortlist is now a narrow translucent right-edge drawer with a close button, a yellow `Colormaps` title plus a `Favorites` subtitle, and a plain 12-swatch two-column quick set that stays visible above the search field. Search matches render in a separate results area below the input, Enter first exits the search field before a second Enter commits, arrow-key movement follows the visible two-column grid, and repeated `c` presses cycle through the currently visible swatches while the picker is open.
44
+ - Detached compare-on-X: single-array non-spatial dimensions now support the same compare-center family as two-array compare. The frontend reuses compare mode with per-pane detached indices, the dimbar shows a purple `X`, the compare titles show index-over-total labels, `[` / `]` control pane A, `{` / `}` control pane B, and repeated `X` exits detached compare after cycling the center modes. Focused coverage now includes a browser regression for detached entry/scrubbing/exit plus API coverage for split `/diff` indices on the same session.
45
+ - Normal-mode dimbar readability: inactive non-spatial dims no longer get a blanket reduced parent opacity, so the current index reads bright while `/total` stays subdued via the existing child dim-size styling.
46
+ - Multiview colorbar spacing now matches normal mode: entering ortho with `v` and switching to orthogonal `big-left` with `g` no longer increases the pane-to-colorbar gap. Focused browser coverage now compares the normal-view gap against both multiview layouts directly.
42
47
  - V-mode ortho layout cycling is now a two-state toggle: `g` only switches between `horizontal` and `big-left`. The old `vertical` and `big-top` multiview presets have been removed from the shared ortho preset table, the hold-`g` picker/help text, and the remaining big-pane promotion branches, and the shared multiview colorbar width now stays fixed when `g` toggles between the two surviving layouts.
43
48
  - The old snapshot gallery sidecar has been removed from the viewer. Saving a screenshot still downloads the PNG, but `Shift+G` no longer toggles any screenshot/gallery UI outside compare mode; `G` is now compare-layout cycling only.
44
- - Loupe activation no longer arms on a plain left-button hold. Normal view and multiview panes now use `Ctrl` hover with no mouse button, so plain drag stays available for pane navigation and other mode-specific gestures. While `Ctrl` is held, wheel input keeps its normal slice-scroll behavior instead of being swallowed or repurposed for zoom, and the loupe now redraws when those wheel-driven slice changes land. Focused browser coverage now checks both the normal-view and multiview `Ctrl` hover paths plus `Ctrl`-wheel scrolling and loupe-refresh behavior. qMRI loupe wiring was updated to match, but direct qMRI browser validation is currently blocked by an existing `q`-mode entry failure in `tests/test_browser.py::TestKeyboard::test_reusable_url_restores_qmri_mode`.
49
+ - Loupe activation no longer arms on a plain left-button hold. Normal view and multiview panes now use `Ctrl` hover with no mouse button, so plain drag stays available for pane navigation and other mode-specific gestures. While `Ctrl` is held, wheel input keeps its normal slice-scroll behavior instead of being swallowed or repurposed for zoom, and the loupe now redraws when those wheel-driven slice changes land. Focused browser coverage now checks both the normal-view and multiview `Ctrl` hover paths plus `Ctrl`-wheel scrolling and loupe-refresh behavior. qMRI loupe wiring was updated to match, but direct qMRI browser validation is currently blocked by the qMRI reusable-URL browser test in `tests/test_browser.py`.
45
50
  - Jupyter inline notebooks now default to `height=600`, start in normal mode instead of auto-immersive, and top-align the viewer cluster instead of vertically centering it inside the output cell. This removes the wasted band above the dimbar / below the colorbar while preserving manual `Shift+F` immersive entry. Browser coverage now checks the non-immersive inline start state and low wrapper top padding.
46
51
  - Architecture followthrough: `_server.py` route extraction is complete. Feature domains now live in `_routes_analysis.py`, `_routes_loading.py`, `_routes_persistence.py`, `_routes_segmentation.py`, `_routes_state.py`, `_routes_query.py`, `_routes_export.py`, `_routes_preload.py`, `_routes_vectorfield.py`, `_routes_rendering.py`, and `_routes_websocket.py`. `_server.py` is now the intended assembly surface: FastAPI app setup, shared dependency injection, HTML/template helpers, and the small infrastructure routes for health/UI/assets/colormap metadata.
47
52
  - Focused API coverage now directly guards segmentation activate/scribble/click-accept/export paths, export/preload/vectorfield routes, slice/projection/diff/grid/gif rendering, large-array grid/gif guardrails, and websocket metadata plus shell-close cleanup.
@@ -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-04-29
23
+ last_updated: 2026-05-16
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-04-29
16
+ last_updated: 2026-05-16
17
17
  ---
18
18
 
19
19
  # Setup
@@ -50,7 +50,7 @@ last_updated: 2026-04-29
50
50
  - **No concurrent.futures for the render thread** — uses `threading.Thread` + `SimpleQueue` directly to avoid CPython's `_global_shutdown` executor cleanup racing with daemon threads during interpreter exit.
51
51
  - **No ORM / database** — sessions are in-memory Python dicts; no SQLAlchemy, no SQLite.
52
52
  - **No Redux or client-side state management library** — viewer state is plain JS variables in `_viewer.html`.
53
- - **No CSS framework** — all styles are custom properties in `:root`; the shipped themes are dark, light, solarized, and nord.
53
+ - **No CSS framework** — all styles are custom properties in `:root`; the shipped themes are dark and light.
54
54
 
55
55
  ## Version Constraints
56
56
 
@@ -28,5 +28,6 @@ Lookup table for all pattern files in this directory. Check here before starting
28
28
  | [add-server-endpoint.md](add-server-endpoint.md) | Adding a new REST or WebSocket route to `_server.py` |
29
29
  | [debug-vscode-extension-python.md](debug-vscode-extension-python.md) | Diagnosing VS Code custom-editor failures caused by Python selection, workspace virtualenv drift, or uv fallback behavior |
30
30
  | [debug-render.md](debug-render.md) | Visual rendering failures — wrong colors, blank canvas, artifacts, colormap issues |
31
+ | [extend-compare-mode.md](extend-compare-mode.md) | Extending compare mode in `_viewer.html`, including new compare entry paths, pane labels, or per-pane diff/render state |
31
32
  | [extract-server-route-module.md](extract-server-route-module.md) | Moving an existing route cluster out of `_server.py` into a dedicated `_routes_*.py` module |
32
33
  | [frontend-change.md](frontend-change.md) | Any change to `_viewer.html` — CSS, JS, new mode, keybind, layout, colorbar |
@@ -1,5 +1,7 @@
1
1
  # Patterns
2
2
 
3
+ Last reviewed: 2026-05-16
4
+
3
5
  This folder contains task-specific guidance — the things you would tell your agent if you were sitting next to it. Not generic instructions. Project-specific accumulated wisdom.
4
6
 
5
7
  ## How patterns get created
@@ -15,7 +15,7 @@ edges:
15
15
  condition: for the lazy import pattern and Verify Checklist
16
16
  - target: context/render-pipeline.md
17
17
  condition: when the new format returns an unusual dtype that may affect the render pipeline
18
- last_updated: 2026-04-29
18
+ last_updated: 2026-05-16
19
19
  ---
20
20
 
21
21
  # Add File Format
@@ -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-04-29
19
+ last_updated: 2026-05-16
20
20
  ---
21
21
 
22
22
  # Add Server Endpoint
@@ -16,7 +16,7 @@ triggers:
16
16
  edges:
17
17
  - target: patterns/frontend-change.md
18
18
  condition: always — animation changes are always frontend changes
19
- last_updated: 2026-04-29
19
+ last_updated: 2026-05-16
20
20
  ---
21
21
 
22
22
  # Animation Verify
@@ -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-04-29
25
+ last_updated: 2026-05-16
26
26
  ---
27
27
 
28
28
  # Debug Render
@@ -12,7 +12,7 @@ triggers:
12
12
  edges:
13
13
  - target: context/conventions.md
14
14
  condition: when making code changes after confirming the failure mode
15
- last_updated: 2026-05-06
15
+ last_updated: 2026-05-16
16
16
  ---
17
17
 
18
18
  # Debug VS Code Extension Python
@@ -38,7 +38,7 @@ an unsatisfiable dependency error.
38
38
 
39
39
  1. **Check the extension log first**
40
40
  ```bash
41
- tail -n 120 ~/.arrayview/extension.log
41
+ tail -n 120 "$HOME/.arrayview/extension.log"
42
42
  ```
43
43
  Look for `CUSTOM-EDITOR:`, `PYTHON: spawning`, stderr lines, and the final exit code.
44
44
 
@@ -80,11 +80,11 @@ an unsatisfiable dependency error.
80
80
 
81
81
  - Running `python -m arrayview --mode stdio ...` directly from a shell script without redirecting stdin can feed shell text into the stdio server. Use `</dev/null` for bounded startup checks.
82
82
  - In tunnel workspaces, the clicked-file custom editor does **not** use the current repo checkout automatically unless that workspace `.venv` points to it.
83
- - A reboot or deleting `~/.vscode-server` can change the default interpreter resolution without changing the extension code.
83
+ - A reboot or deleting the VS Code server directory under the user's home directory can change the default interpreter resolution without changing the extension code.
84
84
 
85
85
  ## Verify
86
86
 
87
- - [ ] `~/.arrayview/extension.log` shows the expected candidate order
87
+ - [ ] The ArrayView extension log under the user's home directory shows the expected candidate order
88
88
  - [ ] The failing workspace reproducer emits `SESSION:{...}` with the intended interpreter
89
89
  - [ ] If `extension.js` changed, `vscode-extension/package.json`, `_VSCODE_EXT_VERSION`, and the VSIX version all match
90
90
  - [ ] After reinstalling or reloading, the custom editor opens the target array without `Python process exited with code 1`
@@ -92,4 +92,4 @@ an unsatisfiable dependency error.
92
92
  ## Update Scaffold
93
93
  - [ ] Update `.mex/context/project-state.md` if the shipped fallback behavior changed
94
94
  - [ ] Update any `.mex/context/` files that are now out of date
95
- - [ ] Add this pattern to `.mex/patterns/INDEX.md`
95
+ - [ ] Add this pattern to `.mex/patterns/INDEX.md`
@@ -0,0 +1,60 @@
1
+ ---
2
+ name: extend-compare-mode
3
+ description: Extending compare mode in `_viewer.html` — new compare entry paths, pane labeling, center-mode behavior, or compare-specific per-pane render state.
4
+ triggers:
5
+ - "compare mode"
6
+ - "compare center"
7
+ - "detached compare"
8
+ - "pane titles"
9
+ - "diff params"
10
+ - "X key"
11
+ edges:
12
+ - target: patterns/frontend-change.md
13
+ condition: when the work is primarily a local `_viewer.html` edit
14
+ - target: context/render-pipeline.md
15
+ condition: when compare changes require backend render or diff parameter changes
16
+ last_updated: 2026-05-13
17
+ ---
18
+
19
+ # Extend Compare Mode
20
+
21
+ ## Context
22
+
23
+ Compare behavior is split across a few tight surfaces:
24
+ - state near `compareCenterMode` and `compareSid`
25
+ - pane titles in `updateCompareTitles()`
26
+ - frame fetching in `compareRender()`
27
+ - center diff fetching in `fetchAndDrawDiff()` and `_fetchDiffHistogram()`
28
+ - command and keybinding routing near `compare.cycleCenterMode`
29
+ - compare teardown in `exitCompareMode()`
30
+
31
+ If the feature changes diff request parameters, keep HTTP and stdio parity by updating `_routes_rendering.py`, `_stdio_server.py`, and `_diff.py` together.
32
+
33
+ ## Steps
34
+
35
+ 1. Add new compare-specific state beside the existing compare globals, not in unrelated mode sections.
36
+ 2. Reuse compare entry helpers when possible. If the feature behaves like compare but changes where panes read from, prefer a small wrapper entry function over a parallel mode implementation.
37
+ 3. Update pane labeling in `updateCompareTitles()` so the titles reflect compare state directly.
38
+ 4. If pane sources can diverge, update both `compareRender()` and the center diff/histogram fetch path to build per-pane request params.
39
+ 5. Route keyboard behavior through the command registry and keybind list together. If a key changes meaning in compare mode, add a compare-scoped command before the generic fallback binding.
40
+ 6. Clear all new compare state in `exitCompareMode()`.
41
+ 7. Update `GUIDE_TABS` whenever the key behavior or compare affordances change.
42
+
43
+ ## Gotchas
44
+
45
+ - `compareDisplaySids` can lag initial compare entry; if 2-pane support matters immediately, also account for `_compareExplicitSids`.
46
+ - A compare feature that changes `/diff` params must update `_fetchDiffHistogram()` too, not just `fetchAndDrawDiff()`.
47
+ - Detached or synthetic compare sources should not leak into saved `compare_sid` URL/session state unless restore explicitly supports them.
48
+ - `[` and `]` already mean “adjust compare parameter” in several center modes. New compare-local bindings must be ordered ahead of the generic bracket handler.
49
+
50
+ ## Verify
51
+
52
+ - [ ] Focused browser test for compare entry or the new entry path passes
53
+ - [ ] Focused browser test for `X` / compare-center behavior passes
54
+ - [ ] If diff params changed, focused API coverage for `/diff` passes
55
+ - [ ] If diff histogram depends on the same params, verify histogram path too
56
+
57
+ ## Update Scaffold
58
+
59
+ - [ ] Update `.mex/context/project-state.md` when compare behavior changes
60
+ - [ ] Add this pattern to `.mex/patterns/INDEX.md` if it is new
@@ -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-04-29
14
+ last_updated: 2026-05-16
15
15
  ---
16
16
 
17
17
  # Extract Server Route Module
@@ -16,7 +16,7 @@ edges:
16
16
  condition: for shared conventions and the Verify Checklist
17
17
  - target: patterns/debug-render.md
18
18
  condition: when the change produces wrong visual output
19
- last_updated: 2026-05-01
19
+ last_updated: 2026-05-16
20
20
  ---
21
21
 
22
22
  # Frontend Change
@@ -25,8 +25,8 @@ Bug fixes and internal refactors can go straight to a PR.
25
25
  Never use sans-serif.
26
26
 
27
27
  3. **Colors via CSS custom properties.** Use `var(--surface)`, `var(--text)`,
28
- `var(--active-dim)`, etc. Never hardcode hex values. The viewer ships four
29
- themes (dark, light, solarized, nord) and all must work.
28
+ `var(--active-dim)`, etc. Never hardcode hex values. The viewer ships two
29
+ themes (dark, light) and both must work.
30
30
 
31
31
  4. **Yellow for active state.** `--active-dim` (#f5c842 in dark theme) marks
32
32
  the currently active element. Don't introduce new accent colors.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: arrayview
3
- Version: 0.22.0
3
+ Version: 0.23.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
@@ -36,26 +36,22 @@ Description-Content-Type: text/markdown
36
36
 
37
37
  # <img src="docs/logo.png" height="36"> arrayview
38
38
 
39
- This is what looking at arrays should feel like.
39
+ _This is my array viewer. There are many like it, but this one is mine._
40
40
 
41
- Load up `.npy`, `.nii`, `.h5`, `.mat` and friends. Works locally, in Jupyter, over SSH and VS Code tunnels. Press `?` once you're in.
41
+ And I think you might like it too. Fast, responsive scrolling
42
+ through slices of multi-dimensional arrays. Feature rich with a modern, minimal UI that only shows what needs to be shown.
42
43
 
43
- ## CLI
44
+ It works wherever you work. The shell, scripts (Python/Julia/Matlab), or Jupyter notebooks. Local or remote. Easy to install.
44
45
 
45
- ```bash
46
- uvx arrayview your_array.npy
47
- ```
46
+ VS Code users can even open the viewer just by clicking an array in the explorer tab.
48
47
 
49
- ## Python
48
+ And if you're using the VS Code remote extension to connect to a remote, it just works—no additional setup required.
50
49
 
50
+ Curious? Give it a try with
51
51
  ```bash
52
- uv add arrayview
53
- ```
54
-
55
- ```python
56
- from arrayview import view
57
- view(arr)
52
+ uvx arrayview your_array.npy
58
53
  ```
54
+ Explore, there's more to it than meets the eye.
59
55
 
60
- [docs](https://oscarvanderheide.github.io/arrayview/)
56
+ Check the [docs](https://oscarvanderheide.github.io/arrayview/) to learn more.
61
57
 
@@ -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
+ And I think you might like it too. Fast, responsive scrolling
6
+ through slices of multi-dimensional arrays. Feature rich with a modern, minimal UI that only shows what needs to be shown.
7
+
8
+ It works wherever you work. The shell, scripts (Python/Julia/Matlab), or Jupyter notebooks. Local or remote. Easy to install.
9
+
10
+ VS Code users can even open the viewer just by clicking an array in the explorer tab.
11
+
12
+ And if you're using the VS Code remote extension to connect to a remote, it just works—no additional setup required.
13
+
14
+ Curious? Give it a try with
15
+ ```bash
16
+ uvx arrayview your_array.npy
17
+ ```
18
+ Explore, there's more to it than meets the eye.
19
+
20
+ Check the [docs](https://oscarvanderheide.github.io/arrayview/) to learn more.
21
+
@@ -20,7 +20,7 @@ Drag the colorbar to shift the window. Scroll on the colorbar to narrow or widen
20
20
 
21
21
  ## Themes
22
22
 
23
- `T` cycles: dark (default), light, solarized, nord.
23
+ `T` cycles: dark (default), light.
24
24
 
25
25
  ## Masking
26
26
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "arrayview"
7
- version = "0.22.0"
7
+ version = "0.23.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"
@@ -40,7 +40,7 @@ def get_viewer_colormaps() -> list[str] | None:
40
40
  return None
41
41
 
42
42
 
43
- _VALID_THEMES = {"dark", "light", "solarized", "nord"}
43
+ _VALID_THEMES = {"dark", "light"}
44
44
 
45
45
 
46
46
  def get_viewer_theme() -> str | None:
@@ -95,13 +95,22 @@ def _compute_diff(
95
95
  complex_mode,
96
96
  log_scale,
97
97
  diff_mode,
98
+ indices_a=None,
99
+ indices_b=None,
98
100
  ):
99
101
  """Return raw diff, display range, colormap, and optional separator mask."""
100
- idx_tuple = tuple(int(x) for x in indices.split(",")) if isinstance(indices, str) else indices
102
+ def _parse_indices(raw_indices):
103
+ if raw_indices is None:
104
+ return ()
105
+ if isinstance(raw_indices, str):
106
+ return tuple(int(x) for x in raw_indices.split(",") if x != "")
107
+ return tuple(int(x) for x in raw_indices)
108
+
109
+ idx_tuple = _parse_indices(indices)
101
110
  ndim_a = len(session_a.shape)
102
111
  ndim_b = len(session_b.shape)
103
- idx_a = idx_tuple[:ndim_a]
104
- idx_b = idx_tuple[:ndim_b]
112
+ idx_a = _parse_indices(indices_a)[:ndim_a] if indices_a is not None else idx_tuple[:ndim_a]
113
+ idx_b = _parse_indices(indices_b)[:ndim_b] if indices_b is not None else idx_tuple[:ndim_b]
105
114
  nan_mask = None
106
115
 
107
116
  if dim_z >= 0:
@@ -272,6 +272,8 @@ def register_rendering_routes(app, *, get_session_or_404) -> None:
272
272
  dim_x: int,
273
273
  dim_y: int,
274
274
  indices: str,
275
+ indices_a: str | None = None,
276
+ indices_b: str | None = None,
275
277
  dim_z: int = -1,
276
278
  dr: int = 1,
277
279
  complex_mode: int = 0,
@@ -297,6 +299,8 @@ def register_rendering_routes(app, *, get_session_or_404) -> None:
297
299
  complex_mode,
298
300
  log_scale,
299
301
  diff_mode,
302
+ indices_a=indices_a,
303
+ indices_b=indices_b,
300
304
  )
301
305
  except Exception:
302
306
  return Response(status_code=422)
@@ -328,6 +332,8 @@ def register_rendering_routes(app, *, get_session_or_404) -> None:
328
332
  dim_x: int,
329
333
  dim_y: int,
330
334
  indices: str,
335
+ indices_a: str | None = None,
336
+ indices_b: str | None = None,
331
337
  dim_z: int = -1,
332
338
  dr: int = 1,
333
339
  complex_mode: int = 0,
@@ -351,6 +357,8 @@ def register_rendering_routes(app, *, get_session_or_404) -> None:
351
357
  complex_mode,
352
358
  log_scale,
353
359
  diff_mode,
360
+ indices_a=indices_a,
361
+ indices_b=indices_b,
354
362
  )
355
363
  except Exception:
356
364
  return Response(status_code=422)