Histogram generation and data binning functionality for creating frequency distributions and visualizations. Binning groups discrete samples into consecutive, non-overlapping intervals commonly used in data visualization.
The bin generator creates histogram bins from data, grouping values into intervals for visualization and analysis.
Creates a new bin generator with default settings.
/**
* Creates a new bin generator with default settings
* @returns A configurable bin generator function
*/
function bin(): BinGenerator;
/**
* @deprecated Use bin() instead
* Creates a bin generator (legacy alias for bin)
*/
function histogram(): BinGenerator;
interface BinGenerator {
/**
* Bins the given iterable of data samples
* @param data - The data to bin
* @returns Array of bins, each containing associated elements from input data
*/
(data: Iterable<any>): Bin[];
/**
* Sets or gets the value accessor function
* @param value - Optional accessor function or constant
* @returns The bin generator (if setting) or current accessor (if getting)
*/
value(value?: (d: any, i: number, data: any[]) => number): BinGenerator | ((d: any, i: number, data: any[]) => number);
/**
* Sets or gets the domain (data range) for binning
* @param domain - Domain array [min, max] or function returning domain
* @returns The bin generator (if setting) or current domain (if getting)
*/
domain(domain?: [number, number] | ((values: number[]) => [number, number])): BinGenerator | [number, number] | ((values: number[]) => [number, number]);
/**
* Sets or gets the threshold generator or explicit thresholds
* @param thresholds - Number of bins, array of thresholds, or threshold generator function
* @returns The bin generator (if setting) or current thresholds (if getting)
*/
thresholds(thresholds?: number | number[] | ((values: number[], min: number, max: number) => number | number[])): BinGenerator | number | number[] | ((values: number[], min: number, max: number) => number | number[]);
}
interface Bin extends Array<any> {
/** Lower bound of the bin (inclusive) */
x0: number;
/** Upper bound of the bin (exclusive, except for the last bin) */
x1: number;
}Usage Examples:
import { bin, extent } from "d3-array";
const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// Basic binning with default settings
const histogram = bin();
const bins = histogram(data);
// Each bin is an array containing the data values that fall within its range
// Each bin has x0 (lower bound) and x1 (upper bound) properties
// Configure bin generator
const customBin = bin()
.domain([0, 10]) // Set explicit domain
.thresholds(5); // Request 5 bins
const customBins = customBin(data);Sets the value accessor function for extracting numeric values from data elements.
/**
* Sets the value accessor function for extracting numeric values
* @param value - Function to extract numeric values from data elements
* @returns The bin generator for method chaining
*/
value(value: (d: any, i: number, data: any[]) => number): BinGenerator;Usage Examples:
import { bin } from "d3-array";
const data = [
{score: 85}, {score: 92}, {score: 78}, {score: 96}, {score: 73}
];
const histogram = bin()
.value(d => d.score) // Extract score property
.thresholds(3); // 3 bins
const bins = histogram(data);
// Bins contain the original objects, grouped by their score valuesSets the domain (data range) that should be binned.
/**
* Sets the domain (data range) that should be binned
* @param domain - [min, max] array or function that computes domain from values
* @returns The bin generator for method chaining
*/
domain(domain: [number, number] | ((values: number[]) => [number, number])): BinGenerator;Usage Examples:
import { bin, extent } from "d3-array";
const data = [1, 2, 3, 4, 5, 15, 16, 17, 18, 19]; // Note the gap
// Default domain uses extent of data
const defaultBin = bin();
// Would create bins covering 1-19
// Custom domain focuses on specific range
const focusedBin = bin()
.domain([1, 10]) // Only bin values 1-10
.thresholds(5);
// Values outside domain (15-19) are ignored
const bins = focusedBin(data);Sets the threshold generator or explicit threshold values for binning.
/**
* Sets the threshold generator or explicit threshold values
* @param thresholds - Number of bins, explicit threshold array, or generator function
* @returns The bin generator for method chaining
*/
thresholds(thresholds: number | number[] | ((values: number[], min: number, max: number) => number | number[])): BinGenerator;Usage Examples:
import { bin, thresholdFreedmanDiaconis, ticks } from "d3-array";
const data = [/* numeric data */];
// Specify number of bins (approximate)
const binByCount = bin().thresholds(10);
// Explicit threshold values
const binExplicit = bin().thresholds([0, 5, 10, 20, 50, 100]);
// Use threshold generator function
const binFreedman = bin().thresholds(thresholdFreedmanDiaconis);
// Custom threshold generator
const binCustom = bin().thresholds((values, min, max) => {
return ticks(min, max, 8); // Nice tick values
});Pre-built functions that determine optimal number of bins based on statistical methods.
Returns the number of bins according to Sturges' formula.
/**
* Returns the number of bins according to Sturges' formula
* @param values - Array of numeric values
* @returns Number of recommended bins
*/
function thresholdSturges(values: number[]): number;Returns the number of bins according to the Freedman–Diaconis rule.
/**
* Returns the number of bins according to the Freedman–Diaconis rule
* @param values - Array of numeric values
* @param min - Minimum value in the dataset
* @param max - Maximum value in the dataset
* @returns Number of recommended bins
*/
function thresholdFreedmanDiaconis(values: number[], min: number, max: number): number;Returns the number of bins according to Scott's normal reference rule.
/**
* Returns the number of bins according to Scott's normal reference rule
* @param values - Array of numeric values
* @param min - Minimum value in the dataset
* @param max - Maximum value in the dataset
* @returns Number of recommended bins
*/
function thresholdScott(values: number[], min: number, max: number): number;Usage Examples:
import { bin, thresholdSturges, thresholdFreedmanDiaconis, thresholdScott } from "d3-array";
const data = [/* large dataset of numeric values */];
// Compare different threshold methods
const sturges = bin().thresholds(thresholdSturges);
const freedman = bin().thresholds(thresholdFreedmanDiaconis);
const scott = bin().thresholds(thresholdScott);
const sturgesBins = sturges(data);
const freedmanBins = freedman(data);
const scottBins = scott(data);
console.log(`Sturges: ${sturgesBins.length} bins`);
console.log(`Freedman-Diaconis: ${freedmanBins.length} bins`);
console.log(`Scott: ${scottBins.length} bins`);import { bin } from "d3-array";
// Generate sample data
const scores = [
72, 85, 90, 78, 92, 88, 76, 95, 83, 87,
91, 79, 86, 89, 94, 81, 77, 93, 84, 80
];
// Create histogram with 5 bins
const histogram = bin()
.domain([70, 100]) // Score range
.thresholds(5); // 5 bins
const bins = histogram(scores);
// Display histogram
bins.forEach((bin, i) => {
console.log(`Bin ${i}: [${bin.x0}, ${bin.x1}) - ${bin.length} students`);
console.log(` Scores: ${bin.join(', ')}`);
});
// Output might be:
// Bin 0: [70, 76) - 2 students
// Scores: 72
// Bin 1: [76, 82) - 5 students
// Scores: 78, 76, 79, 81, 77
// etc.import { bin } from "d3-array";
const transactions = [
{id: 1, amount: 25.50, category: 'food'},
{id: 2, amount: 120.00, category: 'shopping'},
{id: 3, amount: 45.75, category: 'food'},
{id: 4, amount: 300.00, category: 'rent'},
{id: 5, amount: 15.25, category: 'food'},
// ... more transactions
];
// Bin transactions by amount
const amountHistogram = bin()
.value(d => d.amount)
.domain([0, 500])
.thresholds(10);
const amountBins = amountHistogram(transactions);
// Analyze spending patterns
amountBins.forEach((bin, i) => {
const totalAmount = bin.reduce((sum, t) => sum + t.amount, 0);
const avgAmount = totalAmount / bin.length;
console.log(`$${bin.x0}-$${bin.x1}: ${bin.length} transactions, avg $${avgAmount.toFixed(2)}`);
});import { bin, timeDay, timeWeek } from "d3-array";
const events = [
{timestamp: new Date('2023-01-01'), type: 'login'},
{timestamp: new Date('2023-01-02'), type: 'purchase'},
{timestamp: new Date('2023-01-03'), type: 'login'},
// ... more events
];
// Bin events by day
const dailyBins = bin()
.value(d => d.timestamp.getTime())
.thresholds((values, min, max) => {
// Create threshold for each day
const start = new Date(min);
const end = new Date(max);
const thresholds = [];
for (let d = new Date(start); d <= end; d.setDate(d.getDate() + 1)) {
thresholds.push(d.getTime());
}
return thresholds;
});
const eventsByDay = dailyBins(events);
// Analyze daily activity
eventsByDay.forEach(bin => {
const date = new Date(bin.x0).toDateString();
console.log(`${date}: ${bin.length} events`);
});import { bin, thresholdFreedmanDiaconis, thresholdSturges, thresholdScott } from "d3-array";
function adaptiveHistogram(data, maxBins = 50) {
// Try different threshold methods and pick the best one
const methods = [
{ name: 'sturges', fn: thresholdSturges },
{ name: 'freedman', fn: thresholdFreedmanDiaconis },
{ name: 'scott', fn: thresholdScott }
];
let bestBins = null;
let bestCount = 0;
methods.forEach(method => {
const histogram = bin().thresholds(method.fn);
const bins = histogram(data);
// Prefer method that gives reasonable number of bins
if (bins.length > bestCount && bins.length <= maxBins) {
bestBins = bins;
bestCount = bins.length;
}
});
return bestBins || bin().thresholds(Math.min(maxBins, Math.ceil(Math.sqrt(data.length))))(data);
}
// Usage
const measurements = [/* large array of measurements */];
const optimalBins = adaptiveHistogram(measurements);import { bin, mean, deviation } from "d3-array";
function analyzeDistribution(data) {
const histogram = bin().thresholds(20);
const bins = histogram(data);
// Calculate statistics for each bin
const binStats = bins.map(bin => ({
range: [bin.x0, bin.x1],
count: bin.length,
density: bin.length / data.length,
mean: mean(bin),
stdDev: deviation(bin)
}));
// Find most common range
const maxBin = binStats.reduce((max, bin) =>
bin.count > max.count ? bin : max
);
return {
bins: binStats,
mostCommon: maxBin,
totalBins: bins.length
};
}
const distribution = analyzeDistribution([/* your data */]);
console.log(`Most common range: [${distribution.mostCommon.range.join(', ')}]`);
console.log(`${distribution.mostCommon.count} values (${(distribution.mostCommon.density * 100).toFixed(1)}%)`);