Handling Large Datasets in Plotly: When to Switch to WebGL
Learn when to switch from Plotly's default SVG rendering to WebGL (scattergl) to handle large datasets without crashing your browser.
14 Nov 2025, 18:45 UTC

The Browser Lag Problem
When plotting a few hundred points in Plotly, the interaction is fluid. However, as your dataset grows toward 10,000 or 100,000 points, you will likely notice a distinct lag during zooming and panning. This happens because Plotly's default rendering engine uses Scalable Vector Graphics (SVG). In an SVG plot, every single data point is treated as a separate element in the browser's Document Object Model (DOM). When you move the chart, the browser must recalculate the position of every single one of those DOM elements, which quickly overwhelms the CPU.
The solution is to move the rendering workload from the browser's DOM to the GPU using WebGL (Web Graphics Library). By switching to WebGL-accelerated traces, you can render millions of points while maintaining a responsive interface.
SVG vs. WebGL: The Technical Trade-off
Plotly provides specific trace types designed for high-performance rendering. The most common is scattergl, the WebGL counterpart to the standard scatter trace. While scattergl solves the performance bottleneck, it is not a drop-in replacement for every use case.
| Feature | SVG (go.Scatter) | WebGL (go.Scattergl) |
|---|---|---|
| Rendering | DOM-based vector elements | GPU-accelerated rasterization |
| Data Volume | Best for < 10k points | Capable of 100k to 1M+ points |
| Visual Fidelity | Crisp, publication-quality | May have subtle anti-aliasing differences |
| Feature Set | Full support for all marker styles | Limited marker symbols and error bars |
Implementing WebGL in Python
If you are using plotly.graph_objects, you simply change the trace class. If you are using plotly.express, you can specify the render_mode argument.
Example: Comparing Render Modes
Run this code in a Python environment with plotly installed. This example generates a synthetic dataset of 100,000 points to demonstrate the performance gap.
import plotly.graph_objects as go
import plotly.express as px
import numpy as np
# Generate 100,000 random points
np.random.seed(42)
x = np.random.randn(100000)
y = np.random.randn(100000)
# Option 1: Using Graph Objects (Manual switch to Scattergl)
fig_gl = go.Figure(data=go.Scattergl(
x=x,
y=y,
mode='markers',
marker=dict(color='blue', size=2)
))
fig_gl.update_layout(title="WebGL Accelerated Plot (Smooth)")
# Option 2: Using Plotly Express (render_mode='webgl')
import pandas as pd
df = pd.DataFrame({'x': x, 'y': y})
fig_px = px.scatter(df, x='x', y='y', render_mode='webgl', title="Plotly Express WebGL")
# To test: Show fig_gl and try zooming in rapidly
fig_gl.show()
Execution Details
- Where to run: Local Python environment, Jupyter Notebook, or a Dash application.
- Permissions: No special OS permissions required; requires a browser with WebGL support.
- Expected Result: The
Scatterglplot should pan and zoom smoothly, whereas a standardScatterplot with the same 100k points would likely freeze the browser tab for several seconds during interaction.
Limitations and Constraints
WebGL is powerful, but it introduces specific constraints that may impact your design:
- Hardware Dependency: WebGL relies on the user's GPU. In highly restricted corporate environments or virtualized desktops without GPU acceleration, these plots may fail to render or fall back to slower methods.
- Feature Parity: Not all SVG marker symbols are supported in WebGL. If your project requires highly specific custom markers or complex per-point text annotations,
scatterglmay strip some of that detail. - Visual Artifacts: Because WebGL rasterizes the points, you may notice slight differences in how edges are anti-aliased compared to the perfectly sharp vectors of SVG. This is usually negligible for data exploration but can be visible in high-resolution exports for print.
Decision Framework: Which one to choose?
To decide which rendering mode to use, follow this heuristic:
- Start with SVG: Use
go.Scatterfor prototypes and small datasets. It provides the highest visual fidelity and full feature support. - Profile Interaction: Once you load realistic data volumes, test the zoom and pan tools. If you feel a "stutter" or the browser becomes unresponsive, you have hit the SVG limit.
- Switch to WebGL: Change to
go.Scatterglorrender_mode='webgl'. - Consider Downsampling: If WebGL still struggles (e.g., 10M+ points), implement server-side downsampling (decimation) to reduce the number of points sent to the browser while preserving the overall shape of the data.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.