Skip to content

Axis bounds ​

min and max set an axis domain outright. Values outside the range are clipped at the plot edge rather than allowed to overflow, and a band marks each edge that is hiding something.

ts
// min and max set the axis domain outright. The 1400ms spike sits well outside
// max, so it is clipped to the plot instead of flattening everything else, and
// the clip indicator band marks the edge that is hiding it.
import type { MochartInputConfig } from '@mochart/core';

export const config: MochartInputConfig = {
  version: '1.0.0',
  title: { text: 'p95 Response Time' },
  categoryAxis: { property: 'time', type: 'string', scale: 'ordinal' },
  valueAxes: [{ id: 'VA0', title: { text: 'Response time (ms)' }, min: 0, max: 200 }],
  series: [
    {
      property: 'ms',
      title: 'p95',
      renderer: 'line',
      marker: { shape: 'circle' }
    }
  ]
};

export const data = [
  { time: '09:00', ms: 118 },
  { time: '09:05', ms: 124 },
  { time: '09:10', ms: 109 },
  { time: '09:15', ms: 132 },
  { time: '09:20', ms: 1408 },
  { time: '09:25', ms: 141 },
  { time: '09:30', ms: 116 },
  { time: '09:35', ms: 127 },
  { time: '09:40', ms: 105 },
  { time: '09:45', ms: 119 }
];

How it works ​

  • min/max are hard bounds: the domain becomes exactly the range given, whatever the data does. One outlier no longer flattens the rest of the series into a band at the bottom of the plot.
  • A clipped mark keeps the part that is inside. The line above enters and leaves the top edge rather than vanishing for that category, so a hidden value never reads as missing data.
  • To keep a value in view without ever clipping, use softMin / softMax instead. They extend the domain to the bound when the data does not already reach it, and give way when it does — see positive and negative for holding zero in view that way.
  • Both bounds default to auto, which fits the domain to the data (plus minMarginFraction / maxMarginFraction). An auto end never clips on its own.
  • minOffset / maxOffset shift an auto end by a fixed amount once the data has been fitted, which is how you pad or tighten a domain without pinning it to a number. Shifting a bound inward hides data, so an offset end clips like an explicit one and gets the same indicator band. They apply only to an end left on auto.
  • min must not be above max when both are set; the config is rejected otherwise. To run an axis backwards use reversed, below.
  • The same properties exist on the category axis, on any scale but ordinal, where they window a numeric or date range (a date bound is an ISO string or a millisecond timestamp).
  • plot.clipOverflow sets how far (in pixels) marks may spill past each edge before being cut. Raise it when a marker or a thick stroke sitting on the boundary is being shaved.

Marking what is hidden ​

The band comes from the clip indicator, which draws on every plot edge with data behind it and needs no configuration to appear.

  • label sets the text, which doubles as the band's accessible name and shows on hover. Set it to null for a band with no text.
  • size is the band depth, defaulting to auto — the label height plus labelPadding on both sides.
  • hatch sets the diagonal fill's spacing and lineWidth. Set it to null for a flat fill instead, which also lightens the style default, since a solid band at the hatched weight reads much heavier.
  • Two axes clipping the same edge produce one band. Bands on neighbouring edges meet on a diagonal, so no corner is drawn twice.
  • visible: false turns the band off. Clipping itself still happens — the values are hidden either way, so leaving it on is what tells a reader they are.

Reversing an axis ​

ts
// reversed flips which end of the axis each bound sits at. A rank reads best
// with first place at the top, which is the opposite of the default direction.
import type { MochartInputConfig } from '@mochart/core';

export const config: MochartInputConfig = {
  version: '1.0.0',
  title: { text: 'League Position' },
  categoryAxis: { property: 'week', type: 'string', scale: 'ordinal' },
  valueAxes: [{ id: 'VA0', title: { text: 'Position' }, reversed: true, min: 1, max: 10, tickLabel: { format: 'd' } }],
  series: [
    {
      property: 'position',
      title: 'Position',
      renderer: 'line',
      marker: { shape: 'circle' }
    }
  ]
};

export const data = [
  { week: 'Wk 1', position: 8 },
  { week: 'Wk 2', position: 7 },
  { week: 'Wk 3', position: 9 },
  { week: 'Wk 4', position: 5 },
  { week: 'Wk 5', position: 4 },
  { week: 'Wk 6', position: 6 },
  { week: 'Wk 7', position: 3 },
  { week: 'Wk 8', position: 2 }
];
  • reversed runs an axis backwards. min is still the lower bound — the flag changes which end of the plot that bound sits at, so a rank of 1 lands at the top.
  • It works on every axis, including the category axis and ordinal scales, where it reverses the slot order.
  • It composes with plot.inverted, which is a different setting: inverted swaps which screen direction each axis runs along (see horizontal charts), while reversed flips one axis end for end.
  • Base lines, thresholds, ticks and stacking are unaffected — the domain still ascends, only its screen direction changes.

Released under the MIT License.