WebGL Scatterplot
High-performance scatterplot using raw WebGL shaders for rendering 10k–50k+ data points. Based on the ScatterPlotWGL component from thedatavizcomponents library, used in the PerturbSeq application for UMAP embeddings and gene expression visualization.
Live Demo
Cell Type
Implementation Guide
WebGL Rendering Pipeline
Points are rendered as GL_POINTS with custom vertex and fragment shaders. The fragment shader creates smooth circles with anti-aliased edges usingsmoothstep on the distance from center.
// Vertex shader: transform data coords to clip space
attribute vec2 aPosition;
uniform vec2 uScale, uOffset;
void main() {
gl_Position = vec4(aPosition * uScale + uOffset, 0.0, 1.0);
gl_PointSize = uPointSize * uPixelRatio;
}
// Fragment shader: smooth circle with alpha blending
void main() {
float dist = length(gl_PointCoord - vec2(0.5)) * 2.0;
if (dist > 1.0) discard;
float alpha = 1.0 - smoothstep(0.8, 1.0, dist);
gl_FragColor = vec4(vColor.rgb * alpha, vColor.a * alpha);
}Interleaved Buffer Layout
Data is packed into a single interleaved Float32Array for efficient GPU upload. Each vertex stores position (x, y) and color (r, g, b, a) = 6 floats per point.
// 6 floats per point: x, y, r, g, b, a
const buf = new Float32Array(points.length * 6);
for (let i = 0; i < points.length; i++) {
buf[i*6+0] = points[i].x;
buf[i*6+1] = points[i].y;
buf[i*6+2] = points[i].color[0]; // r
// ...
}
gl.bufferData(gl.ARRAY_BUFFER, buf, gl.STATIC_DRAW);Zoom and Pan
View state is maintained as scale + offset uniforms passed to the vertex shader. Mouse wheel adjusts scale, drag adjusts offset. Point size scales with zoom level.
Architecture
┌─────────────────────────────────────────────┐
│ React Component │
│ ┌────────────────────────────────────────┐ │
│ │ <canvas> element │ │
│ │ │ │
│ │ WebGL Context │ │
│ │ ├─ Vertex Shader (position + zoom) │ │
│ │ ├─ Fragment Shader (circle + alpha) │ │
│ │ └─ Interleaved Float32Array buffer │ │
│ │ │ │
│ └────────────────────────────────────────┘ │
│ │
│ State: │
│ ├─ viewRef (scale, offset) ──► uniforms │
│ ├─ selectedCategory ──► buffer rebuild │
│ └─ hoveredPoint ──► tooltip overlay │
│ │
│ Events: │
│ ├─ wheel ──► zoom (scale adjustment) │
│ ├─ mousedown/move ──► pan (offset) │
│ └─ mousemove ──► nearest-point detection │
└─────────────────────────────────────────────┘Performance Notes
- Single draw call: All points rendered in one
gl.drawArrayscall - GPU-side transforms: Zoom/pan computed in vertex shader, no CPU re-computation of positions
- Alpha blending: Pre-multiplied alpha for correct overlapping point rendering
- DPI awareness: Point size and canvas resolution scale with
devicePixelRatio
Source Reference
datavizcomponents/src/modules/scatterplotWGL/scatterplotWGL.jsdatavizcomponents/src/modules/tools/scatterplotRenderer.jsdatavizcomponents/src/components/ScatterPlotWGL.jsx
Use Cases
UMAP / t-SNE Embeddings
Visualize dimensionality reduction results from single-cell RNA-seq or perturbation experiments with tens of thousands of cells.
Gene Expression Scatter
Plot gene-gene expression correlations or differential expression results (volcano plots, MA plots) with interactive filtering.
QC Metrics
Inspect quality control distributions (reads per cell, genes detected, mitochondrial fraction) with lasso selection for outlier removal.