Skip to content

feat(viz): parcoords chart, smart parallel-coordinates panel, gallery WebGL lazy rendering - #4839

Merged
jqnatividad merged 8 commits into
masterfrom
feat/viz-parcoords
Oct 18, 2026
Merged

jqnatividad merged 8 commits into
masterfrom
feat/viz-parcoords

Conversation

@jqnatividad

@jqnatividad jqnatividad commented Oct 18, 2026 •

Copy link
Copy Markdown
Collaborator

Stacked on #4838 (the plotly.rs pin bump that exposes the new plotly.js 3.7 traces). Retarget to master once #4838 merges.

What's new

  • viz parcoords: parallel coordinates, one line per row across the numeric --cols (default: all numeric, minus near-unique integer IDs).
    • --color <col> colors the lines through Viridis, with a colorbar. The color column doesn't have to be one of the axes. The default is the first axis.
    • Rows are stride-sampled to the QSV_VIZ_MAX_POINTS budget, with a "(sampled)" title cue. --size is rejected with a usage error.
  • viz smart parallel-coordinates panel (HTML-only, like parcats):
    • When: it appears when 3+ measures each correlate with another at |r| ≥ 0.3.
    • Data: it's built from the columns and matrix already read for the correlation heatmap, so there's no extra data pass.
    • Layout: up to 6 axes, chained greedily so neighboring axes are the strongest pairs (the only pairs parallel coordinates lets you read). Lines are colored by the strongest pair's first member.
    • Size: capped at 5,000 lines, because the panel is plain JSON (not gzip'd or typed-array encoded).
    • Tour token @parcoords.
    • On by default, with an opt-out: --no-parcoords leaves it out. The auto --max-charts 0 ceiling (MAX_PANELS_INLINE) goes from 64 to 65, so the panel doesn't push a per-column chart out of a wide Data Schematic. An explicit --max-charts N is unchanged: the panel competes for those N slots like the other overview panels.
  • i18n: viz.title.parcoords, viz.title.parcoords_dims and viz.tour.explain.parcoords in all 8 locales.
  • Regenerated docs/help/viz.md and qsv-viz.json (new subcommand enum entry plus an example).

Gallery: WebGL context budget (separate commit, 8b87bec)

Parcoords is a WebGL trace and uses 3 contexts. Chrome keeps ~16 live WebGL contexts per page (same-origin iframes share the budget) and silently drops the oldest, leaving those plots permanently blank.

The gallery on master already needs ~38 once its 17 lazy iframes load, so this was a latent problem. Parcoords made it visible at first paint: splom, scatter3d and the maps went blank.

gen_gallery.py now does two things:

  • Figures with WebGL traces render only within a viewport of the screen and are Plotly.purged when they scroll away, with their height pinned.
  • Data Schematic iframes swap to about:blank off-screen.

SVG figures stay eager. Verified in Chrome: scrolling top → bottom → back re-renders splom, scatter3d, parcoords and the maps, a parked iframe's map renders on reload, and the console shows no context-loss warnings. Standalone viz output and single dashboards are unaffected; the busiest regenerated dashboard has 3 contexts.

Not regenerated

The 4 LLM-gated PREGENERATED dashboards (smart_dict_treemap, smart_dict_sunburst, smart_world_choropleth, smart_geospatial) don't pick up the panel until a QSV_VIZ_REGEN_LLM=1 refresh. Dashboards whose only regen diff was timestamps were not committed.

Verification

  • cargo t viz -F all_features: all pass. New tests: 9 integration and 3 unit (parcoords_axis_order).
  • Mutation-checked: disabling the smart insert, the |r| gate, color-not-an-axis, sampling, and the --size rejection each fails its test.
  • scripts/double-run-check.py --check OK; cargo +nightly fmt; clippy reports no warnings on added lines.
  • In Chrome: standalone chart, smart dashboards (light/dark), and the gallery as above.

The wiki Visualization page update is staged locally and will be pushed after merge.

🤖 Generated with Claude Code

jqnatividad added a commit that referenced this pull request Oct 18, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codacy-production

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

Base automatically changed from deps/plotly-0.15-traces to master October 18, 2026 17:24
jqnatividad and others added 8 commits October 18, 2026 13:24
- `viz parcoords`: one line per row across the numeric --cols (default: all
  numeric, minus near-unique integer IDs), colored by an optional numeric
  --color column (which need not be an axis). Stride-sampled to the
  QSV_VIZ_MAX_POINTS budget with a "(sampled)" title cue. --size is rejected.
- `viz smart`: a parallel-coordinates overview panel when 3+ measures
  correlate at |r| >= 0.3, built from the columns and matrix already read for
  the correlation heatmap (no extra data pass). Up to 6 axes, chained so
  neighbors are the strongest pairs; lines colored by the strongest pair's
  first member; capped at 5,000 lines. HTML-only, like parcats.
- i18n: viz.title.parcoords, viz.title.parcoords_dims and
  viz.tour.explain.parcoords in all 8 locales; tour token `@parcoords`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Chrome keeps ~16 live WebGL contexts per page (same-origin iframes share the
budget) and silently drops the oldest, leaving those plots blank for good.
The gallery already needed ~38 once its 17 lazy iframes loaded, so splom,
scatter3d and map figures could go blank after scrolling.

Figures with WebGL traces now render when they come within a viewport of the
screen and are purged when they scroll away (height pinned), and the Data
Schematic iframes swap to about:blank off-screen. SVG figures stay eager.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ain the panel

smart_geo_outliers, smart_sales, smart_sales_kpi and smart_timeseries have 3+
correlated measures, so they now carry the parallel-coordinates panel. The
LLM-gated pre-generated dashboards are unchanged until the next
QSV_VIZ_REGEN_LLM=1 refresh.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The parallel-coordinates panel stays on by default in `viz smart`, but
`--no-parcoords` now leaves it out. MAX_PANELS_INLINE (the `--max-charts 0`
auto ceiling) goes from 64 to 65, so the new overview panel doesn't push a
per-column chart out of a wide Data Schematic.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
qsvInitFit scans .js-plotly-plot once at load, but a lazily-rendered
figure isn't plotted yet then, so maps scrolled into view later missed
their camera fit and scrollZoom setting, and scatter3d missed the wheel
interceptor. Split the per-plot setup into qsvInitPlot(gd) and call it
when a lazy render resolves; clear its flags on purge, which drops
plotly's handlers and the layout the fit was baked from.

Addresses roborev 5453/5454.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
qsvApplyCamera writes the fitted zoom into the FIGS layout that the
next lazy render reuses, so clearing __qsvBaked on purge made each
revisit re-capture an already-fitted zoom and shrink it again
(0.171 -> -0.658 -> -1.486). Keep __qsvBaked; only the init flag is
cleared.

Addresses roborev 5458.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jqnatividad
jqnatividad merged commit e7ceeae into master Oct 18, 2026
31 checks passed
@jqnatividad
jqnatividad deleted the feat/viz-parcoords branch October 18, 2026 18:29
jqnatividad added a commit that referenced this pull request Oct 19, 2026
Full refresh via refresh_external_dashboards.sh (the five dashboards built
from external datasets) followed by gen_gallery.py (every other page and
gallery.html), so the whole gallery is on one binary. QSV_VIZ_REGEN_LLM=1:
the four --dictionary infer pages reused their committed .schema.json
sidecars; no LLM was contacted. gallery.html itself is byte-identical
(58 figures); 23 dashboard pages changed.

Beyond version/Compiled stamps:
- 3 pages with seasonality panels swap 6 scatterpolar rings for barpolar
  bars (#4840): pitt311data, brazil-lpg, boston_311_2025.
- 3 pages last built by 24.0.0 gain the parallel-coordinates panel (#4839)
  plus panels added in 25.0.0: colombia-calidad-aire, dict_sunburst,
  pa_crashes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant