Initial Release help-frontend

Dr. Frontend

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

Scroll to zoom, drag to pan

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.drawArrays call
  • 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.js
  • datavizcomponents/src/modules/tools/scatterplotRenderer.js
  • datavizcomponents/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.