Skip to content

Error Bars

Error bars are first-class series config: set errorLowProperty and errorHighProperty to the data properties holding a point's absolute lower and upper bounds, and the chart draws a capped whisker through every bar or line point.

ts
// Error bars are first-class series config: point errorLowProperty and
// errorHighProperty at the columns holding each point's absolute bounds and
// the chart draws a capped whisker per bar (or line point).
import type { MochartInputConfig } from '@mochart/core';

export const config: MochartInputConfig = {
  version: '1.0.0',
  title: { text: 'Monthly Output with 95% CI (fictional)' },
  categoryAxis: { property: 'month', type: 'string', scale: 'ordinal' },
  valueAxes: [{ title: 'units per day' }],
  seriesGroups: [{ id: 'plants' }],
  series: [
    { id: 'a', title: 'Plant A', property: 'a', renderer: 'bar', group: 'plants',
      errorLowProperty: 'aLow', errorHighProperty: 'aHigh', valueFormat: ',.1f' },
    { id: 'b', title: 'Plant B', property: 'b', renderer: 'bar', group: 'plants',
      errorLowProperty: 'bLow', errorHighProperty: 'bHigh', valueFormat: ',.1f' },
    { id: 'target', title: 'Target', property: 'target', renderer: 'line', group: null,
      errorLowProperty: 'targetLow', errorHighProperty: 'targetHigh', valueFormat: ',.1f' }
  ]
};

export const data = [
  { month: 'Jan', a: 52.1, aLow: 46.1, aHigh: 58.1, b: 47.7, bLow: 44.0, bHigh: 52.4, target: 52.0, targetLow: 50.0, targetHigh: 53.8 },
  { month: 'Feb', a: 64.1, aLow: 58.5, aHigh: 68.2, b: 50.1, bLow: 43.6, bHigh: 55.9, target: 56.5, targetLow: 54.6, targetHigh: 59.5 },
  { month: 'Mar', a: 69.6, aLow: 64.6, aHigh: 75.2, b: 47.1, bLow: 42.7, bHigh: 51.3, target: 59.8, targetLow: 57.7, targetHigh: 61.5 },
  { month: 'Apr', a: 65.5, aLow: 58.6, aHigh: 69.5, b: 54.4, bLow: 50.0, bHigh: 60.3, target: 61.0, targetLow: 58.5, targetHigh: 62.7 },
  { month: 'May', a: 59.7, aLow: 55.4, aHigh: 64.3, b: 51.5, bLow: 46.6, bHigh: 55.9, target: 59.8, targetLow: 57.6, targetHigh: 62.3 },
  { month: 'Jun', a: 55.7, aLow: 49.2, aHigh: 60.4, b: 45.6, bLow: 40.4, bHigh: 51.1, target: 56.5, targetLow: 53.9, targetHigh: 58.6 }
];

How it works

  • The bounds are absolute values in value-axis units (e.g. the ends of a confidence interval), not deltas from the value. For value ± error data, derive the bound columns once when preparing the rows.
  • The bounds join the value axis domain, so whiskers never clip — note the axis above reaching past the tallest bar to cover its upper bound.
  • Whiskers center on each bar's layout slot — including grouped sub-slots, as in the two plant series above — and on the point position for line, area and none renderer series. On horizontal charts they run horizontally with vertical caps.
  • Either bound works alone: a category missing one bound draws a one-sided whisker from the point to the defined bound, and a category missing both draws no whisker. A missing bound is a legitimate one-sided error bar, so the tooltip renders nothing for it rather than the missing-value text.
  • Stacked series can't take error properties — absolute bounds have no meaning against a cumulative stack position — and config validation rejects the combination.
  • The tooltip appends the bounds after the value, joined by the tooltip's rangeValueSeparator: 56.5 (53.9 - 58.6).
  • Styling: errorBarCapSize sets the cap width in pixels (0 hides the caps; on bars the caps clamp to the bar slot), and errorBarStyle paints the whisker itself. Being a line, it takes a stroke-only style — strokeColor, strokeOpacity, strokeWidth and strokeDashArray (e.g. "5, 5"; null for a solid whisker) — once per focus state. The default strokeColor is "series" in normal and "same" in focused and defocused, so whiskers follow their series' color through focus, while the opacities (0.9 normally, 1 focused, 0.5 defocused) dim them alongside it. Only the members you name are overridden, so thickening just the focused whisker is errorBarStyle: { focused: { strokeWidth: 3 } }.
  • Whiskers animate with their series: value transitions share one duration across the point and its bounds, so the whisker stays glued to a moving bar, and entering categories grow their whisker out of the axis base with the bar.

Released under the BSD-3-Clause License.