Skip to content

Enhance interactive 3D viz: overlays, server-side rendering, fast playback#1310

Draft
sbryngelson wants to merge 1 commit intoMFlowCode:masterfrom
sbryngelson:viz-updates
Draft

Enhance interactive 3D viz: overlays, server-side rendering, fast playback#1310
sbryngelson wants to merge 1 commit intoMFlowCode:masterfrom
sbryngelson:viz-updates

Conversation

@sbryngelson
Copy link
Member

Summary

  • New features: contour overlays (2D/3D), isosurface/isovolume mixing, solid color isosurfaces, opacity control, improved timestep slider
  • Server-side rendering: kaleido renders Plotly figures to JPEG on Linux for fast 3D playback over SSH tunnels (bypasses JSON serialization + browser WebGL round-trip)
  • Playback performance: aggressive data prefetch (3 workers, 15 steps ahead, 40-entry cache), 3D mesh prefetch (3 workers, 50K cell budget), forced Dash patch path during playback — cached frames render in ~0.002s

Dependencies

  • Add kaleido for server-side Plotly image export (Linux SSH playback)
  • Remove pyvista (replaced by kaleido — simpler, identical visual output)

Test plan

  • ./mfc.sh precheck -j 8 passes
  • 2D interactive viz (./mfc.sh viz <2d_dir> -i) works as before
  • 3D isosurface/volume playback on macOS (local browser, no kaleido)
  • 3D isosurface/volume playback on Linux over SSH tunnel (kaleido path)
  • Contour overlays render correctly in 2D and 3D slice modes
  • Overlay variable mixing (isosurface + isovolume) works in 3D

🤖 Generated with Claude Code

@github-actions
Copy link

github-actions bot commented Mar 14, 2026

(review resolved)

@github-actions
Copy link

github-actions bot commented Mar 14, 2026

(review resolved)

@github-actions
Copy link

github-actions bot commented Mar 14, 2026

(review resolved)

…yback

Major interactive visualization improvements:

**New features:**
- Contour overlays (2D/3D), isosurface/isovolume mixing
- Solid color isosurfaces, opacity control, improved timestep slider
- Server-side rendering via kaleido on Linux for fast 3D playback over SSH

**Playback performance:**
- Aggressive data prefetch: 3 workers, 15 steps ahead, 40-entry cache
- 3D mesh prefetch: 3 workers, 50K cell budget during playback
- Force Dash patch path during playback to avoid full re-renders
- Prefetch keeps cache warm so playback hits ~0.002s/frame

**Dependencies:**
- Add kaleido for server-side Plotly figure rendering (Linux SSH)
- Remove pyvista (replaced by kaleido)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions
Copy link

Claude Code Review

Head SHA: d46ca53

Files changed (3):

  • toolchain/mfc/viz/_step_cache.py
  • toolchain/mfc/viz/interactive.py
  • toolchain/pyproject.toml

Summary

  • Adds contour overlays (2D/3D), solid-color/opacity isosurface controls, and isosurface/isovolume overlay mixing for 3D
  • Server-side rendering via kaleido on Linux for fast 3D playback over SSH tunnels
  • Aggressive 3D mesh prefetch cache (40-entry, 3-worker pool) with a coarse/fine resolution split during playback
  • Timestep dropdown replaced with a slider + hidden dcc.Store that holds the actual step value
  • _step_cache cache doubled (20→40) and prefetch pool tripled (1→3 workers)

Findings

1. kaleido as an unconditional hard dependency — toolchain/pyproject.toml line +6

"kaleido",

The code already gracefully handles missing kaleido via _kaleido_available() and a full fallback path. Making it a mandatory install forces all users (macOS, Windows, clusters without network access) to pull in kaleido, which embeds Chromium/V8 and has known platform-specific install failures. Recommend making it optional, e.g. conditional on platform or as a [project.optional-dependencies] extra:

"kaleido; sys_platform == 'linux'",

or just removing it from pyproject.toml entirely since the runtime probe already handles the absent case.

2. Wrong transform applied to overlay variable in 3D isosurface overlay — interactive.py around diff line 1246

_ov_vx, _ov_vy, _ov_vz, _ov_fi, _ov_fj, _ov_fk, _ov_int =     _compute_isomesh(
        _ov_ds, _ox, _oy, _oz,
        _tf, _ov_ilo, _ov_ihi,   # ← primary variable's log/linear transform
        ...
    )

_tf is derived from the primary variable's log-scale checkbox. The overlay variable has no independent log control, so if log mode is active and the overlay variable contains zeros or negative values, _tf will produce nan/-inf, marching cubes will fail silently (returning an empty mesh), and the overlay will disappear without any error message. The thresholds _ov_ilo/_ov_ihi are computed from _tf(_ov_3d_raw) which compounds the problem — if _tf maps half the overlay values to nan, nanmin/nanmax may produce a range that no actual values fall within. Either apply an identity transform for overlay rendering, or compute the overlay's own range before applying _tf.

3. playing-st.data as Input triggers spurious full re-renders — interactive.py around diff line 770

Input('playing-st', 'data'),
...
def _update(..., playing_st):  # pylint: disable=unused-argument

playing-st.data is listed as an Input but the parameter is explicitly marked unused-argument — the actual play state is read from the closure variable _is_playing[0]. Every play/pause toggle fires _update with the current (unchanged) step, forcing a full figure rebuild just to switch between play and pause states. This also means step-sel.data fires at the same time as playing-st.data, causing _trig3 to fail the issubset check and fall through to the slower full-render path on the very first playback frame. Consider using State instead of Input here (or removing it, since the closure already provides the value).


Minor / Improvement Opportunities

4. No version constraint on kaleido — kaleido had a disruptive 0.2.x series. Without a pin (kaleido>=0.1,<1.0 or similar) a future release could silently break the export interface.

5. _compute_contour_traces is not subsampled for large 2D fields — the main render path subsamples arrays > 200 K cells for the color-range computation, but contour computation uses the full-resolution data_2d. For a 1024×1024 field with 20 contour levels this calls find_contours 20 times on the full array, adding noticeable latency on each step during playback. A simple stride subsample (matching the pattern already used in _prefetch_3d_mesh) would help.

6. _mesh3_cache evicts by insertion order, not LRU — for forward playback this is functionally correct (oldest entry = already played), but if a user scrubs backward, the evicted entries are exactly the ones most likely to be needed again. A simple dict move-to-end on hit (or collections.OrderedDict) would make it a true LRU with no algorithmic cost.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant