Skip to content

User/mattwar/large data charts#93

Merged
mattwar merged 8 commits into
mainfrom
user/mattwar/LargeDataCharts
Apr 29, 2026
Merged

User/mattwar/large data charts#93
mattwar merged 8 commits into
mainfrom
user/mattwar/LargeDataCharts

Conversation

@mattwar

@mattwar mattwar commented Apr 28, 2026

Copy link
Copy Markdown
Collaborator

Speed up chart rendering and resize for large result sets

A 50,000-row chart used to take minutes and was unresponsive to resize/edit. After this PR, it renders in a couple of seconds and resizes cleanly.

Changes

  • WebGL traces: line/scatter/non-stacked-area traces with >1000 points now use Plotly scattergl instead of SVG scatter.
  • Faster page parse: chart data is embedded as JSON.parse('…') instead of a JavaScript object literal.
  • Structured payload: single-chart renders post {divId, dataJson, layoutJson, configJson} and the page calls Plotly.newPlot directly, avoiding a multi-MB innerHTML parse and script reinjection.
  • Skip sort when sorted: trace builder detects monotonic-x input and reuses the arrays in place.
  • Cheaper resize: Plotly.relayout (layout-only) replaces Plotly.newPlot on resize, eliminating GPU re-upload.
  • No double-resize: fill-mode wrapper is now absolutely positioned so its layout can't retrigger the ResizeObserver.
  • Faster resize trigger: requestAnimationFrame replaces setTimeout(50) after panel toggle / view switch.
  • Layout helper cleanup: dark/light helpers mutate the in-memory layout object instead of round-tripping through JSON.

Follow-up fixes from PR feedback

  • Escape U+2028 / U+2029 in embedded JSON so the generated <script> is valid on any runtime.
  • Apply fill-mode wrapper isolation in _chartUpdated too, so the initial render can't trigger the same ResizeObserver feedback loop the resize path was already protected against.
  • Add a chartViewReady handshake so setChartContent is reliably delivered on initial load and after webview.html rebuilds, with the latest payload cached in PlotlyChartView for replay.
  • Harden the setChartContent handler against untrusted postMessage payloads: validate divId against a strict pattern and build the placeholder element via createElement/appendChild instead of innerHTML concatenation.
  • Sync the test helper's local escape and decodeJsStringLiteral with the production escapeForJsStringLiteral so the structured-invoke path round-trips correctly for U+2028 / U+2029.

Tests

All 112 unit tests pass; added cases for the scattergl threshold (and that stacked area stays on SVG), the monotonic-x fast path, and the new structured setChartContent invocation.

Copilot AI review requested due to automatic review settings April 28, 2026 23:52

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves Plotly chart responsiveness for large result sets in the VS Code results viewer by reducing DOM-heavy SVG rendering, avoiding expensive HTML/script reinjection, and making resizes/layout updates cheaper.

Changes:

  • Switches large line/scatter/non-stacked-area traces to WebGL (scattergl) above a point threshold.
  • Introduces structured single-chart rendering via postMessage payloads ({ divId, dataJson, layoutJson, configJson }) and faster JSON embedding (JSON.parse('...')) for HTML-based paths.
  • Optimizes resize behavior (uses Plotly.relayout, wrapper positioning, rAF resize trigger) and skips sorting when x is already monotonic.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
src/Client/tests/unit/plotlyChartProvider.test.ts Updates tests for structured setChartContent rendering and adds coverage for scattergl threshold + monotonic-x fast path.
src/Client/features/resultsViewer.ts Adjusts chart container CSS to prevent ResizeObserver loops and uses requestAnimationFrame for resize triggering on view/panel toggles.
src/Client/features/plotlyChartProvider.ts Implements WebGL trace selection, structured single-chart payload rendering, faster JSON embedding, monotonic-x sort skip, and relayout-based resize updates.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/Client/features/plotlyChartProvider.ts Outdated
Comment on lines +1622 to +1626
// Apply font/size overrides to the already-rendered plot via relayout.
// newPlot would force Plotly to re-upload all trace data and rebuild the
// GL canvas; relayout updates layout-only properties in place.
var overrides = Object.assign({ width: targetW, height: targetH }, applyFontOverrides(plotDiv.layout || {}, targetW, targetH, preset));
Plotly.newPlot(plotDiv, plotDiv.data, Object.assign({}, plotDiv.layout, overrides), plotDiv._context);
Plotly.relayout(plotDiv, overrides);

Copilot AI Apr 28, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_chartUpdated() still uses the non–aspect-ratio branch that clears wrapperDiv.style.position/left/top (see just above this block), while resizeChartCore() now relies on the wrapper being absolutely positioned in fill mode to prevent ResizeObserver feedback loops. Consider updating _chartUpdated() to apply the same fill-mode wrapper positioning (absolute + left/top = 0) so a post-update layout change doesn’t immediately retrigger an extra resize.

Copilot uses AI. Check for mistakes.
Comment thread src/Client/features/plotlyChartProvider.ts Outdated
Comment thread src/Client/features/plotlyChartProvider.ts
Co-authored-by: Copilot <copilot@github.com>
@mattwar mattwar merged commit 105046c into main Apr 29, 2026
5 checks passed
@mattwar mattwar deleted the user/mattwar/LargeDataCharts branch April 29, 2026 00:19
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.

2 participants