Per-datum colours
By default, every chart picks one colour per series from the active theme palette. When you want a single bar, slice, or point to render in its own colour, SwiftChart gives you four ways to express it — pick the one closest to the shape of your data.
Resolution order
Section titled “Resolution order”The four layers are tried high-to-low. The first one that returns a colour wins; the rest are skipped:
| Layer | Where it lives | Best for |
|---|---|---|
| 1 | config.colorFn callback | value-driven rules (“red if negative”) |
| 2 | Dataset.colors[i] array | static, designer-picked colours per slot |
| 3 | mapping.colorField (resolves into colors[]) | data-bound categorical colours |
| 4 | Dataset.color | the existing series-wide override |
| 5 | Theme palette | fallback |
You can mix layers freely — for example, a colorMap for normal points plus a colorFn that highlights the row under hover.
1. colorFn — conditional colours by value
Section titled “1. colorFn — conditional colours by value”The callback runs once per datum at draw time. Return undefined to fall through to the next layer.
new BarChart('#chart', { colorFn: (v) => v < 0 ? '#ef4444' : v > 600 ? '#22c55e' : '#5b8cff',}).setData(regionPnL, { x: 'region', y: 'pnl' });The same effect using colorField — bound to a row attribute so the live preview works without serialising a function:
2. Dataset.colors — explicit per-slot palette
Section titled “2. Dataset.colors — explicit per-slot palette”When you already know the colour for each slot at build time, pass a parallel array. Falsy entries fall through, so you can colour just a few standout points:
chart.setData([], { labels: ['Q1', 'Q2', 'Q3', 'Q4'], datasets: [{ label: 'Revenue', data: [120, 180, 90, 240], colors: [undefined, undefined, '#fbbf24', undefined], // highlight Q3 }],});3. mapping.colorField — data-bound colours
Section titled “3. mapping.colorField — data-bound colours”Carry the colour (or a category that maps to one) on the row itself. SwiftChart resolves it once at setData time, so there’s no per-frame cost.
The field value can be:
- A CSS colour string (
#,rgb(),hsl(),oklch(), named colours) — used verbatim. - A category key matched against
colorMapfor an explicit lookup. - Anything else — hashed deterministically into the theme palette so the same category always lands on the same colour across re-renders.
The resolve runs once at setData time and once again on every theme change (chart.setTheme(...) or update({ theme })) — categorical values that hash into the palette flip to the new theme’s colours; explicit colorMap entries and verbatim CSS colour strings stay put. There’s no per-frame cost either way.
const traffic = [ { source: 'Organic', visits: 4200, status: 'good' }, { source: 'Direct', visits: 3100, status: 'good' }, { source: 'Social', visits: 1800, status: 'warn' }, { source: 'Referral', visits: 1100, status: 'warn' }, { source: 'Email', visits: 800, status: 'bad' }, { source: 'Paid Ads', visits: 600, status: 'bad' },];
chart.setData(traffic, { x: 'source', y: 'visits', colorField: 'status', colorMap: { good: '#22c55e', warn: '#f59e0b', bad: '#ef4444' },});4. Pies, treemaps, and funnels
Section titled “4. Pies, treemaps, and funnels”The same API works on every chart whose datums are naturally per-slot. A pie’s slices are a good example:
new PieChart('#chart').setData(traffic, { labelField: 'source', valueField: 'visits', colorField: 'source', colorMap: { Organic: '#5b8cff', Direct: '#22c55e', Social: '#f59e0b', Referral: '#a855f7', Email: '#06b6d4', 'Paid Ads': '#ef4444', },});5. Highlighting a single point on a line chart
Section titled “5. Highlighting a single point on a line chart”colorFn applies to dot fills on line charts (the line stroke stays at the series level so it doesn’t change colour mid-segment):
new LineChart('#chart', { dots: true, colorFn: (v, i) => i === 7 ? '#fbbf24' : undefined,}).setData(monthlySales, { x: 'month', y: 'revenue' });You can achieve the same with a colors[] array on a pre-built dataset:
chart.setData([], { labels: months, datasets: [{ label: 'Revenue', data: revenue, colors: revenue.map((_, i) => i === 7 ? '#fbbf24' : undefined), }],});Where it applies
Section titled “Where it applies”| Chart | Datum-level colouring | How |
|---|---|---|
| Bar, HBar, Stacked Bar, Combo (bars), Marimekko | ✅ each bar / cell | colorFn, colors[], colorField |
| Pie / Donut, Treemap, Funnel, Radial Bar | ✅ each slice / tile | colorFn, colorField |
| Scatter, Bubble | ✅ each point | colorFn (overrides group palette) |
| Line / Area | ✅ each dot (stroke stays per series) | colorFn, colors[] |
| Waterfall, Candlestick | ⛔ semantic (positive/negative, up/down) | use theme.positive / theme.negative |
| Heatmap | ⛔ already a value→colour gradient | use colorScale |
Performance
Section titled “Performance”colorFieldis resolved exactly once, atsetDatatime — it adds no per-frame cost.colorFnruns once per visible datum per redraw. Keep it pure and side-effect-free.Dataset.colorsis a sparse array, so a single highlighted point doesn’t pay for the rest.- The fallback hash (
hashStr) is FNV-1a — a few cycles per category.
API references
Section titled “API references”ColorFnDataset.colorsDataMapping.colorFieldandcolorMapdatumColor()— the resolver, exported for custom chart subclasses