Skip to content

Histogram

Summarize one measure in deterministic numeric bins.

Chart ID: histogram. Independent import: @revolist/charts/histogram.

Loading chart…

Read the frequency or aggregate within numeric bins. Bin placement uses the selected numeric values; an independently bound Y measure can supply sums or means instead of counts.

Use one category per row and one or more numeric series. Values are finite numbers or explicit nulls; the row mapper does not group or aggregate repeated keys.

The roles below describe the chart's data contract. Generic category/value roles resolve from the dataset; explicitly bind specialized numeric roles as shown in the complete example.

Data roleField count
category1 or more
value1 or more
series1 or more

Download the complete sample data and settings (JSON). See Data & Configuration for mapping, null values, updates and lifecycle rules.

Install the package using the installation guide, give the host an explicit height, and call createHistogramChart after the host mounts. This factory fixes the chart type to histogram.

<div id="chart" style="width: 100%; height: 450px;"></div>
Complete runnable TypeScript example with sample data
import { createHistogramChart } from '@revolist/charts/histogram';
const container = document.getElementById('chart')!;
const chart = await createHistogramChart({
container,
"dataset": {
"revision": 0,
"source": "client",
"categories": [
{
"id": "preview-category-0",
"label": "12",
"path": [
"12"
],
"labels": [
"12"
],
"depth": 1,
"kind": "leaf"
},
{
"id": "preview-category-1",
"label": "18",
"path": [
"18"
],
"labels": [
"18"
],
"depth": 1,
"kind": "leaf"
},
{
"id": "preview-category-2",
"label": "23",
"path": [
"23"
],
"labels": [
"23"
],
"depth": 1,
"kind": "leaf"
},
{
"id": "preview-category-3",
"label": "27",
"path": [
"27"
],
"labels": [
"27"
],
"depth": 1,
"kind": "leaf"
},
{
"id": "preview-category-4",
"label": "31",
"path": [
"31"
],
"labels": [
"31"
],
"depth": 1,
"kind": "leaf"
},
{
"id": "preview-category-5",
"label": "35",
"path": [
"35"
],
"labels": [
"35"
],
"depth": 1,
"kind": "leaf"
},
{
"id": "preview-category-6",
"label": "42",
"path": [
"42"
],
"labels": [
"42"
],
"depth": 1,
"kind": "leaf"
},
{
"id": "preview-category-7",
"label": "48",
"path": [
"48"
],
"labels": [
"48"
],
"depth": 1,
"kind": "leaf"
}
],
"series": [
{
"id": "preview-series-0",
"label": "Value",
"columnPath": [
"Value"
],
"labels": [
"Value"
],
"kind": "leaf",
"prop": "preview-0"
}
],
"values": [
[
12
],
[
18
],
[
23
],
[
27
],
[
31
],
[
35
],
[
42
],
[
48
]
],
"analyticalFrame": {
"derived": {
"distributions": [
{
"kind": "samples",
"categoryId": "preview-category-0",
"seriesId": "preview-series-0",
"samples": [
8,
12,
14,
18,
19,
23,
27,
31,
48
]
},
{
"kind": "samples",
"categoryId": "preview-category-1",
"seriesId": "preview-series-0",
"samples": [
10,
14,
16,
20,
21,
25,
29,
33,
50
]
},
{
"kind": "samples",
"categoryId": "preview-category-2",
"seriesId": "preview-series-0",
"samples": [
12,
16,
18,
22,
23,
27,
31,
35,
52
]
},
{
"kind": "samples",
"categoryId": "preview-category-3",
"seriesId": "preview-series-0",
"samples": [
14,
18,
20,
24,
25,
29,
33,
37,
54
]
},
{
"kind": "samples",
"categoryId": "preview-category-4",
"seriesId": "preview-series-0",
"samples": [
16,
20,
22,
26,
27,
31,
35,
39,
56
]
},
{
"kind": "samples",
"categoryId": "preview-category-5",
"seriesId": "preview-series-0",
"samples": [
18,
22,
24,
28,
29,
33,
37,
41,
58
]
},
{
"kind": "samples",
"categoryId": "preview-category-6",
"seriesId": "preview-series-0",
"samples": [
20,
24,
26,
30,
31,
35,
39,
43,
60
]
},
{
"kind": "samples",
"categoryId": "preview-category-7",
"seriesId": "preview-series-0",
"samples": [
22,
26,
28,
32,
33,
37,
41,
45,
62
]
}
]
},
"fields": [
{
"id": "pivot:category",
"label": "pivot:category",
"role": "dimension",
"semanticType": "category"
},
{
"id": "pivot:series",
"label": "pivot:series",
"role": "dimension",
"semanticType": "category"
},
{
"id": "preview-series-0",
"label": "Value",
"role": "measure",
"semanticType": "number",
"sourceField": "preview-0"
}
],
"observations": [
{
"id": "[\"preview-category-0\",\"preview-series-0\"]",
"dimensions": {
"pivot:category": {
"value": "12",
"label": "12",
"path": [
"12"
],
"labels": [
"12"
]
},
"pivot:series": {
"value": "Value",
"label": "Value",
"path": [
"Value"
],
"labels": [
"Value"
]
}
},
"measures": {
"preview-series-0": 12
}
},
{
"id": "[\"preview-category-1\",\"preview-series-0\"]",
"dimensions": {
"pivot:category": {
"value": "18",
"label": "18",
"path": [
"18"
],
"labels": [
"18"
]
},
"pivot:series": {
"value": "Value",
"label": "Value",
"path": [
"Value"
],
"labels": [
"Value"
]
}
},
"measures": {
"preview-series-0": 18
}
},
{
"id": "[\"preview-category-2\",\"preview-series-0\"]",
"dimensions": {
"pivot:category": {
"value": "23",
"label": "23",
"path": [
"23"
],
"labels": [
"23"
]
},
"pivot:series": {
"value": "Value",
"label": "Value",
"path": [
"Value"
],
"labels": [
"Value"
]
}
},
"measures": {
"preview-series-0": 23
}
},
{
"id": "[\"preview-category-3\",\"preview-series-0\"]",
"dimensions": {
"pivot:category": {
"value": "27",
"label": "27",
"path": [
"27"
],
"labels": [
"27"
]
},
"pivot:series": {
"value": "Value",
"label": "Value",
"path": [
"Value"
],
"labels": [
"Value"
]
}
},
"measures": {
"preview-series-0": 27
}
},
{
"id": "[\"preview-category-4\",\"preview-series-0\"]",
"dimensions": {
"pivot:category": {
"value": "31",
"label": "31",
"path": [
"31"
],
"labels": [
"31"
]
},
"pivot:series": {
"value": "Value",
"label": "Value",
"path": [
"Value"
],
"labels": [
"Value"
]
}
},
"measures": {
"preview-series-0": 31
}
},
{
"id": "[\"preview-category-5\",\"preview-series-0\"]",
"dimensions": {
"pivot:category": {
"value": "35",
"label": "35",
"path": [
"35"
],
"labels": [
"35"
]
},
"pivot:series": {
"value": "Value",
"label": "Value",
"path": [
"Value"
],
"labels": [
"Value"
]
}
},
"measures": {
"preview-series-0": 35
}
},
{
"id": "[\"preview-category-6\",\"preview-series-0\"]",
"dimensions": {
"pivot:category": {
"value": "42",
"label": "42",
"path": [
"42"
],
"labels": [
"42"
]
},
"pivot:series": {
"value": "Value",
"label": "Value",
"path": [
"Value"
],
"labels": [
"Value"
]
}
},
"measures": {
"preview-series-0": 42
}
},
{
"id": "[\"preview-category-7\",\"preview-series-0\"]",
"dimensions": {
"pivot:category": {
"value": "48",
"label": "48",
"path": [
"48"
],
"labels": [
"48"
]
},
"pivot:series": {
"value": "Value",
"label": "Value",
"path": [
"Value"
],
"labels": [
"Value"
]
}
},
"measures": {
"preview-series-0": 48
}
}
],
"matrixCells": [
{
"categoryId": "preview-category-0",
"seriesId": "preview-series-0",
"observationId": "[\"preview-category-0\",\"preview-series-0\"]",
"measureFieldId": "preview-series-0"
},
{
"categoryId": "preview-category-1",
"seriesId": "preview-series-0",
"observationId": "[\"preview-category-1\",\"preview-series-0\"]",
"measureFieldId": "preview-series-0"
},
{
"categoryId": "preview-category-2",
"seriesId": "preview-series-0",
"observationId": "[\"preview-category-2\",\"preview-series-0\"]",
"measureFieldId": "preview-series-0"
},
{
"categoryId": "preview-category-3",
"seriesId": "preview-series-0",
"observationId": "[\"preview-category-3\",\"preview-series-0\"]",
"measureFieldId": "preview-series-0"
},
{
"categoryId": "preview-category-4",
"seriesId": "preview-series-0",
"observationId": "[\"preview-category-4\",\"preview-series-0\"]",
"measureFieldId": "preview-series-0"
},
{
"categoryId": "preview-category-5",
"seriesId": "preview-series-0",
"observationId": "[\"preview-category-5\",\"preview-series-0\"]",
"measureFieldId": "preview-series-0"
},
{
"categoryId": "preview-category-6",
"seriesId": "preview-series-0",
"observationId": "[\"preview-category-6\",\"preview-series-0\"]",
"measureFieldId": "preview-series-0"
},
{
"categoryId": "preview-category-7",
"seriesId": "preview-series-0",
"observationId": "[\"preview-category-7\",\"preview-series-0\"]",
"measureFieldId": "preview-series-0"
}
]
}
},
"bindings": {},
"presentation": {
"dataLabels": false
}
});
// When the host unmounts:
// chart.destroy();

Await updates before reading a snapshot or exporting. Call chart.destroy() when the host unmounts. See the live catalog to interact with this type.

Set these fields in chartOptions. The option schema validates supported keys, ranges and choices; updating chartOptions replaces that authored object.

OptionDefaultAccepted values
showGridLinestruetrue or false
markOpacity10.2 to 1; step 0.05
binCount00 to 256; step 1
histogramBinBoundaries[]2 to 257 increasing finite edges, or [] for automatic binning
histogramAggregationcountcount, sum, mean
histogramAreafalsetrue or false

Configure primary, secondary or named aggregate Y axes and primary or named numeric bin-boundary X axes, including scales, bounds, reversal, formatting, ticks and measured placement. Explicit sample bindings own independent distributions and axis assignments; X uses sample values and Y uses bin counts, sums or means. See histogram-axis options and limits and stable sample navigation.

Titles, legends, theme and labels belong to presentation or the corresponding top-level setting. Axis, color, navigation and interaction support depends on the selected chart; see Data & Configuration.

For bin sample scales and aggregate metric bounds, transforms, reversal, ticks and placement, see Histogram bin and metric axes. See Histogram sample navigation for local sample-window zoom/pan, navigator, brushes, CSV and synchronization. See Histogram shared hover and crosshair for bin-metric readouts and formatter metadata. Remote detail loading uses complete source frames, which also support precomputed equal/irregular intervals. Named sample and metric axes are supported through the collection contract below.

Charts overview · Installation · Data & Configuration

Use chartOptions.histogramBinBoundaries to configure explicit raw-sample intervals, including irregular widths. It overrides automatic bin counts and is also available in Pivot’s Bin boundaries appearance field.

Set chartOptions.histogramArea: true for raw-width area encoding, including density axes, navigator values and typed tooltip metadata.

Inspect loaded records and complete bin statistics with histogram sample/bin data views, shared with Pivot’s Samples/Bins Data tab.

A histogram can display several explicitly bound distributions, using the shared Charts engine in standalone Charts and Pivot. Each sample measure owns its partition and X/Y-axis assignments. Raw observations and metric/helper measures remain in the canonical dataset.

const chart = await createChart({
container,
chartType: 'histogram',
dataset,
bindings: {
x: ['duration', 'delay'],
y: ['weight', 'cost'],
},
chartOptions: { binCount: 12, histogramAggregation: 'sum' },
axes: {
x: { scale: 'linear', unit: 's', title: 'Duration' },
xAxes: {
delayAxis: { scale: 'symlog', constant: 1, reverse: true, unit: 'ms', title: 'Delay' },
},
y: { min: 0, unit: 'kg' },
yAxes: { money: { min: 0, unit: 'EUR', title: 'Cost' } },
},
seriesOverrides: {
duration: { color: '#2563eb' },
delay: { xAxis: 'delayAxis', yAxis: 'money', color: '#d97706' },
},
navigation: { enabled: true, navigator: { series: 'all' }, xAxis: 'delayAxis' },
rangeSelection: { enabled: true, xAxis: 'delayAxis' },
});
FieldMeaning
bindings.xOrdered list of sample measure IDs.
bindings.valueEquivalent sample-binding form. If both it and X are nonempty, their IDs/order must agree.
bindings.yOmit to use each sample measure as its own sum/mean metric; use one ID for a shared metric, or one distinct ID per sample for paired metrics. Count still counts sample observations.
seriesOverrides[sampleId].xAxis'primary' or a configured axes.xAxes ID. Default primary.
seriesOverrides[sampleId].yAxis'primary', 'secondary' or a configured axes.yAxes ID. Default primary.
seriesOverrides[sampleId].color, .visibleSaved sample paint and visibility. Helpers do not acquire histogram marks or legend entries.

Without explicit nonempty sample bindings, the first dataset measure remains the single legacy sample. Extra measures are not automatically added as distributions. Binding IDs must exist. Duplicate sample IDs, conflicting value/X lists and invalid metric cardinality reject before replacing the frame. The raw measure count is now governed by the normal chart limits rather than a two-measure cap.

Every member independently uses binCount, histogramBinBoundaries, histogramAggregation and histogramArea. Automatic partitions can differ even when members share X. Explicit raw boundaries give them a common partition. Same-axis distributions overlay; they are not stacked, added, dodged or merged. Use markOpacity, sample colors, visibility or separate named axes deliberately.

A logical X axis uses the union of its visible complete partition bounds, with its authored bounds taking precedence. A logical Y axis uses all visible member metrics on that axis. Overflowed sums share one finite geometry unit per Y axis; this does not add distributions together or change source values. Empty/null samples and missing metric contributors keep their existing histogram semantics. Hidden groups do not influence inferred geometry, and hiding a sample never removes its raw sample/metric fields or complete source statistics.

Primary/secondary/named metric axes and named sample axes support existing numeric scale, domain, reversal, placement, tick, title, formatting and color controls. Numeric X still supports linear/log/symlog/sqrt; category is the legacy bin presentation. X comes from the bound sample, so category data/level mappings, grouped category bands and time X are not histogram options. Logs require positive samples/metrics under the existing rules. Unknown axes reject atomically, including assignments on hidden members.

Area encoding divides each member’s aggregate by its raw interval width. A shared density Y axis displays a unit only when all contributing density units agree; otherwise per-bin tooltips retain each unit and the axis is numeric. Synchronization uses the full density-unit set to prevent matching a mixed axis to an unrelated raw or single-unit axis. Primary Y remains the only synchronized value axis; secondary/named Y projections use complete bins and authored bounds.

Plot gestures/navigator use navigation.xAxis; a brush can independently use rangeSelection.xAxis. viewport.xAxes[id] stores each named window. Reversal changes projection, not source identities or increasing semantic bounds. Navigator series can choose the first visible sample (default), 'all' or explicit sample IDs on its selected X. Existing navigator series overrides and colors apply to the derived metric paths; these remain noninteractive previews of bin metrics rather than replacement source records.

Shared/crosshair readouts and peer hover use only distributions on the same logical X axis. Each bin retains its own interval even when partitions differ. context.aggregate now includes sampleSeriesId, valueSeriesId, xAxis and yAxis alongside the existing raw count/sum/mean and interval fields. The representative context.series remains the metric measure for sum/mean.

Shared tooltip formatters can read context.histogramItems, an array of ChartHistogramTooltipItem values containing category, series, value, displayValue, color and aggregate. Representatives may be outside the loaded row slice, so these are not fabricated matrix-cell sharedItems. The display is bounded to 20 aggregate peers and uses omittedSharedItemCount for additional members. The main hovered aggregate remains available separately. Genuine singleton activation still sends its canonical sample value; aggregate bins do not invent click/drill records.

CSV with dataScope: 'all' remains the raw loaded matrix. Current-scope raw CSV uses the union of rows whose sample is visible in any bound distribution’s own window. It does not replace cells with counts, densities or overflowed aggregate values. Complete remote statistics never fabricate unloaded CSV observations. Models, SVG server rendering, hydration and SVG/image exports retain the normal shared lifecycle and persisted axes/options.

import { createChartHistogramDataView, createChartHistogramDataViews } from '@revolist/charts';
const allDistributions = createChartHistogramDataViews(chart.model, { dataScope: 'current' });
const delays = createChartHistogramDataView(chart.model, {
sampleSeriesId: 'delay',
dataScope: 'all',
});

createChartHistogramDataView keeps its first-bound-member default and adds optional sampleSeriesId. createChartHistogramDataViews returns every bound member in binding order and accepts dataScope only. Both validate the model, return owned snapshots, and use each sample’s own X assignment/window. Unknown requested samples reject. Existing samples/bins fields retain their raw/complete-statistics distinction. Empty collections return an empty plural array; the singular empty-data snapshot remains available.

The Pivot chart facade exports the corresponding createPivotChartHistogramDataView / createPivotChartHistogramDataViews and shared types. In Data, Sample series chooses the member whose raw samples and complete bin table are inspected. The choice is transient UI state. Its UI policy is dataView.histogramSeries; parent dataView policies still apply. Localize the caption with localeText.histogramData.sampleSeries.

Existing Customize → Axes and scales controls edit configured primary, secondary and named axes. Per-series X/Y assignments are shown only for sample members. Chart/legend color and visibility controls target the sample, not its weight helper. Bind collection members through the model/API; this does not add a separate histogram binding-builder UI or a Pivot-specific rendering engine.

The singleton primary-axis source protocol is unchanged: request histogram, response analyticalFrame.derived.histogram. Multiple members, or a member with a nonprimary X/Y assignment, use request histograms and response analyticalFrame.derived.histograms. Arrays are keyed by sample ID; response summary order does not determine plot order. Singular/plural summary metadata are mutually exclusive.

Each ChartHistogramCollectionSourceRequest adds these fields to the existing bin-count/boundaries/aggregation/scale/symlog-constant hints:

FieldContract
sampleSeriesIdRequested source sample measure.
valueSeriesIdIts shared or paired aggregation measure.
xAxisIdentity used for the partition’s full X metadata.
yAxisIdentity of its plotted metric axis.

The provider returns exactly one validated ChartHistogramSummary per requested sample, with matching sample/value IDs and applied options. Counts, sums, means, representatives, boundaries and finite sum multipliers are global statistics, independent of loaded rows. Use fullDomain.x for primary X and fullDomain.xAxes[id] for named X. Each domain equals the union of complete raw partition boundaries assigned to that axis and has the requested transform. Named-only source domains are accepted when no primary X is used. There must be at least one full numeric/time X domain under the shared source contract. Histogram source assignments require explicit sample bindings when the field identities cannot be inferred before the first load.

fullDomain.y, when supplied, still describes primary Y in the applied raw aggregation units. Area encoding ignores that raw hint and derives global densities from complete bins. Secondary/named-Y global metrics are likewise inferred from their complete summaries. Authored axis bounds still win.

A missing/mismatched partition or domain rejects the response without replacing the accepted chart. Global statistics stay stable within one source revision and partition/field request; changing only the loaded window, summary order or axis identity must not alter them. A changed bin policy/transform is a new partition request. Paint/visibility changes do not reload the source. The last accepted complete frame stays visible through loading or errors. Saved models retain accepted summaries; source handles/controllers remain application-owned.

Pivot viewport providers receive the same chart.histogram / chart.histograms hints, with cloned request ownership and exact primary/named window echoes. Normal Pivot scope/query/revision correlation remains in force. PivotChartHistogramCollectionSourceRequest and PivotChartHistogramTooltipItem alias the shared public types.

Standalone histogram collections do not add stacking, independent Y navigation or generic histogram analytical overlays. To combine complete histogram bins with other Cartesian layers, use the distinct bubble and histogram combination contract. The MUI axes reference describes the upstream independent-axis model; these histogram contracts retain the framework-neutral Charts bindings and complete-source semantics.