|
| 1 | +# Viewer debug notes |
| 2 | + |
| 3 | +## 1. Call graph |
| 4 | +- `v.plot()` builds a `PlotOptions` object and wraps an inner `_plot` that materializes virtual cubes, infers dims, and returns a configured `CubePlot` with geom/axes/theme set. The function returns either the `Verb` or the resulting `CubePlot`. 【F:src/cubedynamics/verbs/plot.py†L17-L108】 |
| 5 | +- `CubePlot.to_html()` prepares stats/annotations and calls `_render_viewer`, which constructs the viewer HTML via `cube_from_dataarray` with styling and legend metadata. `_repr_html_` simply delegates to `to_html()`. 【F:src/cubedynamics/plotting/cube_plot.py†L582-L804】【F:src/cubedynamics/plotting/cube_plot.py†L836-L839】 |
| 6 | +- `_render_viewer` hands off to `cube_from_dataarray` in `cube_viewer.py`, which renders faces/interior slices to base64 PNGs and assembles the WebGL viewer template. This template is the only HTML/JS builder on the Python side. 【F:src/cubedynamics/plotting/cube_plot.py†L629-L684】【F:src/cubedynamics/plotting/cube_viewer.py†L1-L120】 |
| 7 | + |
| 8 | +## 2. Python types |
| 9 | +Running `python tools/debug_viewer_pipeline.py` prints: |
| 10 | +``` |
| 11 | +CubePlot type: <class 'cubedynamics.plotting.cube_plot.CubePlot'> |
| 12 | +v.plot return type: <class 'cubedynamics.plotting.cube_plot.CubePlot'> |
| 13 | +``` |
| 14 | +So `v.plot()` still returns a `CubePlot` object. 【27a0d3†L1-L2】 |
| 15 | + |
| 16 | +## 3. Logging |
| 17 | +- Added logging hooks: `v.plot()` now logs the cube name/dims when invoked; `CubePlot._repr_html_` logs when the HTML repr is requested. 【F:src/cubedynamics/verbs/plot.py†L81-L84】【F:src/cubedynamics/plotting/cube_plot.py†L836-L839】 |
| 18 | +- Enable by configuring `logging.basicConfig(level=logging.INFO)` in a notebook/kernel; watch stdout/stderr for calls when rendering. |
| 19 | + |
| 20 | +## 4. Performance harness |
| 21 | +- `notebooks/cube_viewer_perf.ipynb` builds full/half/quarter-resolution NDVI cubes and renders them with `v.plot(debug=True)`. |
| 22 | + Record a Performance trace in Chrome and confirm `[CubeViewer debug] draw start/end` logs only appear while dragging or zooming. |
| 23 | + |
| 24 | +## 5. HTML/JS template |
| 25 | +- The viewer HTML is entirely generated in `cube_from_dataarray` and `_render_cube_html`. It currently uses a custom WebGL wireframe cube (`canvas.getContext("webgl")` plus manual shaders) rather than the previous Lexcube integration—no references to Lexcube remain. 【F:src/cubedynamics/plotting/cube_viewer.py†L90-L195】【F:src/cubedynamics/plotting/cube_viewer.py†L374-L520】 |
| 26 | +- The HTML builds a cube wrapper with `<canvas id="cube-canvas-{fig_id}">` and overlays axis labels/legend, but the JS only draws a wireframe cube; face textures are never applied to the canvas. PNG faces are still generated, but `_render_cube_html` only uses them as CSS backgrounds for `div` planes, which are missing in the current WebGL path. 【F:src/cubedynamics/plotting/cube_viewer.py†L30-L88】【F:src/cubedynamics/plotting/cube_viewer.py†L471-L520】 |
| 27 | +- No alternative templates are present; the current template is the single path invoked by `CubePlot`. |
| 28 | + |
| 29 | +## 6. JS console |
| 30 | +- Added guard logging around the viewer script; browser consoles should now show `[CubeViewer] script starting` and report `[CubeViewer] top-level error` if the script throws early. 【F:src/cubedynamics/plotting/cube_viewer.py†L369-L520】 |
| 31 | +- To capture errors: open DevTools → Console after running `pipe(ndvi) | v.plot()`; watch for those messages alongside any WebGL errors. |
| 32 | + |
| 33 | +## 7. Double render? |
| 34 | +- Searches show no `IPython.display.display` calls in plotting/verbs; rendering relies solely on the `CubePlot` return value and its `_repr_html_`. No evidence of double display. 【dbd202†L1-L1】 |
| 35 | + |
| 36 | +## 8. Eager loads |
| 37 | +- Face PNGs and interior planes call `.values` on slices; this is necessary for encoding small 2D images. Bulk operations include downsampling via `coarsen(...).mean()` for interior planes. Potentially heavy if the cube is large and `thin_time_factor` is small. 【F:src/cubedynamics/plotting/cube_viewer.py†L638-L718】【F:src/cubedynamics/plotting/cube_viewer.py†L828-L868】 |
| 38 | +- Coordinate metadata lookups use `coord.values` but are lightweight. 【F:src/cubedynamics/plotting/cube_plot.py†L446-L474】 |
| 39 | + |
| 40 | +## 9. Hypotheses |
| 41 | +- **H1:** Viewer shows blank center because the JS path now draws only a green wireframe cube; PNG face textures (data slices) are not being mapped anywhere in the WebGL canvas. The DOM also lacks the Lexcube/CSS 3D elements that previously displayed face images. 【F:src/cubedynamics/plotting/cube_viewer.py†L374-L520】【F:src/cubedynamics/plotting/cube_viewer.py†L30-L88】 |
| 42 | +- **H2:** Any WebGL init failure would now surface via `[CubeViewer] top-level error`; if errors appear, the script may be failing before draw (e.g., shader issues), leaving a blank canvas. 【F:src/cubedynamics/plotting/cube_viewer.py†L369-L520】 |
| 43 | +- **H3:** Slowness likely comes from full-face `.values` extraction and color mapping for each face plus interior downsampling; large cubes will still materialize multiple slices eagerly before rendering. 【F:src/cubedynamics/plotting/cube_viewer.py†L638-L718】【F:src/cubedynamics/plotting/cube_viewer.py†L828-L868】 |
| 44 | + |
| 45 | +## 10. Interaction regressions (2025-03) |
| 46 | +- **What changed?** Drag setup was refactored to share pointer/mouse/touch start logic and attach move/end listeners to `window` so rotation keeps flowing even if the pointer leaves the drag surface. Pointer capture is attempted on the drag overlay but gracefully skipped when unsupported. Drag sessions now track the active pointer/touch identifier and clear any stale listeners before beginning a new drag to prevent cross-pointer interference. 【F:src/cubedynamics/plotting/cube_viewer.py†L353-L472】 |
| 47 | +- **How to debug:** |
| 48 | + - Open DevTools and watch for `[CubeViewer] drag start/move/end` console logs when interacting with the cube. Absence of logs suggests the event listeners are not attaching (e.g., scripts blocked) or the drag surface is not present. |
| 49 | + - Verify the transparent drag surface exists with `document.getElementById("cube-drag-surface-<fig_id>")`; rotation depends on this element being on top of the cube. |
| 50 | + - Pointer capture failures are expected on some touch devices; the viewer falls back to window-level listeners. If moves stop mid-drag, confirm the move/end listeners are on `window` via `getEventListeners(window)` (in Chromium-based devtools) or by adding `window.addEventListener` breakpoints. |
| 51 | + - If drag motion stutters on multi-touch devices, inspect `activePointerId`/`activeTouchId` in the embedded script to ensure the move handler is gating events to the current pointer ID; stale listeners are cleared at drag start, so seeing multiple active IDs usually means the drag surface never received `pointerup/touchend`. |
| 52 | + - Zoom uses the wheel handler on the drag surface; if scroll-to-zoom stops working, inspect whether the `wheel` listener is blocked by the notebook or page-level scroll container. |
| 53 | + |
| 54 | +## 11. Rotation/zoom expectations (2025-05) |
| 55 | +- Rotation is applied around the cube’s center via `applyCubeRotation()`; if you see skewing or off-center rotation, inspect the inline handler that updates `rotationX`/`rotationY` during drag gestures before the transform is applied. 【F:src/cubedynamics/plotting/cube_viewer.py†L590-L647】 |
| 56 | +- Zoom should bring the cube closer (larger on screen). In DevTools, watch the logged `zoom` value in the `wheel` handler; if the cube shrinks when you zoom in, confirm the exponential zoom factor is clamped between `zoomMin` and `zoomMax`. 【F:src/cubedynamics/plotting/cube_viewer.py†L723-L730】 |
| 57 | + |
| 58 | +## 12. Interactivity hooks (2025-05) |
| 59 | +- The root viewer element now carries deterministic IDs (`cube-figure-<id>`) plus `data-debug`/`data-fig-id` attributes so the inline script can always locate the DOM node, even when Jupyter wraps outputs. The debug flag enables `[CubeViewer debug]` console logs for pointer/mouse/touch/wheel events. 【F:src/cubedynamics/plotting/cube_viewer.py†L200-L236】【F:src/cubedynamics/plotting/cube_viewer.py†L529-L596】 |
| 60 | +- PointerEvents, mouse, and touch listeners are always attached to the drag surface; wheel zoom uses a non-passive handler to prevent default scrolling. Event logs emit pointer/touch identifiers to help debug Safari or embedded-notebook quirks. 【F:src/cubedynamics/plotting/cube_viewer.py†L597-L705】 |
| 61 | +- `_write_demo_html()` emits a standalone `cube_demo.html` with color blocks so developers can validate drag/zoom outside of notebooks before shipping changes. 【F:src/cubedynamics/plotting/cube_viewer.py†L1032-L1072】 |
0 commit comments