Skip to main content

Histogram Charts

A histogram visualizes the distribution of a dataset by grouping values into contiguous bins and displaying each bin as a bar whose height represents the count (or frequency) within that range. Typical use cases include frequency distributions, population statistics, and scientific data analysis.

SciChart.js has no dedicated histogram series type. Histograms are assembled from FastRectangleRenderableSeriesšŸ“˜ with XyxyDataSeriesšŸ“˜, using EColumnMode.StartEndšŸ“˜ to place each bar between explicit bin boundaries on the X axis.

tip

The JavaScript Histogram Chart Example can be found in the SciChart.JS Examples Suite on GitHub, or in the live demo at scichart.com/demo.

Above: The JavaScript Histogram Chart example from the SciChart.js Demo

Create a Histogram​

// Histogram bins: each entry defines [x, x1, y] = [binStart, binEnd, count]
// representing Europe's population by age bracket (simplified)
const bins = [
{ x: 0, x1: 20, y: 150_000_000 },
{ x: 20, x1: 30, y: 75_000_000 },
{ x: 30, x1: 45, y: 112_000_000 },
{ x: 45, x1: 65, y: 138_000_000 },
{ x: 65, x1: 70, y: 32_000_000 },
{ x: 70, x1: 80, y: 48_000_000 },
];

const histogramSeries = new FastRectangleRenderableSeries(wasmContext, {
dataSeries: new XyxyDataSeries(wasmContext, {
xValues: bins.map(b => b.x),
yValues: bins.map(b => b.y),
x1Values: bins.map(b => b.x1),
y1Values: bins.map(() => 0),
}),
columnXMode: EColumnMode.StartEnd,
columnYMode: EColumnYMode.TopBottom,
fillLinearGradient: new GradientParams(new Point(0, 0), new Point(0, 1), [
{ color: "rgba(70, 130, 180, 0.9)", offset: 0 },
{ color: "rgba(70, 130, 180, 0.3)", offset: 1 },
]),
strokeThickness: 0,
topCornerRadius: 4,
opacity: 0.85,
dataLabels: {
style: { fontSize: 13, fontFamily: "Arial" },
color: "white",
}
});

In the code above:

  • Each bin is defined as { x, x1, y } — bin start, bin end, and count.
  • XyxyDataSeries stores xValues (bin starts), x1Values (bin ends), yValues (bar tops — the counts), and y1Values (bar bottoms — all zero, the baseline).
  • columnXMode: EColumnMode.StartEnd tells the series that x and x1 are explicit start/end positions on the X axis — each bar fills exactly its bin range with no gaps.
  • columnYMode: EColumnYMode.TopBottom tells the series that y is the bar top and y1 is the bottom.
  • fillLinearGradient applies a vertical blue gradient from the bar top to bottom.
  • topCornerRadius: 4 rounds the top corners; strokeThickness: 0 removes the border.
  • dataLabels renders the count above each bar using the default Y value formatter.

Data Aggregation​

The demo above uses pre-aggregated data. In practice, you start from raw measurements and bin them using breakpoints:

function aggregateToBins(
values: number[],
breakpoints: number[]
): { xValues: number[]; x1Values: number[]; yValues: number[] } {
const xValues: number[] = [];
const x1Values: number[] = [];
const yValues: number[] = [];

for (let i = 0; i < breakpoints.length - 1; i++) {
const lo = breakpoints[i];
const hi = breakpoints[i + 1];
xValues.push(lo);
x1Values.push(hi);
yValues.push(values.filter(v => v >= lo && v < hi).length);
}
return { xValues, x1Values, yValues };
}

// Example: bin 1000 random ages into ranges
const rawAges = Array.from({ length: 1000 }, () => Math.random() * 80);
const { xValues, x1Values, yValues } = aggregateToBins(rawAges, [0, 20, 30, 45, 65, 80]);

Pass the result directly into XyxyDataSeries:

new XyxyDataSeries(wasmContext, { xValues, yValues, x1Values })

Axes​

X Axis​

A standard NumericAxisšŸ“˜ with axisTitle and a small growBy padding so the outermost bars don't clip against the chart edge:

sciChartSurface.xAxes.add(new NumericAxis(wasmContext, {
axisTitle: "Age (years)",
growBy: new NumberRange(0.05, 0.05)
}));

Y Axis​

Use labelFormat: ENumericFormat.Engineering to display large population counts compactly (e.g. 150M instead of 150000000):

sciChartSurface.yAxes.add(new NumericAxis(wasmContext, {
axisTitle: "Population",
labelFormat: ENumericFormat.Engineering,
growBy: new NumberRange(0, 0.2) // headroom above the tallest bar for data labels
}));

Styling​

Key styling properties on FastRectangleRenderableSeriesšŸ“˜:

PropertyPurpose
fillLinearGradientVertical gradient fill using GradientParamsšŸ“˜
fillSolid fill color (alternative to gradient)
opacityBar transparency (0–1)
topCornerRadiusRounds top corners of each bar
strokeThicknessSet to 0 to remove bar outlines

Data Labels​

dataLabels on the series renders the Y value above each bar. Override dataLabelProvider.getText to format the displayed value:

dataLabels: {
style: { fontSize: 13, fontFamily: "Arial" },
color: "white",
}

To show custom formatted text, override the label provider after construction:

histogramSeries.dataLabelProvider.getText = (state) =>
(state.yVal() / 1_000_000).toFixed(0) + "M";

Chart Modifiers​

Standard zoom and pan modifiers work unchanged with histogram series:

sciChartSurface.chartModifiers.add(
new ZoomPanModifier(),
new ZoomExtentsModifier(),
new MouseWheelZoomModifier()
);

Custom Texture Fills​

FastRectangleRenderableSeriesšŸ“˜ supports a customTextureOptions property that accepts an ICustomTextureOptionsšŸ“˜ implementation. This enables pictograph-style (isotype) histograms where bars are filled with a repeating icon pattern — as seen in the live showcase above, which uses a custom StickFigureTextureOptions class to render proportionally-scaled stick figures inside each bar. For an introduction to custom texture fills see the Custom Texture styling example.

See Also​