arrayview 0.6.0__tar.gz → 0.8.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 (73) hide show
  1. {arrayview-0.6.0 → arrayview-0.8.0}/.claude/skills/ui-consistency-audit/SKILL.md +32 -0
  2. arrayview-0.8.0/.claude/skills/visual-bug-fixing/SKILL.md +153 -0
  3. arrayview-0.8.0/.github/workflows/docs.yml +20 -0
  4. {arrayview-0.6.0 → arrayview-0.8.0}/.gitignore +5 -1
  5. arrayview-0.8.0/AGENTS.md +52 -0
  6. arrayview-0.8.0/PKG-INFO +133 -0
  7. arrayview-0.8.0/README.md +98 -0
  8. {arrayview-0.6.0 → arrayview-0.8.0}/docs/remote.md +26 -5
  9. arrayview-0.8.0/matlab/arrayview.m +74 -0
  10. {arrayview-0.6.0 → arrayview-0.8.0}/mkdocs.yml +2 -0
  11. arrayview-0.8.0/plans/webview/LOG.md +130 -0
  12. {arrayview-0.6.0 → arrayview-0.8.0}/pyproject.toml +1 -1
  13. {arrayview-0.6.0 → arrayview-0.8.0}/src/arrayview/__init__.py +2 -1
  14. arrayview-0.8.0/src/arrayview/__main__.py +4 -0
  15. {arrayview-0.6.0 → arrayview-0.8.0}/src/arrayview/_app.py +0 -2
  16. {arrayview-0.6.0 → arrayview-0.8.0}/src/arrayview/_config.py +29 -0
  17. arrayview-0.8.0/src/arrayview/_icon.png +0 -0
  18. {arrayview-0.6.0 → arrayview-0.8.0}/src/arrayview/_io.py +91 -4
  19. {arrayview-0.6.0 → arrayview-0.8.0}/src/arrayview/_launcher.py +516 -99
  20. {arrayview-0.6.0 → arrayview-0.8.0}/src/arrayview/_render.py +11 -37
  21. arrayview-0.8.0/src/arrayview/_segmentation.py +227 -0
  22. {arrayview-0.6.0 → arrayview-0.8.0}/src/arrayview/_server.py +990 -128
  23. {arrayview-0.6.0 → arrayview-0.8.0}/src/arrayview/_session.py +8 -3
  24. arrayview-0.8.0/src/arrayview/_stdio_server.py +705 -0
  25. arrayview-0.8.0/src/arrayview/_torch.py +217 -0
  26. {arrayview-0.6.0 → arrayview-0.8.0}/src/arrayview/_viewer.html +4245 -1743
  27. {arrayview-0.6.0 → arrayview-0.8.0}/src/arrayview/_vscode.py +365 -141
  28. arrayview-0.8.0/src/arrayview/arrayview-opener.vsix +0 -0
  29. {arrayview-0.6.0 → arrayview-0.8.0}/tests/test_api.py +36 -0
  30. {arrayview-0.6.0 → arrayview-0.8.0}/tests/test_cli.py +3 -3
  31. {arrayview-0.6.0 → arrayview-0.8.0}/tests/test_config.py +27 -0
  32. {arrayview-0.6.0 → arrayview-0.8.0}/tests/test_interactions.py +23 -23
  33. {arrayview-0.6.0 → arrayview-0.8.0}/tests/test_mode_consistency.py +38 -22
  34. arrayview-0.8.0/tests/test_torch.py +223 -0
  35. {arrayview-0.6.0 → arrayview-0.8.0}/tests/ui_audit.py +132 -5
  36. {arrayview-0.6.0 → arrayview-0.8.0}/tests/visual_smoke.py +85 -6
  37. {arrayview-0.6.0 → arrayview-0.8.0}/uv.lock +1 -1
  38. arrayview-0.8.0/vscode-extension/extension.js +895 -0
  39. {arrayview-0.6.0 → arrayview-0.8.0}/vscode-extension/package.json +9 -2
  40. arrayview-0.6.0/.claude/skills/task-workflow/SKILL.md +0 -82
  41. arrayview-0.6.0/AGENTS.md +0 -137
  42. arrayview-0.6.0/PKG-INFO +0 -68
  43. arrayview-0.6.0/README.md +0 -33
  44. arrayview-0.6.0/docs/superpowers/plans/2026-03-27-colorbar-class-refactor.md +0 -1642
  45. arrayview-0.6.0/src/arrayview/arrayview-opener.vsix +0 -0
  46. arrayview-0.6.0/vscode-extension/extension.js +0 -395
  47. {arrayview-0.6.0 → arrayview-0.8.0}/.claude/skills/invocation-consistency/SKILL.md +0 -0
  48. {arrayview-0.6.0 → arrayview-0.8.0}/.claude/skills/modes-consistency/SKILL.md +0 -0
  49. {arrayview-0.6.0 → arrayview-0.8.0}/.claude/skills/viewer-ui-checklist/SKILL.md +0 -0
  50. {arrayview-0.6.0 → arrayview-0.8.0}/.github/workflows/python-publish.yml +0 -0
  51. {arrayview-0.6.0 → arrayview-0.8.0}/.python-version +0 -0
  52. {arrayview-0.6.0 → arrayview-0.8.0}/.tmp-vsix/extension/extension.js +0 -0
  53. {arrayview-0.6.0 → arrayview-0.8.0}/.tmp-vsix/extension/package.json +0 -0
  54. {arrayview-0.6.0 → arrayview-0.8.0}/LICENSE +0 -0
  55. {arrayview-0.6.0 → arrayview-0.8.0}/docs/comparing.md +0 -0
  56. {arrayview-0.6.0 → arrayview-0.8.0}/docs/configuration.md +0 -0
  57. {arrayview-0.6.0 → arrayview-0.8.0}/docs/display.md +0 -0
  58. {arrayview-0.6.0 → arrayview-0.8.0}/docs/index.md +0 -0
  59. {arrayview-0.6.0 → arrayview-0.8.0}/docs/loading.md +0 -0
  60. /arrayview-0.6.0/src/arrayview/_icon.png → /arrayview-0.8.0/docs/logo.png +0 -0
  61. {arrayview-0.6.0 → arrayview-0.8.0}/docs/measurement.md +0 -0
  62. {arrayview-0.6.0 → arrayview-0.8.0}/docs/stylesheets/extra.css +0 -0
  63. {arrayview-0.6.0 → arrayview-0.8.0}/docs/viewing.md +0 -0
  64. {arrayview-0.6.0 → arrayview-0.8.0}/scripts/demo.py +0 -0
  65. {arrayview-0.6.0 → arrayview-0.8.0}/src/arrayview/_platform.py +0 -0
  66. {arrayview-0.6.0 → arrayview-0.8.0}/src/arrayview/_shell.html +0 -0
  67. {arrayview-0.6.0 → arrayview-0.8.0}/tests/conftest.py +0 -0
  68. {arrayview-0.6.0 → arrayview-0.8.0}/tests/make_vectorfield_test_arrays.py +0 -0
  69. {arrayview-0.6.0 → arrayview-0.8.0}/tests/test_browser.py +0 -0
  70. {arrayview-0.6.0 → arrayview-0.8.0}/tests/test_large_arrays.py +0 -0
  71. {arrayview-0.6.0 → arrayview-0.8.0}/tests/test_mode_matrix.py +0 -0
  72. {arrayview-0.6.0 → arrayview-0.8.0}/tests/test_rgb_pixel_art.py +0 -0
  73. {arrayview-0.6.0 → arrayview-0.8.0}/vscode-extension/LICENSE +0 -0
@@ -222,6 +222,13 @@ These rules are codified as DOM assertions in `tests/ui_audit.py`. When a new in
222
222
  | R26 | Shared colorbar width capped in compare mode | `#slim-cb-wrap` width ≤ 500px in compare mode |
223
223
  | R27 | Mode eggs hidden during loading | `#mode-eggs` empty/hidden until at least one frame has been received |
224
224
  | R28 | Compare+multiview crosshair fade works | Crosshair lines in compare+multiview fade in/out on hover, scoped to the hovered array's panes |
225
+ | R29 | Dimbar/colorbar height sync | `#info` and `#slim-cb-wrap` offsetHeight within 4px when both visible. Enforced by `_validateUIState()` (runtime) and `run_invariant_assertions()` (Playwright) |
226
+ | R30 | Drag positions cleared on immersive exit | `_infoDragPos`, `_cbDragPos`, `_islandDragPos` all null when `!_fullscreenActive`. Enforced by `_validateUIState()` and `run_immersive_exit_assertions()` |
227
+ | R31 | No .fs-overlay outside immersive | Zero `.fs-overlay` elements when `!_fullscreenActive && !_immersiveAnimating`. Enforced by `_validateUIState()` and `run_immersive_exit_assertions()` |
228
+ | R32 | Per-pane cbs only in immersive+center | `.compare-pane-cb-island.fs-overlay` count > 0 only when `_fullscreenActive && centerMode`. Enforced by `_validateUIState()` |
229
+ | R33 | Colorbar flex-direction always row | All visible `.cb-island` computed `flex-direction === 'row'`. Enforced by CSS (`!important`) and `_validateUIState()` and `run_invariant_assertions()` |
230
+ | R34 | Shared colorbar visible in compare non-center | `#slim-cb-wrap` not `display:none` when `compareActive && !centerMode`. Enforced by `_validateUIState()` |
231
+ | R35 | Islands fully inside or outside pane | Dynamic islands must be fully inside pane bounds (immersive) or fully outside in normal flow (non-immersive) — never partially overlapping |
225
232
 
226
233
  ---
227
234
 
@@ -240,6 +247,31 @@ All colorbars across ALL modes follow the same structure: `[vmin span] [gradient
240
247
 
241
248
  ---
242
249
 
250
+ ## Section 5d: Enforcement Layers
251
+
252
+ Rules are enforced through multiple layers. When adding new rules, add enforcement at the appropriate layer(s):
253
+
254
+ | Layer | Mechanism | Where | When it runs |
255
+ |-------|-----------|-------|--------------|
256
+ | **CSS** | `!important` structural constraints | `_viewer.html` CSS (line ~156) | Always — structurally impossible to violate |
257
+ | **Runtime JS** | `_validateUIState()` | `_viewer.html` JS (after `_positionFullscreenChrome`) | After every layout change, gated behind `?debug_ui=1` |
258
+ | **Playwright** | `run_invariant_assertions()` + `run_immersive_exit_assertions()` | `tests/ui_audit.py` | During `ui_audit.py` runs (all tiers) |
259
+ | **Skill** | This document (Section 5b) | `.claude/skills/ui-consistency-audit/SKILL.md` | When AI agent invokes the skill |
260
+
261
+ **Cross-reference:**
262
+
263
+ | Rule | CSS | Runtime JS | Playwright | Notes |
264
+ |------|-----|-----------|------------|-------|
265
+ | R29 (height sync) | — | ✓ | ✓ | |
266
+ | R30 (drag cleanup) | — | ✓ | ✓ | Only after immersive exit |
267
+ | R31 (fs-overlay cleanup) | — | ✓ | ✓ | Only after immersive exit |
268
+ | R32 (per-pane cb visibility) | — | ✓ | — | |
269
+ | R33 (flex-direction row) | ✓ | ✓ | ✓ | CSS makes violation impossible |
270
+ | R34 (shared cb in compare) | — | ✓ | — | |
271
+ | R35 (island containment) | — | — | — | Design principle, enforced by code review |
272
+
273
+ ---
274
+
243
275
  ## Section 6: Common Feature Categories
244
276
 
245
277
  ### Zoom / Canvas Sizing
@@ -0,0 +1,153 @@
1
+ ---
2
+ name: visual-bug-fixing
3
+ description: Use when fixing any visual bug, layout glitch, rendering artifact, or UI regression in arrayview. Triggered by symptoms like overlapping elements, wrong positioning, missing components, flickering, or incorrect sizing in any view mode.
4
+ ---
5
+
6
+ # Visual Bug Fixing
7
+
8
+ ## Overview
9
+
10
+ **Fix visual bugs with screenshot evidence, not guesswork.** Capture before-state, diagnose root cause, fix, capture after-state, verify no regressions across all view modes. Never commit a visual fix without photographic proof it works and doesn't break anything else.
11
+
12
+ ## When to Use
13
+
14
+ - User reports a visual bug (overlap, misalignment, wrong size, missing element, rendering artifact)
15
+ - You notice a visual inconsistency during other work
16
+ - A UI change causes unexpected layout shifts
17
+ - Screenshot diff failures in `ui_audit.py`
18
+
19
+ **When NOT to use:**
20
+ - Pure logic bugs with no visual impact — use superpowers:systematic-debugging
21
+ - Adding new UI features — use ui-consistency-audit + frontend-designer
22
+ - Updating test coverage — use viewer-ui-checklist
23
+
24
+ ## Workflow
25
+
26
+ ```dot
27
+ digraph visual_bug_fix {
28
+ rankdir=TB;
29
+ "Bug reported" -> "Capture baseline screenshots";
30
+ "Capture baseline screenshots" -> "Diagnose root cause";
31
+ "Diagnose root cause" -> "Implement fix";
32
+ "Implement fix" -> "Capture post-fix screenshots";
33
+ "Capture post-fix screenshots" -> "Compare before/after";
34
+ "Compare before/after" -> "Run full regression check";
35
+ "Run full regression check" -> "Regressions found?" [shape=diamond];
36
+ "Regressions found?" -> "Implement fix" [label="yes — iterate"];
37
+ "Regressions found?" -> "Show evidence & commit" [label="no"];
38
+ }
39
+ ```
40
+
41
+ ### Step 1: Capture Baseline Screenshots
42
+
43
+ Before touching any code, capture the current broken state. Use the Playwright MCP tools:
44
+
45
+ 1. **Navigate** to the affected view using `browser_navigate` to the arrayview URL
46
+ 2. **Set up the bug conditions** — press keys to enter the right mode, load the right array
47
+ 3. **Screenshot the broken state** with `browser_take_screenshot` — save as `baseline_bug.png`
48
+ 4. **Screenshot ALL other modes** that could be affected:
49
+ - Normal view (default)
50
+ - Immersive mode (`Shift+K`)
51
+ - Compare mode (navigate to compare URL)
52
+ - Diff modes (`Shift+X` to cycle)
53
+ - Multiview (`v`)
54
+ - Zen mode (`Shift+F`)
55
+ - Zoomed state (`+` keys)
56
+
57
+ **Key selectors to inspect** (via `browser_snapshot` or `browser_evaluate`):
58
+ - `#canvas-wrap` — main canvas container
59
+ - `#slim-cb-wrap` — colorbar wrapper
60
+ - `#info` — info bar
61
+ - `.mode-egg` — mode indicator badges
62
+ - `#miniview` — minimap overlay
63
+ - `#dimbar` — dimension navigation bar
64
+
65
+ ### Step 2: Diagnose Root Cause
66
+
67
+ Read the relevant source files. The UI lives in:
68
+
69
+ | Layer | File |
70
+ |-------|------|
71
+ | HTML structure | `arrayview/_viewer.html` |
72
+ | Inline CSS | `<style>` blocks in `_viewer.html` |
73
+ | Canvas rendering | JavaScript in `_viewer.html` (search for `scaleCanvas`, `mvScaleAllCanvases`, `compareScaleCanvases`) |
74
+ | Python server | `arrayview/_app.py` |
75
+ | Colorbar logic | `ColorBar` class in `_viewer.html` |
76
+
77
+ **Diagnosis checklist:**
78
+ - Is this a CSS issue (positioning, overflow, z-index, flexbox)?
79
+ - Is this a JS layout calculation issue (wrong width/height, missing mode branch)?
80
+ - Does the bug only appear in certain modes? Which scale function is involved?
81
+ - Does zoom level matter? Check the zoom-related code paths.
82
+ - Is this a race condition (element rendered before data arrives)?
83
+
84
+ **Check hard rules:** Before implementing a fix, check if the bug is a violation of a hard UI rule (R1-R35 in `ui-consistency-audit` Section 5b). If so, the fix should restore the invariant rather than work around it. Enable `?debug_ui=1` to see runtime invariant warnings in the browser console — they may pinpoint the exact rule being violated.
85
+
86
+ **Use `browser_evaluate` to inspect live DOM state:**
87
+ ```javascript
88
+ // Get bounding boxes of key elements
89
+ JSON.stringify({
90
+ canvas: document.querySelector('#canvas-wrap')?.getBoundingClientRect(),
91
+ colorbar: document.querySelector('#slim-cb-wrap')?.getBoundingClientRect(),
92
+ info: document.querySelector('#info')?.getBoundingClientRect(),
93
+ viewport: { width: window.innerWidth, height: window.innerHeight }
94
+ })
95
+ ```
96
+
97
+ ### Step 3: Implement the Fix
98
+
99
+ Apply the minimal fix. Reference the ui-consistency-audit design rules (R1-R35) to ensure the fix doesn't violate any existing constraints.
100
+
101
+ **Common fix patterns:**
102
+ - **Overlap bugs**: Check z-index hierarchy, adjust `position`/`top`/`left`/`right`
103
+ - **Sizing bugs**: Trace the calculation chain in the relevant scale function
104
+ - **Mode-specific bugs**: Ensure all mode branches handle the element (check `isCompare`, `isMultiview`, `isImmersive`, `isZen` flags)
105
+ - **Zoom bugs**: Check `zoomLevel` interactions with element positioning
106
+
107
+ ### Step 4: Capture Post-Fix Screenshots
108
+
109
+ Repeat the exact same navigation and key presses from Step 1. Screenshot every view that was captured in the baseline.
110
+
111
+ ### Step 5: Compare Before/After
112
+
113
+ Present the before and after screenshots to the user. Explain:
114
+ - What was broken (with baseline screenshot)
115
+ - What changed in the code
116
+ - What it looks like now (with post-fix screenshot)
117
+
118
+ ### Step 6: Full Regression Check
119
+
120
+ Run the automated visual audit:
121
+
122
+ ```bash
123
+ uv run python tests/ui_audit.py --tier 1
124
+ ```
125
+
126
+ This checks 14 core scenarios with DOM assertions and pixel diffs. If any fail:
127
+ - Read the failure output to identify which scenario regressed
128
+ - Screenshot that specific scenario manually to understand the regression
129
+ - Go back to Step 3 and iterate
130
+
131
+ For thorough validation (before committing):
132
+ ```bash
133
+ uv run python tests/ui_audit.py --tier 2
134
+ ```
135
+
136
+ **Only commit when Tier 1 passes clean.** Tier 2 failures should be investigated but may be pre-existing.
137
+
138
+ ## Red Flags — STOP and Investigate
139
+
140
+ | Symptom | Likely Cause |
141
+ |---------|-------------|
142
+ | Fix works in normal mode but breaks compare | Missing branch in `compareScaleCanvases` |
143
+ | Element disappears on zoom | Absolute positioning without zoom-aware offsets |
144
+ | Fix works at 1440x900 but breaks at other sizes | Hardcoded pixel values instead of relative/calc |
145
+ | Colorbar overlaps canvas after fix | Forgot to account for colorbar width in canvas sizing |
146
+ | Mode eggs shift position | Changed a parent container's layout without updating egg anchoring |
147
+
148
+ ## Common Mistakes
149
+
150
+ - **Fixing the symptom, not the cause** — A `display:none` hack hides the bug. Find why the element is in the wrong place.
151
+ - **Testing only the affected mode** — Visual bugs often have cross-mode impact. Always check at minimum: normal, immersive, compare, multiview.
152
+ - **Skipping the baseline screenshot** — Without before/after evidence, you can't prove the fix worked or detect subtle regressions.
153
+ - **Committing without running ui_audit.py** — DOM assertions catch things screenshots miss (off-by-1px overlaps, viewport overflow).
@@ -0,0 +1,20 @@
1
+ name: Deploy docs
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ paths: [docs/**, mkdocs.yml]
7
+
8
+ permissions:
9
+ contents: write
10
+
11
+ jobs:
12
+ deploy:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ - uses: actions/setup-python@v5
17
+ with:
18
+ python-version: "3.x"
19
+ - run: pip install mkdocs-material
20
+ - run: mkdocs gh-deploy --force
@@ -11,6 +11,7 @@ wheels/
11
11
 
12
12
  *.npy
13
13
  .claude/
14
+ .worktrees/
14
15
  !.claude/skills/
15
16
  !.claude/skills/**
16
17
  CLAUDE.md
@@ -24,7 +25,10 @@ tests/smoke_output/
24
25
  dev/
25
26
  *.png
26
27
  !src/arrayview/_icon.png
28
+ !docs/logo.png
27
29
 
28
30
  benchmarks/data
29
31
  .superpowers/brainstorm
30
- site/
32
+ site/
33
+ van_gogh/
34
+ docs/superpowers
@@ -0,0 +1,52 @@
1
+ # ArrayView
2
+
3
+ Interactive viewer for multi-dimensional arrays and medical/scientific volumes. FastAPI server + single-file HTML/JS frontend (`_viewer.html`), displayed via native window, browser, VS Code Simple Browser, or Jupyter iframe.
4
+
5
+ ## Core Files
6
+
7
+ | File | Role |
8
+ |------|------|
9
+ | `_launcher.py` | Entry points, process management, display routing |
10
+ | `_server.py` | FastAPI app, REST/WebSocket, HTML templates |
11
+ | `_session.py` | Sessions, state, caches, render thread |
12
+ | `_render.py` | Colormaps, LUTs, slice extraction, RGBA |
13
+ | `_viewer.html` | All frontend (JS/CSS embedded, single file) |
14
+ | `_vscode.py` | Extension management, signal-file IPC |
15
+ | `_stdio_server.py` | Stdio transport for direct webview mode |
16
+ | `_segmentation.py` | nnInteractive segmentation client |
17
+
18
+ ## Skills
19
+
20
+ Load the relevant skill before touching the corresponding area.
21
+
22
+ | Skill | When |
23
+ |-------|------|
24
+ | `ui-consistency-audit` | Any visual/UI change |
25
+ | `frontend-designer` | Styling/layout changes to `_viewer.html` |
26
+ | `vscode-simplebrowser` | Extension, signal-file IPC, `_VSCODE_EXT_VERSION` |
27
+ | `invocation-consistency` | Server startup, display-opening, env detection |
28
+ | `docs-style` | README, help overlay, docstrings |
29
+
30
+ ## Non-Negotiables
31
+
32
+ - Always use `localhost` (not `127.0.0.1`) -- required for VS Code port forwarding
33
+ - Never `--force` reinstall the extension if correct version is on disk
34
+ - Do not add logic to `_app.py` -- compat shim only
35
+ - Avoid orphan processes; shutdown must be automatic
36
+ - Do not regress working display paths when fixing another
37
+ - For visual/animation features, propose 2-3 options BEFORE implementing
38
+ - UI visibility changes go through reconcilers (`_reconcileUI`/`_reconcileLayout`/`_reconcileCompareState`/`_reconcileCbVisibility`), not inline `style.display` or `classList` toggles in mode functions
39
+
40
+ ## Execution
41
+
42
+ Always use **subagent-driven development** for implementation. Commit completed work automatically.
43
+
44
+ ## Testing
45
+
46
+ ```bash
47
+ uv run pytest tests/test_api.py -v # HTTP API
48
+ uv run pytest tests/test_browser.py -v # Playwright
49
+ uv run python tests/visual_smoke.py # screenshots
50
+ ```
51
+
52
+ After any UI change, use `/ui-consistency-audit` to verify across all modes.
@@ -0,0 +1,133 @@
1
+ Metadata-Version: 2.4
2
+ Name: arrayview
3
+ Version: 0.8.0
4
+ Summary: Fast multi-dimensional array viewer
5
+ Project-URL: Home, https://github.com/oscarvanderheide/arrayview
6
+ Project-URL: Source, https://github.com/oscarvanderheide/arrayview
7
+ Author-email: Oscar <oscarvanderheide@example.com>
8
+ License: MIT
9
+ License-File: LICENSE
10
+ Keywords: array,mri,npy,viewer,visualization
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3 :: Only
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Requires-Python: >=3.12
17
+ Requires-Dist: fastapi>=0.129.0
18
+ Requires-Dist: h5py>=3.0
19
+ Requires-Dist: matplotlib>=3.9.0
20
+ Requires-Dist: nibabel>=5.3.3
21
+ Requires-Dist: numpy>=2.4.2
22
+ Requires-Dist: pillow>=12.1.1
23
+ Requires-Dist: pyqt5>=5.15; sys_platform == 'linux'
24
+ Requires-Dist: pyqtwebengine>=5.15; sys_platform == 'linux'
25
+ Requires-Dist: python-multipart>=0.0.22
26
+ Requires-Dist: pywebview>=6.1
27
+ Requires-Dist: qmricolors>=0.1.2
28
+ Requires-Dist: qtpy>=2.0; sys_platform == 'linux'
29
+ Requires-Dist: scipy>=1.10
30
+ Requires-Dist: tifffile>=2023.1.1
31
+ Requires-Dist: uvicorn>=0.41.0
32
+ Requires-Dist: websockets>=14.0
33
+ Requires-Dist: zarr>=2.17
34
+ Description-Content-Type: text/markdown
35
+
36
+ # arrayview
37
+
38
+ A viewer for multi-dimensional arrays.
39
+
40
+ - CLI and Python
41
+ - Jupyter / VS Code
42
+ - Browser / native
43
+ - SSH / tunnels
44
+
45
+ ## CLI
46
+
47
+ ```bash
48
+ uvx arrayview scan.nii.gz
49
+ uvx arrayview --window browser scan.npy
50
+ uvx arrayview # demo
51
+ ```
52
+
53
+ ## Python
54
+
55
+ ```python
56
+ from arrayview import view
57
+ view(arr)
58
+ ```
59
+
60
+ ## MATLAB
61
+
62
+ Add the `matlab/` directory to your MATLAB path, then:
63
+
64
+ ```matlab
65
+ addpath('/path/to/arrayview/matlab')
66
+
67
+ A = rand(100, 200, 10);
68
+ arrayview(A)
69
+ ```
70
+
71
+ Requires arrayview installed in [MATLAB's Python environment](https://www.mathworks.com/help/matlab/matlab_external/install-supported-python-implementation.html):
72
+
73
+ ```bash
74
+ pip install arrayview
75
+ ```
76
+
77
+ Arrays are passed zero-copy via the buffer protocol (in-process Python). `arrayview()` enables this automatically — just call it before any other `py.*` call in your MATLAB session.
78
+
79
+ ## PyTorch / Deep Learning
80
+
81
+ ```python
82
+ from arrayview import view_batch, TrainingMonitor
83
+
84
+ # Browse a DataLoader batch
85
+ view_batch(train_loader)
86
+ view_batch(train_loader, overlay='label')
87
+
88
+ # Live training monitor — updates every N epochs
89
+ monitor = TrainingMonitor(every=5, samples=3)
90
+ for epoch in range(100):
91
+ for batch in val_loader:
92
+ pred = model(batch['image'])
93
+ monitor.step(input=batch['image'], target=batch['label'],
94
+ prediction=pred, epoch=epoch)
95
+ ```
96
+
97
+ `view_batch()` accepts DataLoaders, Datasets, dicts, tuples, or raw tensors. `TrainingMonitor` opens a compare window and calls `handle.update()` automatically. PyTorch is not required at import time.
98
+
99
+
100
+ ## Formats
101
+
102
+ `.npy` `.npz` `.nii` `.nii.gz` `.zarr` `.pt` `.h5` `.tif` `.mat`
103
+
104
+ ## Once open
105
+
106
+ `c` colormaps · `d` dynamic range · `v` 3-plane · `z` mosaic · `Shift+O` overlay toggle · `?` help · colorbar dblclick histogram
107
+
108
+
109
+ ## nnInteractive Segmentation
110
+
111
+ `S` starts AI-assisted 3D segmentation (requires CUDA). Click/draw to segment, `Enter` to accept.
112
+
113
+ ```toml
114
+ [nninteractive]
115
+ url = "http://gpu-server:1527" # skip auto-launch, use running server
116
+ ```
117
+
118
+ Or: `ARRAYVIEW_NNINTERACTIVE_URL=http://gpu-server:1527`
119
+
120
+
121
+ ## Config
122
+
123
+ `~/.arrayview/config.toml`:
124
+
125
+ ```toml
126
+ [viewer]
127
+ colormaps = ["gray", "viridis", "plasma"] # colormaps cycled by 'c'
128
+
129
+ [window]
130
+ default = "browser" # browser | native | vscode | inline
131
+ ```
132
+
133
+ [Full documentation →](https://oscarvanderheide.github.io/arrayview/)
@@ -0,0 +1,98 @@
1
+ # arrayview
2
+
3
+ A viewer for multi-dimensional arrays.
4
+
5
+ - CLI and Python
6
+ - Jupyter / VS Code
7
+ - Browser / native
8
+ - SSH / tunnels
9
+
10
+ ## CLI
11
+
12
+ ```bash
13
+ uvx arrayview scan.nii.gz
14
+ uvx arrayview --window browser scan.npy
15
+ uvx arrayview # demo
16
+ ```
17
+
18
+ ## Python
19
+
20
+ ```python
21
+ from arrayview import view
22
+ view(arr)
23
+ ```
24
+
25
+ ## MATLAB
26
+
27
+ Add the `matlab/` directory to your MATLAB path, then:
28
+
29
+ ```matlab
30
+ addpath('/path/to/arrayview/matlab')
31
+
32
+ A = rand(100, 200, 10);
33
+ arrayview(A)
34
+ ```
35
+
36
+ Requires arrayview installed in [MATLAB's Python environment](https://www.mathworks.com/help/matlab/matlab_external/install-supported-python-implementation.html):
37
+
38
+ ```bash
39
+ pip install arrayview
40
+ ```
41
+
42
+ Arrays are passed zero-copy via the buffer protocol (in-process Python). `arrayview()` enables this automatically — just call it before any other `py.*` call in your MATLAB session.
43
+
44
+ ## PyTorch / Deep Learning
45
+
46
+ ```python
47
+ from arrayview import view_batch, TrainingMonitor
48
+
49
+ # Browse a DataLoader batch
50
+ view_batch(train_loader)
51
+ view_batch(train_loader, overlay='label')
52
+
53
+ # Live training monitor — updates every N epochs
54
+ monitor = TrainingMonitor(every=5, samples=3)
55
+ for epoch in range(100):
56
+ for batch in val_loader:
57
+ pred = model(batch['image'])
58
+ monitor.step(input=batch['image'], target=batch['label'],
59
+ prediction=pred, epoch=epoch)
60
+ ```
61
+
62
+ `view_batch()` accepts DataLoaders, Datasets, dicts, tuples, or raw tensors. `TrainingMonitor` opens a compare window and calls `handle.update()` automatically. PyTorch is not required at import time.
63
+
64
+
65
+ ## Formats
66
+
67
+ `.npy` `.npz` `.nii` `.nii.gz` `.zarr` `.pt` `.h5` `.tif` `.mat`
68
+
69
+ ## Once open
70
+
71
+ `c` colormaps · `d` dynamic range · `v` 3-plane · `z` mosaic · `Shift+O` overlay toggle · `?` help · colorbar dblclick histogram
72
+
73
+
74
+ ## nnInteractive Segmentation
75
+
76
+ `S` starts AI-assisted 3D segmentation (requires CUDA). Click/draw to segment, `Enter` to accept.
77
+
78
+ ```toml
79
+ [nninteractive]
80
+ url = "http://gpu-server:1527" # skip auto-launch, use running server
81
+ ```
82
+
83
+ Or: `ARRAYVIEW_NNINTERACTIVE_URL=http://gpu-server:1527`
84
+
85
+
86
+ ## Config
87
+
88
+ `~/.arrayview/config.toml`:
89
+
90
+ ```toml
91
+ [viewer]
92
+ colormaps = ["gray", "viridis", "plasma"] # colormaps cycled by 'c'
93
+
94
+ [window]
95
+ default = "browser" # browser | native | vscode | inline
96
+ ```
97
+
98
+ [Full documentation →](https://oscarvanderheide.github.io/arrayview/)
@@ -16,19 +16,40 @@ Auto-detects VS Code terminals and opens in Simple Browser. Works automatically.
16
16
 
17
17
  ## VS Code tunnel
18
18
 
19
- For remote development through a VS Code tunnel, start the server on the remote machine:
19
+ The VS Code extension uses a **direct webview** transport: the viewer runs
20
+ inside a VS Code webview panel and communicates with a Python subprocess via
21
+ the extension host. No port forwarding or public ports are needed — everything
22
+ stays inside the tunnel.
20
23
 
21
24
  ```bash
22
- # on the remote machine
23
- arrayview --serve
25
+ arrayview volume.nii.gz # opens in a webview tab automatically
26
+ ```
27
+
28
+ ### How it works
29
+
30
+ ```
31
+ Viewer (webview) ←postMessage→ Extension Host ←stdin/stdout→ Python
24
32
  ```
25
33
 
26
- Set port 8000 to Public in the VS Code Ports tab. Load arrays normally — each opens in Simple Browser:
34
+ Instead of a WebSocket connection to a running server, the extension spawns a
35
+ dedicated Python process per array. Slice requests travel through VS Code's
36
+ `postMessage` IPC and the extension relays them to Python's stdin as JSON.
37
+ Binary RGBA responses flow back through stdout with a length prefix.
38
+
39
+ This avoids the main limitation of the WebSocket approach: VS Code tunnels
40
+ don't expose arbitrary ports, so the old method required manually setting
41
+ port 8000 to "Public" in the Ports tab.
42
+
43
+ ### Fallback: WebSocket mode
44
+
45
+ If you prefer the traditional WebSocket server (e.g. for multi-hop setups or
46
+ when sharing the viewer URL), you can still use it:
27
47
 
28
48
  ```bash
29
- arrayview volume.nii.gz
49
+ arrayview --serve
30
50
  ```
31
51
 
52
+ Set port 8000 to Public in the VS Code Ports tab, then load arrays normally.
32
53
  The server persists across invocations. Kill it with `arrayview --kill`.
33
54
 
34
55
  ## Multi-hop
@@ -0,0 +1,74 @@
1
+ function arrayview(A, varargin)
2
+ % ARRAYVIEW View a numeric array in the ArrayView browser viewer.
3
+ %
4
+ % arrayview(A) view array, name taken from variable name
5
+ % arrayview(A, 'name', 'MyName') use custom display name
6
+ % arrayview(A, 'port', 8200) use custom port (default 8123)
7
+ %
8
+ % Requires arrayview installed in MATLAB's Python environment:
9
+ % % In your system Python or conda env:
10
+ % pip install arrayview
11
+ % % Then configure MATLAB to use it:
12
+ % pyenv('Version', '/path/to/python')
13
+ %
14
+ % For zero-copy (recommended for large arrays), arrayview() auto-enables
15
+ % in-process Python. Call arrayview() before any other py.* call in your
16
+ % session, or set it manually:
17
+ % pyenv('ExecutionMode', 'InProcess')
18
+
19
+ % --- Version guard ---
20
+ if verLessThan('matlab', '9.11') % 9.11 = R2021b
21
+ error('arrayview:unsupportedVersion', ...
22
+ 'arrayview() requires MATLAB R2021b (9.11) or later.');
23
+ end
24
+
25
+ % --- Auto-configure in-process Python for zero-copy ---
26
+ % Must happen before Python is first loaded in this session.
27
+ pe = pyenv();
28
+ if strcmp(pe.Status, 'NotLoaded')
29
+ pyenv('ExecutionMode', 'InProcess');
30
+ elseif strcmp(pe.ExecutionMode, 'OutOfProcess')
31
+ warning('arrayview:outOfProcess', '%s', ...
32
+ ['ArrayView: Python is running out-of-process — the array will be ' ...
33
+ 'copied (doubles memory).' newline 'To avoid this, restart MATLAB and call ' ...
34
+ 'arrayview() before any other py.* call.']);
35
+ end
36
+
37
+ % --- Parse arguments ---
38
+ defname = inputname(1);
39
+ if isempty(defname)
40
+ defname = 'Array';
41
+ end
42
+ p = inputParser;
43
+ addParameter(p, 'name', defname);
44
+ addParameter(p, 'port', 8123);
45
+ parse(p, varargin{:});
46
+
47
+ % --- Input validation ---
48
+ validateattributes(A, {'numeric', 'logical'}, {}, 'arrayview', 'A');
49
+
50
+ % --- Wrap array (zero-copy in in-process mode via buffer protocol) ---
51
+ try
52
+ np = py.importlib.import_module('numpy');
53
+ catch ME
54
+ error('arrayview:numpyNotFound', ...
55
+ ['NumPy not found in MATLAB''s Python environment.' newline ...
56
+ 'Install it with:' newline ...
57
+ ' pip install numpy' newline ...
58
+ 'Then restart MATLAB. (Error: %s)'], ME.message);
59
+ end
60
+ arr = np.asarray(A);
61
+
62
+ % --- Call arrayview.view() ---
63
+ try
64
+ av = py.importlib.import_module('arrayview');
65
+ catch ME
66
+ error('arrayview:notInstalled', ...
67
+ ['ArrayView Python package not found.' newline ...
68
+ 'Install it in MATLAB''s Python environment:' newline ...
69
+ ' pip install arrayview' newline ...
70
+ 'Then restart MATLAB. (Error: %s)'], ME.message);
71
+ end
72
+
73
+ av.view(arr, name=p.Results.name, port=int32(p.Results.port));
74
+ end
@@ -4,6 +4,8 @@ repo_url: https://github.com/oscarvanderheide/arrayview
4
4
 
5
5
  theme:
6
6
  name: material
7
+ logo: logo.png
8
+ favicon: logo.png
7
9
  palette:
8
10
  scheme: slate
9
11
  primary: black