Plotly ScatterGL: Rendering Hundreds of Thousands of Points with WebGL
Plotly’s scattergl renderer lets you plot massive point clouds with minimal lag. This guide walks through prerequisites, setup, performance checks, and fallback strategies for older browsers or low‑end GPUs.
18 Feb 2026, 11:25 UTC

Goal
Plotly’s scattergl renderer allows you to display hundreds of thousands of points in a browser with far less CPU usage than the standard scatter trace. This article shows how to enable it, verify performance, and fall back when WebGL2 is unavailable.
Prerequisites
- Modern browser with WebGL2 support (Chrome, Firefox, Edge, Safari on recent OS). Older browsers will silently fall back to
scatter. - Plotly.js v5.x (or later) loaded in the page. If using npm, install
plotly.js-dist-minorplotly.js-dist. - Basic JavaScript knowledge to generate data arrays.
- Optional: a performance monitoring tool (Chrome DevTools Performance panel).
Step‑by‑Step Procedure
- Generate a large dataset. The following code creates 200 000 random points. In practice replace this with your real data.
const n = 200000; const x = new Array(n).fill(0).map(() => Math.random() * 100); const y = new Array(n).fill(0).map(() => Math.random() * 100); const z = new Array(n).fill(0).map(() => Math.random() * 100); // optional for 3D - Build the trace. Use
type: 'scattergl'and set marker properties. Note that line width and other advanced styles are limited.const trace = { x: x, y: y, z: z, // omit for 2D mode: 'markers', type: 'scattergl', marker: { size: 5, color: x, // color by x value colorscale: 'Viridis', opacity: 0.8 } }; - Define layout. Keep it simple; complex axis transforms may not work with scattergl.
const layout = { title: 'Large Point Cloud with ScatterGL', scene: { // 3D only if z is provided xaxis: {title: 'X'}, yaxis: {title: 'Y'}, zaxis: {title: 'Z'} } }; - Render the figure. Call
Plotly.newPlotin a container element.Plotly.newPlot('myDiv', [trace], layout); - Verify performance. Open Chrome DevTools, go to the Performance tab, record a few seconds, and check the frame rendering time. A smooth 60 fps run indicates that
scatterglis working.
Expected Behavior
- Initial render is noticeably faster than a CPU‑based
scattertrace of the same size. - Zoom, pan, and hover remain responsive. Selection tools may be slower depending on the GPU.
- If the browser lacks WebGL2, the plot still appears but falls back to
scatterwithout error.
Common Pitfalls & Recovery
- Low‑end GPU. On older laptops the frame rate may drop. Test on target devices before deployment. If performance is unacceptable, chunk the data.
- Memory limits. GPU memory can hold ~1–2 million points. For larger datasets, split the array into multiple traces or load data incrementally.
// Example chunking: 5 traces of 200k points each const chunks = 5; const chunkSize = n / chunks; const traces = []; for (let i = 0; i < chunks; i++) { const start = i * chunkSize; const end = start + chunkSize; traces.push({ x: x.slice(start, end), y: y.slice(start, end), mode: 'markers', type: 'scattergl', marker: {size: 5, color: 'rgba(0,0,255,0.5)'} }); } Plotly.newPlot('myDiv', traces, layout); - Unsupported styling. Features like
marker.line.widthare ignored. Stick to size, color, opacity, and colorscale. - 3D rotations. Complex 3D interactions are not fully supported with scattergl; fall back to
scatter3dif needed.
Fallback Strategy
Plotly automatically detects WebGL2 availability. If it’s missing, the trace reverts to the CPU implementation. No additional code is required. To force a fallback for testing, disable WebGL in the browser or use an older browser and observe the slower rendering.
Conclusion
By setting type: 'scattergl', you can efficiently plot large point clouds while preserving interactivity. Remember to test on the target hardware, monitor frame rates, and chunk data when approaching GPU memory limits. When WebGL2 is unavailable, Plotly’s graceful fallback ensures the plot still renders, albeit with reduced performance.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.