downsample

Downsampling and smoothing algorithms for time series data, built for fast, accurate chart rendering.

Library
npm
v1.4.0
102stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
31/100Needs Attention
Development Activity0
Maintenance0
Community44
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
70/100Good
Architecture78
Code Quality72
Innovation75
Learning Curve55

downsample is a TypeScript library that reduces the number of points in a numeric time series while preserving its visual shape, so large datasets stay readable and performant when rendered in a chart. It implements five distinct algorithms — Largest Triangle Three Buckets (LTTB), Largest Triangle One Bucket (LTOB), Largest Triangle Dynamic (LTD), Simple Moving Average (SMA), and ASAP (Automatic Smoothing for Attention Prioritization) — covering both downsampling that preserves peaks and valleys and smoothing that removes short-term noise.

Every function accepts arrays of tuples ([x, y] or [Date, y]), plain objects ({x, y}), or typed arrays, and returns data in the same shape it was given. A factory API (createLTTB, createSMA, and so on) lets consumers define custom accessors and output point types for data shapes the built-in functions don’t cover, making the library usable directly inside charting pipelines without any intermediate transformation step.

What You Get

  • Five downsampling/smoothing algorithms - LTTB, LTOB, and LTD for shape-preserving downsampling, plus SMA and ASAP for noise-smoothing.
  • Format-preserving output - input given as tuples, {x, y} objects, or typed arrays comes back in the same shape it was given.
  • TypedArray support - functions accept and return Int16Array, Float32Array, and other typed arrays directly for numeric-heavy pipelines.
  • Factory functions for custom data types - createLTTB, createSMA, and friends let you supply custom x/y accessors and a toPoint constructor for arbitrary point shapes.
  • Zero runtime dependencies - the published package has no dependencies, keeping it lightweight to bundle into chart-heavy frontends.

Common Use Cases

  • Rendering large time-series charts - reduce a dataset from tens of thousands of points down to the pixel width of a chart before passing it to a plotting library.
  • Smoothing noisy sensor or telemetry data - apply SMA or ASAP to reveal underlying trends in high-frequency measurements.
  • Preprocessing data for dashboards - downsample server-side before sending payloads to the browser to cut response size.
  • Working with mixed data shapes - use the factory API to downsample custom point objects, such as domain models, without first converting them to plain tuples.

Under The Hood

Architecture downsample is architected as a small, cleanly layered functional library. A shared types module defines the point and configuration vocabulary, a utils module implements shape-agnostic primitives — triangle-area math, bucket splitting, mean/standard-deviation helpers, and a generic value-extractor/normalizer — and a self-contained FFT/inverse-FFT module is consumed only by the ASAP algorithm for autocorrelation. Each algorithm module in the methods directory follows the same two-tier pattern: a factory function that accepts an accessor/config object (x, y, and for smoothing methods a point constructor) and returns a bound function, alongside a pre-bound default export built from a shared legacy-config helper so consumers get built-in support for tuple, {x, y}, and Date-based points without touching the factory API directly. The top-level entry point is a thin re-export barrel with no additional logic. There’s no dependency-injection container or plugin system — composition happens purely by passing accessor objects into factories, keeping the surface area small, though every algorithm module carries a direct, repeated dependency on the shared normalization primitives, so changing that shared vocabulary would ripple across all of them.

Tech Stack The library is written in TypeScript and compiled with a custom compiler pipeline that adds a runtime type-guard plugin, enabling duck-typed checks (is this a Date? an {x,y} object?) at runtime despite TypeScript’s types being erased. It’s bundled with Rollup into a single entry file plus type declarations, while also exposing per-algorithm files so consumers can deep-import individual methods for better tree-shaking. The published package has no runtime dependencies at all — the entire dependency list is devDependencies for the build and test toolchain. Continuous integration runs on CircleCI, executing an install-and-build-and-test job on every push, with a separate, manually-gated release workflow triggered from version tags.

Code Quality Test coverage is organized one spec file per algorithm plus a dedicated file for the shared utilities, all run through Jest with ts-jest. Each algorithm’s suite shares a common test helper that’s exercised against every supported point-shape variant (tuple/Date, tuple/number, XY/Date, XY/number) plus TypedArray input, checking edge cases like negative parameters throwing descriptive errors, datasets shorter than the target resolution passing through unchanged, and first/last points being preserved — backed by snapshot tests against recorded real-world datasets. The FFT module used internally by ASAP has no dedicated unit tests of its own and is only exercised indirectly through ASAP’s snapshot suite. ESLint with TypeScript-aware rules, Prettier formatting, and a pre-commit lint-staged hook enforce consistent style, and the CI pipeline gates every push on a full build and test run — though there’s no coverage threshold enforcement.

API Design Every downsampling and smoothing function shares one calling convention — data first, algorithm-specific numeric parameters after — and each one preserves the input’s exact shape, so a chart pipeline can swap between algorithms without reshaping data in between. The factory functions expose the same call signature as their pre-bound defaults, just parameterized by accessor and point-construction config, letting a consumer move from ‘reasonable default for tuple or object points’ to ‘downsample my own custom point type’ without learning a second API. The README documents every exported function with a type signature and a runnable example, though algorithm selection itself is left to brief descriptions and links to the source academic papers, so choosing between LTTB, LTOB, LTD, SMA, and ASAP requires some outside reading. Precise generic TypeScript types give strong autocomplete and compile-time checking at every call site.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search