Skip to main content
typescript react spectroscopy open-source visualization

SpectraView:Canvas-FirstSpectralVisualizationfortheBrowser

· 14 min read

Most spectrum viewers on the web use Plotly, Chart.js, or an SVG-based charting library. These work fine for 50-point bar charts. They do not work for vibrational spectra — 2,048 to 8,192 data points, sub-wavenumber precision, users who zoom in to inspect individual peak shoulders. The DOM chokes. Interactions lag. Scientists go back to Origin.

SpectraView exists because I needed a spectrum viewer for Spektron that could render IR and Raman spectra in the browser without compromise. It’s a React component — npm install spectraview — that renders spectral data on Canvas and everything else on SVG.

install + use
1
2
3

The Rendering Split

A spectrum is a dense polyline — thousands of (x, y) pairs connected by segments. SVG represents each segment as a DOM node. At 4,000 points, that’s 4,000 <line> or <path> elements that the browser must lay out, paint, and composite. Zooming reflows the entire subtree.

Canvas has none of this overhead. ctx.lineTo() draws to a pixel buffer. 10,000 points take the same time as 100. But Canvas has no event model, no hover detection, no accessible text.

SpectraView uses both. The spectral data renders on Canvas for performance. Axes, grid lines, peak markers, annotations, and the crosshair render as SVG for interactivity and accessibility. The layers are composited by absolute positioning within a single container.

Rendering architecture
SVG-only (typical)
Canvas + SVG (SpectraView)

LTTB Downsampling

Even Canvas has limits. Drawing 50,000 lineTo calls per frame during a zoom animation is wasteful — most segments map to the same pixel column. SpectraView uses the Largest-Triangle-Three-Buckets (LTTB) algorithm to reduce the rendered point count to plotWidth * 2 while preserving visual fidelity.

LTTB divides the data into equal-sized buckets and selects the point in each bucket that forms the largest triangle with its neighbors. Unlike simple min-max decimation, it preserves the visual shape of peaks and shoulders. The downsampling happens per frame on the zoomed window, so you never lose resolution — zoom in and the algorithm selects more detail.

Composable Architecture

SpectraView is not a monolithic charting component. It’s 15 components and 9 hooks that compose together. The main <SpectraView /> component is a convenience wrapper — every internal layer is independently exported.

composition.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14

The hooks handle state. useZoomPan wraps d3-zoom with memoized scale management. usePeakPicking runs prominence-based peak detection reactively whenever spectra change. useNormalization applies spectral transformations — baseline correction, normalization, smoothing, derivatives — returning new Spectrum objects without mutating the originals.

This design means you can build a custom viewer that has a minimap and tooltip but no toolbar, or a comparison view with two independent zoom states, or a processing dashboard that chains useNormalization with useHistory for undo/redo.

Parsing Four Formats

Spectroscopists store data in JCAMP-DX, CSV, SPC, and JSON. SpectraView parses all four.

parsers.ts
1
2
3
4
5
6
7
8
9
10

The SPC parser is the most interesting. SPC is a binary format from the 1990s — little-endian, variable-length headers, two different Y-data encodings (16-bit integer or 32-bit float), optional per-sub-spectrum X arrays. The parser reads the format using DataView for byte-level access, handles both single and multi-spectrum files, and automatically maps Thermo’s numeric type codes to human-readable unit labels.

Processing in the Browser

SpectraView includes spectral processing utilities that run entirely client-side. No server round-trip. No Python dependency.

processing.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14

Every processing function follows the same contract as SpectraKit: arrays in, arrays out. No mutation, no side effects. The useNormalization hook wraps these into a reactive pipeline — change the mode from “none” to “snv” and all spectra re-render with SNV normalization applied, memoized so it doesn’t recompute on every frame.

The SpectraKit Connection

SpectraView and SpectraKit are companion libraries that share the same design philosophy but target different runtimes:

Two runtimes, one workflow
SpectraKit (Python)
SpectraView (Browser)

Process heavy datasets with SpectraKit in Python. Visualize results with SpectraView in the browser. Both use functional APIs over typed arrays. A spectrum processed by one library can be displayed by the other with zero transformation.

Testing

266 tests across 35 test files. Every component, hook, parser, and utility function is tested. The test suite covers:

  • Parsers — JCAMP-DX, CSV, JSON, SPC binary format parsing
  • Processing — Baseline correction, normalization, smoothing, derivatives
  • Comparison — Difference, correlation, interpolation
  • Components — All 15 React components via Testing Library
  • Hooks — Zoom/pan, peak detection, region selection, undo/redo
test_results.sh
1
2
3
4
5
6
7
8
9
10

What’s Next

SpectraView is the visualization layer for Spektron. The next integration is a prediction viewer — load a spectrum, run it through the Spektron model, and overlay the predicted molecular structure alongside the input spectrum. The composable architecture makes this straightforward: add a new component, wire it to the existing zoom state, render.

  • Storybook: Live demos — interactive component playground with 15 stories
  • Companion library: SpectraKit — Python preprocessing with the same functional API philosophy
  • Foundation model: Spektron — uses SpectraView as its visualization frontend
  • Architecture insight: Why Spectra Are Harder Than Images — the domain challenges that shaped SpectraView’s design
spectraview — summary
1
2
3
4
5
6
7
8
9
10
11
12
13
14