When scattergl beats scatter in Plotly: GPU rendering for large point sets
Plotly offers SVG and WebGL rendering for scatter plots. Learn when to switch from go.Scatter to go.Scattergl for large point sets, what features you lose, and how to verify the change.
20 Oct 2025, 23:59 UTC

The dashboard that stutters on pan and zoom
You build an exploratory view with a few hundred thousand points. With Plotly's default SVG scatter the figure renders, but panning and zooming feel sluggish and hover becomes choppy. The useful takeaway is not to add more JavaScript, it is to change the rendering model. Plotly exposes a GPU-accelerated trace type for the same declarative API, and switching from SVG to WebGL can restore interactive throughput for large point sets.
SVG draws each point as a DOM element. That gives precise shapes, full accessibility and complete feature parity, but the browser must manage one node per mark. WebGL renders points into a GPU buffer and draws them on a canvas. That reduces DOM work and moves the heavy lifting to the GPU, at the cost of some features.
SVG for completeness, WebGL for throughput
Plotly's engineering decision is to keep both models under a similar API. SVG traces like go.Scatter are the default because they support error bars, shapes, annotations, and advanced hovermode behaviors with full accessibility via DOM.
WebGL traces like go.Scattergl and go.Heatmapgl trade feature completeness for throughput. They are designed for large exploratory views where interactive pan, zoom and hover matter more than fine annotation.
Drop-in substitution with go.Scattergl
In Plotly.py the WebGL variant is available as go.Scattergl with an API surface largely compatible with go.Scatter. The construction pattern stays the same, only the trace class changes.
import plotly.graph_objects as go
import numpy as np
# Generate placeholder data, replace with your source
n = 200_000
x = np.linspace(0, 100, n)
y = np.random.randn(n).cumsum()
fig = go.Figure()
fig.add_trace(go.Scattergl(
x=x,
y=y,
mode='markers',
marker=dict(size=3, opacity=0.6),
name='stream'
))
fig.update_layout(title='Large point set with WebGL rendering', hovermode='closest')
fig.show()
Where to run: a Python environment with plotly installed, e.g. a notebook or a script with permissions to open a browser window. Required permissions are read access to the data source and a browser that supports WebGL.
Practical checks after creation:
- Inspect figure.data[0].type and confirm it is 'scattergl' rather than 'scatter'.
- Open the figure and compare interactive smoothness during pan and zoom against an equivalent go.Scatter figure with the same data.
- Test a feature you rely on, such as error bars or shapes, and observe whether it is rendered or silently ignored.
Risks: WebGL adds GPU initialization overhead, so for small datasets SVG can be faster and more predictable. Browser WebGL availability and GPU memory constraints can still limit extreme datasets.
Where WebGL falls short
WebGL traces have reduced feature parity with SVG. Notable gaps include limited support for some error bars, shapes, annotations and advanced hovermode behaviors. Accessibility differs because a WebGL canvas is not a DOM tree of individual points.
Performance benefits are data-size dependent. Below a few tens of thousands of points the difference is often imperceptible, and SVG's predictability is preferable for annotation-heavy dashboards.
How to decide for your view
Use SVG traces for small, annotation-heavy dashboards where precise shapes, error bars and full hover customization matter.
Switch to WebGL traces for large exploratory views where interactivity at scale is the priority and annotations are minimal.
A practical pattern is to keep both options in your code and choose by data size or user mode. Validate fallback behavior by disabling WebGL in the browser environment and observing Plotly's rendering choice.
Close by measuring the specific view you ship: create two equivalent figures with the same data using scatter and scattergl, check trace type, and compare pan and zoom responsiveness. Choose the rendering model that meets the feature needs of that view, not the largest dataset you can imagine.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.