--- url: https://chartbuddy.io/embed/docs/axes/secondary.md --- > Docs index: [llms.txt](https://chartbuddy.io/embed/docs/llms.txt) # Secondary / dual axis Use a secondary value axis when two series need **independent scales** (e.g. revenue in dollars vs growth in %). Same units on two axes is usually harder to read; prefer one axis when you can. Secondary sits on: | Orientation | Secondary side | |---|---| | `vertical` | `right` | | `horizontal` | **`top`** | *** ## Config shape ```js axes: { right: { id: 'secondaryRange', enabled: true, visible: true, boundSeries: [1], // original series indices (0-based) labels: { preferredTickInterval: 10, numberFormat: { mode: 'custom', customFormat: { prefix: '', postfix: '%', decimalPlaces: 0, forceDecimals: false, thousandSeparator: ',', decimalSeparator: '.', signDisplay: 'auto', scaleDown: 0, }, }, }, axisTitle: { visible: true, text: 'Growth' }, }, } ``` | Field | Role | |---|---| | `enabled` / `visible` | Turn the secondary scale and chrome on | | `boundSeries` | Which **original** series indices use this scale (not filtered/display order) | | `labels.*` | Independent ticks, bounds, and formats from the primary range | | `breaks` | Supported on secondary the same way as primary – see [Breaks](https://chartbuddy.io/embed/docs/axes/breaks.md) | Series **not** listed in `boundSeries` stay on the primary range. Primary bounds **exclude** secondary-bound series so each scale fits its own data. *** ## Line charts Dual-axis is fully supported on **line** charts: ```js { chartType: 'line', isDataTransposed: true, seriesData: [ ['', 'Q1', 'Q2', 'Q3', 'Q4'], ['Revenue', 120, 132, 141, 155], ['Margin %', 18, 19, 17, 21], ], axes: { left: { axisTitle: { visible: true, text: 'Revenue' }, labels: { numberFormat: { mode: 'custom', customFormat: { prefix: '$', postfix: '', decimalPlaces: 0, forceDecimals: false, thousandSeparator: ',', decimalSeparator: '.', signDisplay: 'auto', scaleDown: 0, }, }, }, }, right: { id: 'secondaryRange', enabled: true, visible: true, boundSeries: [1], axisTitle: { visible: true, text: 'Margin %' }, labels: { preferredTickInterval: 5, numberFormat: { mode: 'custom', customFormat: { prefix: '', postfix: '%', decimalPlaces: 0, forceDecimals: false, thousandSeparator: ',', decimalSeparator: '.', signDisplay: 'auto', scaleDown: 0, }, }, }, }, }, } ``` Live: [Dual-axis line sample](https://chartbuddy.io/embed/docs/samples/dual-axis-line.md). Indices in `boundSeries` match **row order in `seriesData`** after the header row – series `0` is the first data row, series `1` the second, and so on. *** ## Horizontal dual axis (secondary on top) With `orientation: 'horizontal'`, put secondary on **`top`**: ```js { orientation: 'horizontal', chartType: 'line', axes: { bottom: { /* primaryRange – values */ }, top: { id: 'secondaryRange', enabled: true, visible: true, boundSeries: [1], }, left: { /* domain – categories */ }, }, } ``` Give the chart enough height: domain labels on the left plus a top value axis need vertical room. *** ## Combo charts Combo can bind series to the secondary axis the same way (`boundSeries` + `enabled` / `visible`). Pair with `combo.seriesTypes` so the secondary series renders as a line (or whatever type you need): ```js { chartType: 'combo', isDataTransposed: true, seriesData: [ ['', 'Q1', 'Q2', 'Q3', 'Q4'], ['Units', 40, 48, 52, 61], ['ASP', 12, 11, 13, 14], ], combo: { seriesTypes: { 1: 'line' }, }, axes: { right: { id: 'secondaryRange', enabled: true, visible: true, boundSeries: [1], labels: { numberFormat: { mode: 'custom', customFormat: { prefix: '$', postfix: '', decimalPlaces: 0, forceDecimals: false, thousandSeparator: ',', decimalSeparator: '.', signDisplay: 'auto', scaleDown: 0, }, }, }, }, }, } ``` Bars that stay on the primary axis still share one primary scale. Prefer exporting from the editor if you are unsure of series indices after reordering. *** ## Anti-patterns * Two axes for the **same** unit (readers compare the wrong scale) * Forgetting `enabled: true` **and** `visible: true` * Wrong `boundSeries` index after inserting/reordering series rows * Putting secondary on `right` after flipping to horizontal (it moves to `top`) Next: [Value axis](https://chartbuddy.io/embed/docs/axes/value-axis.md) · [Breaks](https://chartbuddy.io/embed/docs/axes/breaks.md) · [By chart type](https://chartbuddy.io/embed/docs/axes/by-chart-type.md)