Appearance
Are you an LLM? You can read better optimized documentation at /embed/docs/configuration/number-formats.md for this page in Markdown format
Number formats
Every numeric surface uses the same spec shape. There is no separate sibling format bag.
js
{
mode: 'custom', // or 'linked'
source: undefined, // only when mode is 'linked'
customFormat: {
prefix: '',
postfix: '',
thousandSeparator: ',',
decimalSeparator: '.',
decimalPlaces: 0,
forceDecimals: true,
signDisplay: 'auto', // 'auto' | 'always' | 'parens'
scaleDown: 0,
},
}| Field | Role |
|---|---|
mode | 'custom' — this surface owns customFormat. 'linked' — inherit another surface |
source | When linked: 'primaryRangeAxis' | 'dataLabels' | 'totalLabels' |
customFormat | The formatting knobs (also kept as an unlink stash when linked) |
prefix / postfix | Strings before / after the number (postfix: '%' on percentage charts) |
thousandSeparator / decimalSeparator | Grouping and decimal marks |
decimalPlaces | Digits after the decimal |
forceDecimals | Pad to decimalPlaces even with trailing zeros |
signDisplay | 'auto' | 'always' | 'parens' |
scaleDown | Scale exponent (0 = raw; higher values shorten large magnitudes) |
Not a number format: category date patterns live at axes.<side>.labels.dateFormat.format (a string like 'MMM D, YYYY').
1. Axes
Value-axis tick labels. Path is always under the side that holds that axis for the current orientation.
| Surface | Path | Notes |
|---|---|---|
| Primary value axis (Y on vertical charts) | axes.left.labels.numberFormat | Usually the main “Y-axis” format hub |
| Primary value axis (Y on horizontal charts) | axes.bottom.labels.numberFormat | Same role after orientation flip |
| Secondary value axis | axes.right (vertical) or axes.top (horizontal) .labels.numberFormat | Dual-axis; typically mode: 'custom' only — see Secondary |
| Domain / category axis | axes.<side>.labels.numberFormat | Rarely used for numbers; mekko-style % domain ticks are the main case |
Link targets elsewhere refer to the primary value axis as source: 'primaryRangeAxis' (not the side name).
js
axes: {
left: {
labels: {
numberFormat: {
mode: 'custom',
customFormat: {
prefix: '$',
postfix: '',
thousandSeparator: ',',
decimalSeparator: '.',
decimalPlaces: 0,
forceDecimals: true,
signDisplay: 'auto',
scaleDown: 0,
},
},
},
},
}2. Chart labels
Whole-chart label formats under annotations.
Data labels
| Surface | Path | Default / notes |
|---|---|---|
| Main data-label format | annotations.dataLabels.numberFormat | Hub used by Absolute when Absolute is linked |
| Absolute part | annotations.dataLabels.numberFormatAbsolute | Defaults to mode: 'linked', source: 'dataLabels' |
| Percentage part | annotations.dataLabels.numberFormatPercentage | Defaults to custom with postfix: '%' |
Which part paints depends on annotations.dataLabels.labelParts (e.g. ['absolute'], ['percentage'], ['absolute','percentage']). Pie / donut slice labels also use these Absolute / Percentage helpers.
js
annotations: {
dataLabels: {
labelParts: ['absolute'],
numberFormat: {
mode: 'custom',
customFormat: { /* … */ },
},
numberFormatAbsolute: {
mode: 'custom', // or keep linked to 'dataLabels'
customFormat: { /* … */ },
},
numberFormatPercentage: {
mode: 'custom',
customFormat: {
prefix: '',
postfix: '%',
thousandSeparator: ',',
decimalSeparator: '.',
decimalPlaces: 0,
forceDecimals: true,
signDisplay: 'auto',
scaleDown: 0,
},
},
},
}Stack / column totals
| Surface | Path | Charts |
|---|---|---|
| Totals | annotations.totals.numberFormat | Stacked bar / stackedBar100, mekko, bar mekko, waterfall |
Not used on line or area (no stack totals). Changing the Y-axis does not change totals unless totals are linked to primaryRangeAxis.
js
annotations: {
totals: {
visible: true,
numberFormat: {
mode: 'custom',
customFormat: { /* … */ },
},
},
}3. Annotation overlays
Per-object formats. Each arrow / line has its own spec (not shared chart-wide).
Level lines
| Surface | Path |
|---|---|
| Level-line value label | annotations.levelLines.<id>.labelNumberFormatSpec |
Same shape as numberFormat. Default when unset: follow the primary Y-axis (linked → primaryRangeAxis). Lines bound to the secondary axis follow that axis’s custom format. See Level lines.
js
annotations: {
levelLines: {
target: {
value: 70,
labelNumberFormatSpec: {
mode: 'custom',
customFormat: { /* … */ },
},
},
},
}Arrows (difference, CAGR, level)
Each entry under these maps can carry Absolute and Percentage specs:
| Kind | Map path | Absolute | Percentage |
|---|---|---|---|
| Difference | annotations.differenceArrows.<id> | numberFormatAbsolute | numberFormatPercentage |
| CAGR | annotations.cagrs.<id> | numberFormatAbsolute | numberFormatPercentage |
| Level | annotations.levelArrows.<id> | numberFormatAbsolute | numberFormatPercentage |
Which of Absolute / Percentage appears depends on that arrow’s displayMode / labelParts. See Arrows.
js
annotations: {
differenceArrows: {
q1VsQ2: {
start: 0,
end: 1,
displayMode: 'absoluteWithPercentage',
numberFormatAbsolute: {
mode: 'custom',
customFormat: { /* … */ },
},
numberFormatPercentage: {
mode: 'custom',
customFormat: {
prefix: '',
postfix: '%',
thousandSeparator: ',',
decimalSeparator: '.',
decimalPlaces: 1,
forceDecimals: true,
signDisplay: 'auto',
scaleDown: 0,
},
},
},
},
}4. Linking
Three hubs can be link sources: primary Y-axis (primaryRangeAxis), data labels (dataLabels), totals (totalLabels).
| Target | Can link to |
|---|---|
| Primary Y-axis | dataLabels, totalLabels |
| Data labels | primaryRangeAxis, totalLabels |
| Totals | primaryRangeAxis, dataLabels |
| Absolute / Percentage parts | dataLabels, primaryRangeAxis, totalLabels |
| Arrow Absolute / Percentage | primaryRangeAxis, dataLabels, totalLabels |
| Level-line labels | primaryRangeAxis, dataLabels, totalLabels |
Hand-authored configs should prefer mode: 'custom' so the format does not depend on another surface.
js
// Totals follow the Y-axis
annotations: {
totals: {
numberFormat: {
mode: 'linked',
source: 'primaryRangeAxis',
customFormat: { /* stash if unlinked later */ },
},
},
}5. Quick path index
| Category | Full path |
|---|---|
| Primary / secondary / domain axis | axes.<left|right|bottom|top>.labels.numberFormat |
| Data labels (main) | annotations.dataLabels.numberFormat |
| Data-label Absolute | annotations.dataLabels.numberFormatAbsolute |
| Data-label Percentage | annotations.dataLabels.numberFormatPercentage |
| Stack totals | annotations.totals.numberFormat |
| Level-line label | annotations.levelLines.<id>.labelNumberFormatSpec |
| Difference arrow Absolute / % | annotations.differenceArrows.<id>.numberFormatAbsolute / numberFormatPercentage |
| CAGR arrow Absolute / % | annotations.cagrs.<id>.numberFormatAbsolute / numberFormatPercentage |
| Level arrow Absolute / % | annotations.levelArrows.<id>.numberFormatAbsolute / numberFormatPercentage |
Percentage chart types (stackedBar100, stackedArea100, mekko) often set customFormat.postfix: '%' on the surfaces you care about (usually the primary axis and/or totals).