Skip to content

Value axis

The primary range (and secondary range) axes are linear value scales. On a vertical chart that is usually axes.left; on a horizontal chart it is axes.bottom. Always write to the side that holds id: 'primaryRange' (or 'secondaryRange') after orientation remap – see Orientation.

js
axes: {
  left: {
    id: 'primaryRange',
    labels: {
      preferredTickInterval: null, // auto
      customMin: null,
      customMax: null,
      numberFormat: {
        mode: 'custom',
        customFormat: {
          prefix: '',
          postfix: '',
          thousandSeparator: ',',
          decimalSeparator: '.',
          decimalPlaces: 0,
          forceDecimals: true,
          signDisplay: 'auto',
          scaleDown: 0,
        },
      },
    },
  },
}

Full format field reference: Number formats.


Two modes: interval vs bounds

Ticks and bounds are mutually exclusive drivers. Change one; do not fight both at once.

Interval / auto modeBounds mode
TriggerLeave min/max null; optionally set preferredTickIntervalSet customMin and/or customMax
BoundsAuto-round to multiples of the chosen intervalFixed to your min/max
IntervalPrefers your preferredTickInterval when allowedAuto-picked so ticks land on the bounds

If you pin bounds and a preferred interval that cannot divide the span, the engine adjusts the interval (or ignores the preference). Chasing both by hand causes a feedback loop – pick one mode.


Preferred interval

preferredTickInterval is a step size (e.g. 10, 25, 50), not “number of labels.”

js
axes: {
  left: {
    labels: {
      preferredTickInterval: 25,
    },
  },
}

Leave it null for new charts so auto sparse selection runs from the space budget:

Space for (max labels)Aim for
1–5~2 labels
6–13~3
14–20~4
21+~5

Nice candidates are values like 1, 2, 2.5, 5, 10 × powers of 10.

Do not hand-author customTickInterval. The engine writes that field when resolving ticks. Authors set preferredTickInterval (or leave null).

Percentage charts

For stackedBar100, stackedArea100, and mekko value axes, allowed intervals are filtered to divisors of 100 (1, 2, 2.5, 4, 5, 10, 20, 25, 50, 100). Prefer 20 / 25 / 50 for clean decks. Defaults already seed postfix: '%'.

See Percent axis sample.


Bounds

js
axes: {
  left: {
    labels: {
      customMin: 0,
      customMax: 200,
    },
  },
}
  • null / omit – auto from data (+ nice rounding in interval mode)
  • Set one or both – bounds mode

Zero rules

Chart familyGuidance
Clustered / stacked bar, stacked area, waterfallUsually keep 0 in range. Cutting off zero exaggerates differences.
Line, scatterZooming with customMin / customMax around the data is often right – zero is not required.
100% / mekko valuePin 0–100 (engine and defaults already bias this way).

If customMin sits above the lowest data point (or customMax below the highest), bars/lines clip. Fix the bound or widen it.

Recipe: zoomed line

js
{
  chartType: 'line',
  isDataTransposed: true,
  seriesData: [/* … */],
  axes: {
    left: {
      labels: {
        customMin: 80,
        customMax: 120,
        preferredTickInterval: 10,
      },
    },
  },
}

Recipe: currency ticks

js
axes: {
  left: {
    labels: {
      preferredTickInterval: 50,
      numberFormat: {
        mode: 'custom',
        customFormat: {
          prefix: '$',
          postfix: '',
          thousandSeparator: ',',
          decimalSeparator: '.',
          decimalPlaces: 0,
          forceDecimals: false,
          signDisplay: 'auto',
          scaleDown: 0,
        },
      },
    },
    axisTitle: {
      visible: true,
      text: 'USD millions',
    },
  },
}

Live: Currency ticks sample.


Horizontal charts

After orientation: 'horizontal', the primary range is on bottom. Put formats, preferred intervals, bounds, and value gridlines there – not on left (that side is domain / categories).

js
{
  orientation: 'horizontal',
  axes: {
    bottom: {
      labels: {
        preferredTickInterval: 20,
        numberFormat: {
          mode: 'custom',
          customFormat: {
            prefix: '',
            postfix: '%',
            decimalPlaces: 0,
            forceDecimals: false,
            thousandSeparator: ',',
            decimalSeparator: '.',
            signDisplay: 'auto',
            scaleDown: 0,
          },
        },
      },
      gridlines: { visible: true },
    },
  },
}

Gridlines

Default for new charts: gridlines visible: false. Turn them on on the value axis side and pair overrides with a fixed preferredTickInterval so tick keys stay stable – Gridlines.


Pitfalls

  • Authoring customTickInterval instead of preferredTickInterval
  • Formatting left after flipping to horizontal (range moved to bottom)
  • Pinning bounds that clip data
  • Using dual custom min/max and an incompatible preferred interval
  • Expecting chartData number format alone to change PNG/slide look – formats are on the axis labels (and linked surfaces)

Next: Domain axis · Secondary · By chart type

Developer documentation for ChartBuddy Embed · Not the end-user Help Center · Help Center