d3-array
Array manipulation, ordering, searching, and statistical summarization for JavaScript, built to power D3's data-visualization pipeline.
Repository Health
Technical Analysis
d3-array is the array-processing foundation of the D3.js ecosystem, providing a comprehensive set of functions for manipulating, ordering, searching, and summarizing arrays and iterables. It covers everything from basic operations like sum, mean, median, and extent to more specialized statistical routines like quantile computation, histogram binning, and Freedman-Diaconis/Scott/Sturges threshold rules for choosing bin counts.
The library also includes set-theoretic helpers (union, intersection, difference, subset, superset), grouping and rollup utilities backed by InternMap for value-based (not reference-based) key equality, and low-level algorithms like a Floyd-Rivest quickselect and a Neumaier/Kahan-style compensated summation (fsum) for numerically stable totals. Many functions accept an accessor function and operate on any iterable, not just arrays, so they compose naturally with generators and other iterable data sources.
Because it underlies scale domains, histogram generators, and axis tick calculations throughout D3, d3-array is typically pulled in transitively by d3-scale, d3-shape, and the full d3 bundle, but it is equally useful standalone in any JavaScript project that needs precise, well-tested numerical and array utilities without adopting all of D3.
What You Get
- Descriptive statistics: sum, mean, median, mode, variance, deviation, quantile, and rank, all accepting an accessor function
- Binning and histograms via bin() with pluggable threshold rules (Sturges, Scott, Freedman-Diaconis) for choosing bin counts
- Grouping and rollup helpers (group, groups, rollup, rollups, index, flatGroup) backed by InternMap for correct value-based key equality
- Set operations (union, intersection, difference, subset, superset, disjoint) that work on any iterable
- Search and ordering primitives: bisect, bisector, quickselect (Floyd-Rivest selection algorithm), sort, rank, least/greatest
- Numerically stable summation via fsum/Adder, using a Neumaier-style compensated-summation algorithm to avoid floating-point rounding error
Common Use Cases
- Computing chart scale domains (extent, ticks, nice) for D3 axes and scales
- Building histograms for data visualizations with automatic or custom bin thresholds
- Grouping and aggregating tabular data (e.g. CSV rows) by one or more keys before charting
- De-duplicating or comparing collections with set operations where equality must be value-based, not reference-based
- Computing running totals or means over large numeric datasets where floating-point drift matters
Under The Hood
Architecture
d3-array is organized as roughly 60 single-purpose ES modules under src/, each exporting one function (or a small tightly related family, as in group.js’s group/groups/rollup/rollups/index/indexes cluster), re-exported from a single flat src/index.js barrel. There is no shared runtime state or class hierarchy; composition happens by import, and higher-level functions like bin.js explicitly import and call lower-level primitives (bisect, extent, ticks, nice, threshold/sturges), making the dependency graph between modules easy to trace from the barrel file alone. The one structural building block used across the module is InternMap/InternSet (from the separate internmap package), which every grouping function (group, rollup, index, and their plural forms) relies on via a shared internal nest() helper in group.js to get value-based key equality (e.g. two distinct Date objects with the same time compare equal as group keys) instead of JavaScript’s default reference equality. A change to nest()’s traversal order or InternMap’s equality semantics would ripple through every grouping/rollup entry point at once.
Tech Stack
The package is pure, dependency-light modern JavaScript: an ES module ("type": "module") with a single runtime dependency (internmap, version range 1 - 2) and no framework, no bundler runtime, no Node-specific APIs in src/. Rollup (v3) with rollup-plugin-terser builds the UMD/minified dist/ bundle on prepublishOnly, and @rollup/plugin-node-resolve resolves the internmap dependency into that bundle. Tests run under Mocha with Node’s built-in assert, and d3-dsv/jsdom/d3-random are devDependencies used only to construct realistic test fixtures (CSV parsing, DOM-based typed-array checks, seeded randomness), never shipped to consumers.
Code Quality
The test suite is extensive and specific: test/ contains a dedicated *-test.js file per source module (bin-test.js, quickselect-test.js, fsum-test.js, etc.), totaling roughly 4,700 lines of assertions covering edge cases like empty inputs, NaN/undefined handling, iterable vs. array inputs, and deprecated aliases. All tests use plain Node assert/assert.strictEqual/assert.deepStrictEqual rather than a heavier assertion library, keeping the dependency surface minimal. ESLint (eslint:recommended) runs over both src and test in CI (.github/workflows) alongside the Mocha run, though the CI matrix pins a single old Node version (14.x) and hasn’t been updated for newer LTS releases. There are no TypeScript types in the source itself (consumers rely on DefinitelyTyped’s separate @types/d3-array package), and there is no dedicated CONTRIBUTING doc, but naming and code style are highly consistent module-to-module, reflecting the mature, long-maintained nature of the D3 project.
What Makes It Unique
Unlike general-purpose utility libraries (Lodash, Ramda), d3-array is purpose-built for the numerical and statistical needs of data visualization: it ships a Floyd-Rivest quickselect for expected-linear-time order statistics, a Neumaier-style compensated summation (fsum/Adder) to keep running totals accurate under floating-point error, and threshold-rule implementations (Freedman-Diaconis, Scott, Sturges) for automatically choosing histogram bin counts — capabilities that go well beyond typical array-utility packages. Its InternMap-backed grouping functions also solve a real and often-overlooked correctness problem (grouping by object/Date/NaN keys) that most other grouping utilities get wrong by relying on reference equality or string coercion.
Used by 7 apps in this directory
Dub
Marketing · Analytics
The open-source link attribution platform for short links, conversion tracking, and affiliate programs — powering 100M+ clicks monthly.
Kibana
Analytics · Monitoring
Your open source window into the Elastic Stack — query, visualize, and act on data stored in Elasticsearch with real-time dashboards, AI-assisted search, and automated alerting.
MLflow
AI Development · Monitoring
The open source AI engineering platform for debugging, evaluating, monitoring, and optimizing production LLMs and agents at scale.
OpenPanel
Analytics
Open-source Mixpanel alternative with session replay, MCP integration, and privacy-first product analytics you fully control.
PostHog
Analytics · Monitoring · Developer Tools
The all-in-one open source product platform combining analytics, session replay, feature flags, error tracking, AI observability, and a built-in data warehouse in a single self-hostable stack.
Rill
Analytics · Data Engineering
The fastest BI tool for humans and agents — define metrics, models, and dashboards as code and query them instantly on ClickHouse or DuckDB.
Rivet
AI Agents · Developer Tools
Stateful actors as a primitive for AI agents, real-time collaboration, and durable execution — with in-memory state, WebSockets, queues, and scheduling built in.