ialdev-vis 0.2.2__tar.gz → 0.2.4__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 (58) hide show
  1. ialdev_vis-0.2.4/IMVIEW.md +223 -0
  2. {ialdev_vis-0.2.2 → ialdev_vis-0.2.4}/PKG-INFO +43 -5
  3. ialdev_vis-0.2.4/README.md +75 -0
  4. ialdev_vis-0.2.4/js/build.mjs +30 -0
  5. ialdev_vis-0.2.4/js/package-lock.json +454 -0
  6. ialdev_vis-0.2.4/js/package.json +12 -0
  7. ialdev_vis-0.2.4/js/src/canvas.ts +44 -0
  8. ialdev_vis-0.2.4/js/src/colormap.ts +42 -0
  9. ialdev_vis-0.2.4/js/src/controls.ts +298 -0
  10. ialdev_vis-0.2.4/js/src/grid.ts +137 -0
  11. ialdev_vis-0.2.4/js/src/index.ts +152 -0
  12. ialdev_vis-0.2.4/js/src/inspect.ts +192 -0
  13. ialdev_vis-0.2.4/js/src/labels.ts +208 -0
  14. ialdev_vis-0.2.4/js/src/model.ts +178 -0
  15. ialdev_vis-0.2.4/js/src/renderer/Canvas2DRenderer.ts +329 -0
  16. ialdev_vis-0.2.4/js/src/renderer/Renderer.ts +16 -0
  17. ialdev_vis-0.2.4/js/src/selection.ts +46 -0
  18. ialdev_vis-0.2.4/js/src/types.ts +58 -0
  19. ialdev_vis-0.2.4/js/tsconfig.json +12 -0
  20. {ialdev_vis-0.2.2 → ialdev_vis-0.2.4}/pyproject.toml +15 -4
  21. {ialdev_vis-0.2.2/src/iad/vis/colormaps → ialdev_vis-0.2.4/src/iad/vis}/__init__.py +0 -0
  22. ialdev_vis-0.2.4/src/iad/vis/gridcore.py +500 -0
  23. ialdev_vis-0.2.4/src/iad/vis/imview/__init__.py +9 -0
  24. ialdev_vis-0.2.4/src/iad/vis/imview/api.py +284 -0
  25. ialdev_vis-0.2.4/src/iad/vis/imview/colormaps.py +50 -0
  26. ialdev_vis-0.2.4/src/iad/vis/imview/data.py +614 -0
  27. ialdev_vis-0.2.4/src/iad/vis/imview/static/imgrid.css +201 -0
  28. ialdev_vis-0.2.4/src/iad/vis/imview/static/imgrid.js +1 -0
  29. ialdev_vis-0.2.4/src/iad/vis/imview/widget.py +178 -0
  30. {ialdev_vis-0.2.2 → ialdev_vis-0.2.4}/src/iad/vis/insight.py +44 -452
  31. ialdev_vis-0.2.4/src/iad/vis/mutils.py +311 -0
  32. ialdev_vis-0.2.4/src/iad/vis/plgrid.py +837 -0
  33. ialdev_vis-0.2.4/src/iad/vis/poly_to_mask/__init__.py +0 -0
  34. ialdev_vis-0.2.4/tests/test_imview.py +392 -0
  35. ialdev_vis-0.2.4/tests/test_plgrid.py +139 -0
  36. ialdev_vis-0.2.2/README.md +0 -45
  37. ialdev_vis-0.2.2/src/iad/vis/__init__.py +0 -6
  38. {ialdev_vis-0.2.2/src/iad/vis/poly_to_mask → ialdev_vis-0.2.4/src/iad/vis/colormaps}/__init__.py +0 -0
  39. {ialdev_vis-0.2.2 → ialdev_vis-0.2.4}/src/iad/vis/colormaps/blush_cm.py +0 -0
  40. {ialdev_vis-0.2.2 → ialdev_vis-0.2.4}/src/iad/vis/colormaps/glow_cm.py +0 -0
  41. {ialdev_vis-0.2.2 → ialdev_vis-0.2.4}/src/iad/vis/colormaps/rain.jscm +0 -0
  42. {ialdev_vis-0.2.2 → ialdev_vis-0.2.4}/src/iad/vis/colormaps/rain_cm.py +0 -0
  43. {ialdev_vis-0.2.2 → ialdev_vis-0.2.4}/src/iad/vis/colormaps/smooth_cm.py +0 -0
  44. {ialdev_vis-0.2.2 → ialdev_vis-0.2.4}/src/iad/vis/colormaps/wide_cm.py +0 -0
  45. {ialdev_vis-0.2.2 → ialdev_vis-0.2.4}/src/iad/vis/dotstyle.py +0 -0
  46. {ialdev_vis-0.2.2 → ialdev_vis-0.2.4}/src/iad/vis/embedding_in_qt5.py +0 -0
  47. {ialdev_vis-0.2.2 → ialdev_vis-0.2.4}/src/iad/vis/imageviewer.py +0 -0
  48. {ialdev_vis-0.2.2 → ialdev_vis-0.2.4}/src/iad/vis/interact.py +0 -0
  49. {ialdev_vis-0.2.2 → ialdev_vis-0.2.4}/src/iad/vis/ipv.py +0 -0
  50. {ialdev_vis-0.2.2 → ialdev_vis-0.2.4}/src/iad/vis/jupyter.py +0 -0
  51. {ialdev_vis-0.2.2 → ialdev_vis-0.2.4}/src/iad/vis/mpl_styles.py +0 -0
  52. {ialdev_vis-0.2.2 → ialdev_vis-0.2.4}/src/iad/vis/mpl_utils.py +0 -0
  53. {ialdev_vis-0.2.2 → ialdev_vis-0.2.4}/src/iad/vis/poly_to_mask/README.org +0 -0
  54. {ialdev_vis-0.2.2 → ialdev_vis-0.2.4}/src/iad/vis/poly_to_mask/example.py +0 -0
  55. {ialdev_vis-0.2.2 → ialdev_vis-0.2.4}/src/iad/vis/poly_to_mask/roipoly.py +0 -0
  56. {ialdev_vis-0.2.2 → ialdev_vis-0.2.4}/src/iad/vis/view3d.py +0 -0
  57. {ialdev_vis-0.2.2 → ialdev_vis-0.2.4}/tests/test_dotstyle.py +0 -0
  58. {ialdev_vis-0.2.2 → ialdev_vis-0.2.4}/tests/test_insight.py +0 -0
@@ -0,0 +1,223 @@
1
+ # imview — interactive image grid
2
+
3
+ `iad.vis.imview` is the anywidget-based image grid for marimo and Jupyter. It
4
+ replaces JSON heatmaps with binary pixel transport and client-side rendering.
5
+
6
+ ## Capabilities
7
+
8
+ | Feature | Where | Notes |
9
+ |---------|-------|-------|
10
+ | Multi-panel grids | Python layout | Regular `(rows, cols)` or mosaic strings |
11
+ | Scalar + RGB panels | `data.py` | Auto-detect; grayscale RGB collapsed to scalar |
12
+ | Colormaps + clim | Frontend | LUTs built in Python, applied in browser |
13
+ | Pan / zoom | `grid.ts` | Per-panel view window; nearest-neighbor upscale |
14
+ | Pixel inspect | `inspect.ts` | Fixed-width coordinate/value readout |
15
+ | Axis ticks | `labels.ts` | Follow visible window during pan/zoom |
16
+ | Colorbars | Python layout + renderer | Scalar panels only |
17
+ | Static oversampling | `data.py` | One-time integer downsample in Python |
18
+ | `figsize` sizing | `data.py` + CSS | Reference CSS px; 240 px min per dimension |
19
+ | `max_zoom` / `downsample` | `data.py` | Control buffer resolution vs. transfer size |
20
+ | Data budget readout | Toolbar | MB / Mpx sent vs. full; red when over budget |
21
+ | Resolution badge | `labels.ts` | Per-panel `(N:1)` ratio, updates with zoom |
22
+ | In-place updates | `ImageGrid.update_data` | Same shapes; reuses prep kwargs |
23
+ | marimo / Jupyter | `api.py` | Auto backend; `.ui` for layout composition |
24
+
25
+ ## Architecture
26
+
27
+ ```
28
+ Python Browser (imgrid.js)
29
+ ───────────────────────────────── ────────────────────────────────
30
+ imgrid() index.ts (entry)
31
+ └─ prepare_grid / data.py ├─ GridModel (trait bridge)
32
+ layout, downsample, pack ├─ Canvas2DRenderer
33
+ └─ ImageGridWidget.create ├─ LabelsOverlay (ticks, titles)
34
+ traitlets → binary buffers ├─ controls (toolbar)
35
+ └─ ImageGrid wrapper ├─ inspect (hover readout)
36
+ display / update_data └─ grid (pan/zoom)
37
+ ```
38
+
39
+ **Static oversampling:** Python chooses an integer downsample factor per panel,
40
+ packs buffers once, and sends them over anywidget binary comm. The frontend
41
+ draws a sub-window of the buffer for pan/zoom. Upscaling past buffer detail
42
+ uses nearest-neighbor interpolation; downscaling stays smooth.
43
+
44
+ **Layout:** All panel rects, colorbar positions, and canvas size are computed
45
+ in Python (`_display_layout`) as reference CSS pixels. The frontend scales
46
+ to the display width (driven by `figsize`) while preserving aspect ratio.
47
+
48
+ ## Package layout
49
+
50
+ ```
51
+ vis/
52
+ ├── IMVIEW.md # this file
53
+ ├── README.md # package overview + install
54
+ ├── js/ # TypeScript sources (build → static/imgrid.js)
55
+ │ └── src/
56
+ │ ├── index.ts # anywidget render entry, wiring
57
+ │ ├── model.ts # trait getters (panels, view, data_*)
58
+ │ ├── canvas.ts # HiDPI canvas sync
59
+ │ ├── grid.ts # pan/zoom, view state
60
+ │ ├── controls.ts # toolbar, data readout, clim/cmap toggles
61
+ │ ├── inspect.ts # pixel hover readout
62
+ │ ├── labels.ts # titles, axis ticks, resolution badge
63
+ │ ├── selection.ts # panel selection state
64
+ │ ├── colormap.ts # scalar recoloring
65
+ │ ├── types.ts # PanelMeta, ViewState, …
66
+ │ └── renderer/
67
+ │ ├── Renderer.ts # interface
68
+ │ └── Canvas2DRenderer.ts
69
+ ├── src/iad/vis/
70
+ │ ├── gridcore.py # shared grid/mosaic/resize helpers
71
+ │ ├── mutils.py # marimo mogrid(); backend='wgt' → imview
72
+ │ └── imview/
73
+ │ ├── __init__.py # exports imgrid, ImageGrid
74
+ │ ├── api.py # imgrid(), ImageGrid
75
+ │ ├── data.py # prepare_grid*, layout, downsample
76
+ │ ├── widget.py # anywidget traits + apply_prepared
77
+ │ ├── colormaps.py # matplotlib LUT → bytes
78
+ │ └── static/
79
+ │ ├── imgrid.js # built bundle
80
+ │ └── imgrid.css
81
+ └── tests/test_imview.py
82
+ ```
83
+
84
+ ## Public API
85
+
86
+ ### `imgrid(...)`
87
+
88
+ Main entry point. Returns an `ImageGrid` unless `out=` requests a component.
89
+
90
+ ```python
91
+ from iad.vis.imview import imgrid
92
+
93
+ grid = imgrid(
94
+ left, right, diff,
95
+ titles=["left", "right", "diff"],
96
+ figsize=(900, None),
97
+ max_zoom=2,
98
+ clim="auto",
99
+ )
100
+ ```
101
+
102
+ ### `ImageGrid`
103
+
104
+ | Attribute / method | Description |
105
+ |--------------------|-------------|
106
+ | `.widget` | Raw anywidget instance (traits, buffers) |
107
+ | `.ui` | marimo `mo.ui.anywidget(...)` when backend is marimo |
108
+ | `.value` | `{'cursor', 'selection', 'view'}` reactive state |
109
+ | `.panels` | Python `PanelData` list from preparation |
110
+ | `.update_data(data)` | Replace buffers in place (dict by title or sequence) |
111
+
112
+ ### marimo usage
113
+
114
+ ```python
115
+ # Single grid — return as last expression
116
+ grid = imgrid(a, b, figsize=(800, None))
117
+
118
+ # Stack multiple grids — use .ui
119
+ mo.vstack([grid1.ui, grid2.ui])
120
+
121
+ # Reactive readout
122
+ grid.value["cursor"] # current hover panel + coords
123
+ ```
124
+
125
+ Via `mutils`:
126
+
127
+ ```python
128
+ from iad.vis.mutils import mogrid, Backend
129
+
130
+ mogrid(a, b, backend=Backend.WGT, figsize=(800, 600), max_zoom=2)
131
+ ```
132
+
133
+ ### Preparation API (lower level)
134
+
135
+ ```python
136
+ from iad.vis.imview.data import prepare_grid, prepare_grid_from_parsed
137
+
138
+ prepared = prepare_grid(img, titles=["a"], figsize=(600, 400), max_zoom=1.5)
139
+ # prepared.panels, prepared.canvas_size, prepared.sent_bytes, …
140
+ ```
141
+
142
+ ## Key parameters
143
+
144
+ ### `figsize=(width, height)`
145
+
146
+ Target grid size in CSS pixels. Either dimension may be `None`:
147
+
148
+ - `(800, None)` — fit width 800, height from aspect ratio + chrome
149
+ - `(None, 600)` — fit height 600
150
+ - `(800, 600)` — fit inside both bounds
151
+
152
+ Panel aspect ratios always match the source images. Each dimension has a
153
+ **240 px minimum** (`_MIN_PANEL_PX`).
154
+
155
+ ### `max_zoom` vs `downsample`
156
+
157
+ Mutually exclusive.
158
+
159
+ | Mode | Effect |
160
+ |------|--------|
161
+ | *(default)* | Auto factor from `max_pixels` budget |
162
+ | `max_zoom=2` | Buffer ≥ 2× panel display size (crisp 2× zoom headroom) |
163
+ | `max_zoom='full'` | Factor 1 — full resolution sent |
164
+ | `downsample=4` | Fixed 4× block-mean downsample |
165
+
166
+ When `max_zoom` or `downsample` is set explicitly and total sent pixels exceed
167
+ `max_pixels * n_panels`, the toolbar readout turns red (`data_over_budget`).
168
+
169
+ ### `update_data`
170
+
171
+ ```python
172
+ grid.update_data({"left": new_left, "right": new_right})
173
+ grid.update_data([arr0, arr1]) # panel order
174
+ ```
175
+
176
+ Arrays must match original shapes. Uses the same `prep_kwargs` as initial
177
+ creation (cmap, clim, figsize, downsample, …).
178
+
179
+ ## Widget traits (Python ↔ JS)
180
+
181
+ | Trait | Direction | Purpose |
182
+ |-------|-----------|---------|
183
+ | `panels` | → JS | Metadata: layout, clim, factor, source dims |
184
+ | `buffers` | → JS | Binary pixel data (float32 scalar / uint8 RGBA) |
185
+ | `luts` | → JS | Colormap byte blobs |
186
+ | `canvas_width/height` | → JS | Reference layout size |
187
+ | `data_sent_*`, `data_full_*` | → JS | Transfer accounting |
188
+ | `view` | ↔ | `{scale, tx, ty}` pan/zoom |
189
+ | `cursor`, `selection` | ← JS | Inspect / selection state |
190
+ | `cbar`, `ticks`, `show_grid`, `adj_clim` | ↔ | Display toggles |
191
+
192
+ ## Frontend modules
193
+
194
+ | Module | Role |
195
+ |--------|------|
196
+ | `Canvas2DRenderer` | Draw panels, colorbars, grid overlay; nearest upscale |
197
+ | `LabelsOverlay` | DOM overlay for titles, ticks (pan/zoom-aware), res badge |
198
+ | `attachPanZoom` | Wheel zoom + drag pan; updates `view` trait |
199
+ | `attachInspect` | Hover readout with tabular-nums formatting |
200
+ | `buildToolbar` | Cmap/clim controls, data MB/Mpx readout |
201
+ | `GridModel` | Typed accessors over anywidget model traits |
202
+
203
+ ## Build (developers)
204
+
205
+ ```bash
206
+ cd vis/js && npm install && npm run build
207
+ # writes vis/src/iad/vis/imview/static/imgrid.js
208
+ ```
209
+
210
+ Run tests:
211
+
212
+ ```bash
213
+ pixi run pytest vis/tests/test_imview.py
214
+ ```
215
+
216
+ ## Related backends
217
+
218
+ | Module | Backend | Use case |
219
+ |--------|---------|----------|
220
+ | `iad.vis.imview` | anywidget | Interactive notebooks (this doc) |
221
+ | `iad.vis.insight` | matplotlib | Desktop / static figures |
222
+ | `iad.vis.plgrid` | Plotly | Lightweight overview plots |
223
+ | `iad.vis.mutils.mogrid` | switchable | marimo helper; `backend='wgt'` → imview |
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ialdev-vis
3
- Version: 0.2.2
3
+ Version: 0.2.4
4
4
  Summary: iad.vis — visualization utilities (image grids, viewers, colormaps, matplotlib helpers)
5
5
  Author: ipcoder
6
6
  Requires-Python: >=3.10
@@ -12,19 +12,25 @@ Classifier: Programming Language :: Python :: 3
12
12
  Classifier: Programming Language :: Python :: 3.10
13
13
  Classifier: Programming Language :: Python :: 3.11
14
14
  Classifier: Programming Language :: Python :: 3.12
15
- Requires-Dist: ialdev-core>=0.2.4
16
- Requires-Dist: ialdev-io>=0.2.2
15
+ Requires-Dist: ialdev-core>=0.2.6
16
+ Requires-Dist: ialdev-io>=0.2.4
17
17
  Requires-Dist: matplotlib>=3.5.0
18
18
  Requires-Dist: numpy>=1.26.4,<2
19
19
  Requires-Dist: regex>=2021.0.0
20
20
  Requires-Dist: open3d>=0.15.0 ; extra == "3d"
21
21
  Requires-Dist: ipyvolume>=0.6.0 ; extra == "3d"
22
- Requires-Dist: ialdev-vis[graphviz, qt, jupyter, 3d, dev]>=0.2.2 ; extra == "all"
22
+ Requires-Dist: ialdev-vis[graphviz, qt, jupyter, notebook, marimo, 3d, dev]>=0.2.4 ; extra == "all"
23
23
  Requires-Dist: pytest>=7.0.0 ; extra == "dev"
24
24
  Requires-Dist: pytest-cov>=3.0.0 ; extra == "dev"
25
25
  Requires-Dist: pygraphviz>=1.14,<2 ; extra == "graphviz"
26
26
  Requires-Dist: ipywidgets>=7.0.0 ; extra == "jupyter"
27
27
  Requires-Dist: IPython>=7.0.0 ; extra == "jupyter"
28
+ Requires-Dist: plotly>=5.20 ; extra == "jupyter"
29
+ Requires-Dist: anywidget>=0.9 ; extra == "jupyter"
30
+ Requires-Dist: marimo>=0.23 ; extra == "marimo"
31
+ Requires-Dist: plotly>=5.20 ; extra == "marimo"
32
+ Requires-Dist: pandas>=2.0.0 ; extra == "marimo"
33
+ Requires-Dist: anywidget>=0.9 ; extra == "notebook"
28
34
  Requires-Dist: PyQt5>=5.15.0 ; extra == "qt"
29
35
  Requires-Dist: scikit-image>=0.19.0 ; extra == "qt"
30
36
  Project-URL: Homepage, https://github.com/ipcoder/ialdev/tree/master/vis
@@ -35,6 +41,8 @@ Provides-Extra: all
35
41
  Provides-Extra: dev
36
42
  Provides-Extra: graphviz
37
43
  Provides-Extra: jupyter
44
+ Provides-Extra: marimo
45
+ Provides-Extra: notebook
38
46
  Provides-Extra: qt
39
47
 
40
48
  # ialdev-vis
@@ -54,6 +62,8 @@ Optional extras:
54
62
  ```bash
55
63
  pip install "ialdev-vis[qt]"
56
64
  pip install "ialdev-vis[jupyter]"
65
+ pip install "ialdev-vis[notebook]" # anywidget interactive image grid (imview)
66
+ pip install "ialdev-vis[marimo]"
57
67
  pip install "ialdev-vis[3d]"
58
68
  pip install "ialdev-vis[all]"
59
69
  ```
@@ -63,6 +73,7 @@ Requires Python `>=3.10`.
63
73
  ## Highlights
64
74
 
65
75
  - `imgrid` and `imhist` for fast inspection of images and distributions.
76
+ - `iad.vis.imview.imgrid` — interactive notebook image grid (marimo / Jupyter) via anywidget; static oversampling, `figsize` layout, client-side colormap/clim/zoom, mosaic layouts, data-budget readout, and cross-panel inspection. See [IMVIEW.md](IMVIEW.md).
66
77
  - Matplotlib helpers for figure capture and conversion to arrays/PIL images.
67
78
  - Built-in custom colormaps.
68
79
  - Polygon-to-mask helpers and interactive ROI tools.
@@ -71,7 +82,7 @@ Requires Python `>=3.10`.
71
82
  ## Examples
72
83
 
73
84
  ```python
74
- from iad.vis import imgrid, imhist
85
+ from iad.vis.insight import imgrid, imhist
75
86
 
76
87
  imgrid(left_image, right_image, titles=["left", "right"], clim="auto")
77
88
  imhist(left_image, right_image, titles=["left", "right"])
@@ -83,3 +94,30 @@ from iad.vis.mpl_utils import fig2img
83
94
  pil_image = fig2img(figure)
84
95
  ```
85
96
 
97
+ ### Interactive image grid in marimo / Jupyter (`imview`)
98
+
99
+ See **[IMVIEW.md](IMVIEW.md)** for architecture, parameters (`figsize`, `max_zoom`, `downsample`), module layout, and marimo stacking patterns.
100
+
101
+ ```python
102
+ from iad.vis.imview import imgrid
103
+ import marimo as mo
104
+
105
+ grid = imgrid(left, right, diff, titles=["left", "right", "diff"], figsize=(900, None), max_zoom=2)
106
+ grid.ui # use in mo.vstack / mo.hstack
107
+ grid.value # reactive cursor, selection, view state
108
+ grid.update_data({"left": new_left}) # in-place buffer refresh
109
+ ```
110
+
111
+ In marimo, `iad.vis.mutils.mogrid(..., backend='wgt')` routes to the same anywidget backend.
112
+
113
+ Rebuild the frontend after editing TypeScript (widget developers only):
114
+
115
+ ```bash
116
+ cd vis/js && npm install && npm run build
117
+ # or: pixi run build-imview-js (requires pixi feature build-js / nodejs)
118
+ ```
119
+
120
+ **Roadmap:** WebGL renderer (large images), ROI / line-profile tools, live histogram panel, linked selections into pandas/marimo cells.
121
+
122
+ **Note:** `iad.vis.plgrid` remains a lightweight Plotly overview option; desktop/Qt inspection still uses `iad.vis.insight.imgrid` (matplotlib).
123
+
@@ -0,0 +1,75 @@
1
+ # ialdev-vis
2
+
3
+ Visualization utilities for the `iad` toolbox, published as `ialdev-vis` and imported as `iad.vis`.
4
+
5
+ Use this package for quick image grids, histograms, Matplotlib helpers, custom colormaps, interactive annotation widgets, Jupyter logging, and optional Qt/3D visualization tools.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ pip install ialdev-vis
11
+ ```
12
+
13
+ Optional extras:
14
+
15
+ ```bash
16
+ pip install "ialdev-vis[qt]"
17
+ pip install "ialdev-vis[jupyter]"
18
+ pip install "ialdev-vis[notebook]" # anywidget interactive image grid (imview)
19
+ pip install "ialdev-vis[marimo]"
20
+ pip install "ialdev-vis[3d]"
21
+ pip install "ialdev-vis[all]"
22
+ ```
23
+
24
+ Requires Python `>=3.10`.
25
+
26
+ ## Highlights
27
+
28
+ - `imgrid` and `imhist` for fast inspection of images and distributions.
29
+ - `iad.vis.imview.imgrid` — interactive notebook image grid (marimo / Jupyter) via anywidget; static oversampling, `figsize` layout, client-side colormap/clim/zoom, mosaic layouts, data-budget readout, and cross-panel inspection. See [IMVIEW.md](IMVIEW.md).
30
+ - Matplotlib helpers for figure capture and conversion to arrays/PIL images.
31
+ - Built-in custom colormaps.
32
+ - Polygon-to-mask helpers and interactive ROI tools.
33
+ - Optional Qt image viewer and optional `ipyvolume`/Open3D 3D views.
34
+
35
+ ## Examples
36
+
37
+ ```python
38
+ from iad.vis.insight import imgrid, imhist
39
+
40
+ imgrid(left_image, right_image, titles=["left", "right"], clim="auto")
41
+ imhist(left_image, right_image, titles=["left", "right"])
42
+ ```
43
+
44
+ ```python
45
+ from iad.vis.mpl_utils import fig2img
46
+
47
+ pil_image = fig2img(figure)
48
+ ```
49
+
50
+ ### Interactive image grid in marimo / Jupyter (`imview`)
51
+
52
+ See **[IMVIEW.md](IMVIEW.md)** for architecture, parameters (`figsize`, `max_zoom`, `downsample`), module layout, and marimo stacking patterns.
53
+
54
+ ```python
55
+ from iad.vis.imview import imgrid
56
+ import marimo as mo
57
+
58
+ grid = imgrid(left, right, diff, titles=["left", "right", "diff"], figsize=(900, None), max_zoom=2)
59
+ grid.ui # use in mo.vstack / mo.hstack
60
+ grid.value # reactive cursor, selection, view state
61
+ grid.update_data({"left": new_left}) # in-place buffer refresh
62
+ ```
63
+
64
+ In marimo, `iad.vis.mutils.mogrid(..., backend='wgt')` routes to the same anywidget backend.
65
+
66
+ Rebuild the frontend after editing TypeScript (widget developers only):
67
+
68
+ ```bash
69
+ cd vis/js && npm install && npm run build
70
+ # or: pixi run build-imview-js (requires pixi feature build-js / nodejs)
71
+ ```
72
+
73
+ **Roadmap:** WebGL renderer (large images), ROI / line-profile tools, live histogram panel, linked selections into pandas/marimo cells.
74
+
75
+ **Note:** `iad.vis.plgrid` remains a lightweight Plotly overview option; desktop/Qt inspection still uses `iad.vis.insight.imgrid` (matplotlib).
@@ -0,0 +1,30 @@
1
+ import * as esbuild from 'esbuild';
2
+ import { mkdirSync } from 'node:fs';
3
+ import { dirname, resolve } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+
6
+ const root = dirname(fileURLToPath(import.meta.url));
7
+ const outFile = resolve(root, '../src/iad/vis/imview/static/imgrid.js');
8
+ mkdirSync(dirname(outFile), { recursive: true });
9
+
10
+ const watch = process.argv.includes('--watch');
11
+
12
+ const ctx = await esbuild.context({
13
+ entryPoints: [resolve(root, 'src/index.ts')],
14
+ bundle: true,
15
+ format: 'esm',
16
+ platform: 'browser',
17
+ target: ['es2020'],
18
+ outfile: outFile,
19
+ minify: !watch,
20
+ sourcemap: watch,
21
+ });
22
+
23
+ if (watch) {
24
+ await ctx.watch();
25
+ console.log('watching imview bundle...');
26
+ } else {
27
+ await ctx.rebuild();
28
+ await ctx.dispose();
29
+ console.log('built', outFile);
30
+ }