Skip to content

Histogram ​

The createHistogram helper bins a plain array of numbers and returns chart-ready rows plus the config fragments that make the bars read as a histogram: contiguous, one bar per bin.

ts
// createHistogram bins raw values (Sturges' count, round edges) and returns
// chart-ready rows plus config fragments to spread into a chart config.
import { createHistogram } from '@mochart/core';
import type { MochartInputConfig } from '@mochart/core';

// 60 response-time samples (ms).
const samples = [
  62, 71, 78, 84, 91, 97,
  102, 104, 108, 111, 114, 117, 119, 121, 124, 126,
  128, 131, 133, 136, 138, 141, 143, 145, 147, 149,
  151, 153, 156, 158, 161, 164, 167, 170, 173, 176,
  179, 183, 186, 190, 193, 196, 199,
  202, 206, 211, 217, 222, 228, 233, 239, 244, 249,
  254, 261, 270, 281, 293, 305, 318
];

const histogram = createHistogram(samples, { seriesTitle: 'Requests' });

export const config: MochartInputConfig = {
  version: '1.0.0',
  title: { text: 'Response Time Distribution' },
  categoryAxis: { ...histogram.categoryAxis, title: { text: 'Response time (ms)' } },
  valueAxes: [{ min: 0 }],
  series: [histogram.seriesConfig]
};

export const data = histogram.data;

How it works ​

  • createHistogram(values, options) returns { bins, data, categoryAxis, seriesConfig } and picks the bins for you: roughly Sturges' count by default, with edges rounded to 1/2/5-style numbers. Override with binCount (approximate), binWidth (exact, wins over binCount) or domain to bin over a fixed range (values outside it are ignored); nice: false divides the domain exactly instead of rounding. Either override throws past 10000 bins, whether from a large binCount or a binWidth small enough to need that many across the domain. Bins are half-open: a value on an edge falls into the upper bin, except the last bin, which includes its upper edge.
  • The returned categoryAxis fragment uses an ordinal axis with categoryPaddingFraction zeroed so the bars touch, which is what visually separates a histogram from a bar chart. Bins are contiguous and equal width, so an ordinal axis positions them identically to a linear one, and on a linear category axis a bar always spans a single category value, which would leave multi-unit-wide bins as slivers.
  • normalize switches each bin's value from the raw 'count' to 'probability' (sums to 1) or 'density' (integrates to 1), and cumulative: true accumulates the bins left to right. The default series title follows the mode (Count, Probability, Density); set seriesTitle to override it.
  • Each row stores its bin's value under the property named by valueProperty (default 'value'), which the returned seriesConfig fragment points at, plus binStart, binEnd, binCenter and count. The category value is binLabel, formatted by the binLabel option (default start–end; the labels must be unique). The raw bin descriptions come back under bins, useful for annotations built alongside the chart.
  • The lower-level binValues(values, options) returns just the bins with no chart fragments, for when you want the binning without the charting.

Released under the MIT License.