Specialty
One-page tour of Highcharts' specialty series. Each registers its own module (Tier B) — the callout on every example shows the exact import.
Usage
Create a chart atom with standard Highcharts options,
then render Chart(chart) anywhere in a
mates template. Every later chart.set(…) or
chart.update(…) re-renders the chart — no
imperative Highcharts code.
import { html } from "mates";
import { Chart, chartAtom } from "mates-charts";
const chart = chartAtom({
chart: {
type: "dumbbell"
},
title: {
text: "Onboarding time: before vs after redesign"
},
credits: {
enabled: false
},
colors: [
"#00968c",
"#06b6d4",
"#d97706",
"#7c3aed",
"#dc2626",
"#16a34a",
"#0172ad",
"#9333ea"
],
legend: {
enabled: false
},
xAxis: {
categories: [
"Self-serve",
"Guided",
"Enterprise",
"Migration"
]
},
yAxis: {
title: {
text: "days"
}
},
plotOptions: {
dumbbell: {
lowColor: "#94a3b8"
}
},
series: [
{
type: "dumbbell",
name: "Days",
data: [
[
14,
5
],
[
21,
8
],
[
30,
22
],
[
45,
18
]
]
}
]
});
// render inside any mates template — give the wrapper a height:
export const MyChart = () =>
html`<div style="height: 22rem">${Chart(chart)}</div>`;
Live examples
A [low, high] pair per category connected by a stem — before/after, then/now comparisons in their most compact form.
import { html } from "mates";
import { Chart, chartAtom } from "mates-charts";
const chart = chartAtom({
chart: {
type: "dumbbell"
},
title: {
text: "Onboarding time: before vs after redesign"
},
credits: {
enabled: false
},
colors: [
"#00968c",
"#06b6d4",
"#d97706",
"#7c3aed",
"#dc2626",
"#16a34a",
"#0172ad",
"#9333ea"
],
legend: {
enabled: false
},
xAxis: {
categories: [
"Self-serve",
"Guided",
"Enterprise",
"Migration"
]
},
yAxis: {
title: {
text: "days"
}
},
plotOptions: {
dumbbell: {
lowColor: "#94a3b8"
}
},
series: [
{
type: "dumbbell",
name: "Days",
data: [
[
14,
5
],
[
21,
8
],
[
30,
22
],
[
45,
18
]
]
}
]
});
// render inside any mates template — give the wrapper a height:
export const MyChart = () =>
html`<div style="height: 22rem">${Chart(chart)}</div>`;
A column chart reduced to a stem and a dot — cleaner for many categories with small value differences.
import { html } from "mates";
import { Chart, chartAtom } from "mates-charts";
const chart = chartAtom({
chart: {
type: "lollipop"
},
title: {
text: "Bundle size by chart type"
},
credits: {
enabled: false
},
colors: [
"#00968c",
"#06b6d4",
"#d97706",
"#7c3aed",
"#dc2626",
"#16a34a",
"#0172ad",
"#9333ea"
],
legend: {
enabled: false
},
xAxis: {
categories: [
"line",
"area",
"column",
"pie",
"gauge",
"heatmap"
]
},
yAxis: {
title: {
text: "KB (gzip)"
}
},
series: [
{
type: "lollipop",
name: "KB",
data: [
12,
14,
13,
16,
21,
24
]
}
]
});
// render inside any mates template — give the wrapper a height:
export const MyChart = () =>
html`<div style="height: 22rem">${Chart(chart)}</div>`;
Column widths carry a second dimension (z) — value per unit of width, like revenue per employee.
import { html } from "mates";
import { Chart, chartAtom } from "mates-charts";
const chart = chartAtom({
chart: {
type: "variwide"
},
title: {
text: "Revenue per engineer by team"
},
credits: {
enabled: false
},
colors: [
"#00968c",
"#06b6d4",
"#d97706",
"#7c3aed",
"#dc2626",
"#16a34a",
"#0172ad",
"#9333ea"
],
legend: {
enabled: false
},
xAxis: {
type: "category"
},
yAxis: {
title: {
text: "$k / engineer"
}
},
plotOptions: {
variwide: {
dataLabels: {
enabled: true,
format: "{point.y}"
}
}
},
series: [
{
type: "variwide",
name: "Revenue",
data: [
[
"Platform",
920,
2
],
[
"Web",
610,
5
],
[
"Mobile",
480,
3
],
[
"Data",
350,
1
],
[
"Infra",
280,
1
]
],
colorByPoint: true
}
]
});
// render inside any mates template — give the wrapper a height:
export const MyChart = () =>
html`<div style="height: 22rem">${Chart(chart)}</div>`;
Arrows from [x, y] with length and angle as the third/forth values — wind, flow fields, forces.
import { html } from "mates";
import { Chart, chartAtom } from "mates-charts";
const chart = chartAtom({
chart: {
type: "vector"
},
title: {
text: "Wind field"
},
credits: {
enabled: false
},
colors: [
"#00968c",
"#06b6d4",
"#d97706",
"#7c3aed",
"#dc2626",
"#16a34a",
"#0172ad",
"#9333ea"
],
legend: {
enabled: false
},
xAxis: {
min: 0,
max: 10,
tickInterval: 2
},
yAxis: {
min: 0,
max: 10,
tickInterval: 2
},
plotOptions: {
vector: {
vectorLength: 22
}
},
series: [
{
type: "vector",
name: "Wind",
data: [
[
2,
2,
6,
40
],
[
5,
2,
8,
60
],
[
8,
2,
5,
20
],
[
2,
5,
7,
80
],
[
5,
5,
4,
100
],
[
8,
5,
9,
70
],
[
2,
8,
5,
130
],
[
5,
8,
6,
110
],
[
8,
8,
7,
150
]
]
}
]
});
// render inside any mates template — give the wrapper a height:
export const MyChart = () =>
html`<div style="height: 22rem">${Chart(chart)}</div>`;
The meteorological standard: barbs encode speed and direction at each grid point.
import { html } from "mates";
import { Chart, chartAtom } from "mates-charts";
const chart = chartAtom({
chart: {
type: "windbarb"
},
title: {
text: "Surface winds"
},
credits: {
enabled: false
},
colors: [
"#00968c",
"#06b6d4",
"#d97706",
"#7c3aed",
"#dc2626",
"#16a34a",
"#0172ad",
"#9333ea"
],
legend: {
enabled: false
},
xAxis: {
min: 0,
max: 12,
tickInterval: 3
},
yAxis: {
min: 0,
max: 12,
tickInterval: 3
},
series: [
{
type: "windbarb",
name: "Wind",
data: [
[
3,
3,
12,
240
],
[
6,
3,
18,
220
],
[
9,
3,
8,
260
],
[
3,
6,
22,
210
],
[
6,
6,
15,
250
],
[
9,
6,
9,
280
],
[
3,
9,
10,
300
],
[
6,
9,
14,
270
],
[
9,
9,
20,
240
]
],
vectorLength: 20
}
]
});
// render inside any mates template — give the wrapper a height:
export const MyChart = () =>
html`<div style="height: 22rem">${Chart(chart)}</div>`;
Sets with optional overlaps: { sets: [...] } defines circles and intersections by value.
import { html } from "mates";
import { Chart, chartAtom } from "mates-charts";
const chart = chartAtom({
chart: {
type: "venn"
},
title: {
text: "Tool overlap"
},
credits: {
enabled: false
},
colors: [
"#00968c",
"#06b6d4",
"#d97706",
"#7c3aed",
"#dc2626",
"#16a34a",
"#0172ad",
"#9333ea"
],
legend: {
enabled: false
},
plotOptions: {
venn: {
borderColor: "#ffffff",
borderWidth: 2,
dataLabels: {
enabled: true
}
}
},
series: [
{
type: "venn",
name: "Tools",
data: [
{
sets: [
"mates"
],
value: 12,
name: "mates"
},
{
sets: [
"Highcharts"
],
value: 9,
name: "Highcharts"
},
{
sets: [
"mates",
"Highcharts"
],
value: 5,
name: "mates-charts"
}
]
}
]
});
// render inside any mates template — give the wrapper a height:
export const MyChart = () =>
html`<div style="height: 22rem">${Chart(chart)}</div>`;
Typography as data: { name, weight } points laid out to fit the plot area.
import { html } from "mates";
import { Chart, chartAtom } from "mates-charts";
const chart = chartAtom({
chart: {
type: "wordcloud"
},
title: {
text: "Chart library vocabulary"
},
credits: {
enabled: false
},
colors: [
"#00968c",
"#06b6d4",
"#d97706",
"#7c3aed",
"#dc2626",
"#16a34a",
"#0172ad",
"#9333ea"
],
legend: {
enabled: false
},
plotOptions: {
wordcloud: {
allowExtendPlayingField: true
}
},
series: [
{
type: "wordcloud",
name: "Mentions",
data: [
{
name: "reactive",
weight: 9
},
{
name: "tree-shakeable",
weight: 8
},
{
name: "typed",
weight: 7
},
{
name: "highcharts",
weight: 10
},
{
name: "atom",
weight: 6
},
{
name: "chart",
weight: 5
},
{
name: "dashboard",
weight: 4
},
{
name: "themes",
weight: 3
}
]
}
]
});
// render inside any mates template — give the wrapper a height:
export const MyChart = () =>
html`<div style="height: 22rem">${Chart(chart)}</div>`;
Each unit drawn as a discrete icon-square grid — 20 seats used out of 40 reads instantly.
import { html } from "mates";
import { Chart, chartAtom } from "mates-charts";
const chart = chartAtom({
chart: {
type: "item"
},
title: {
text: "Seat usage"
},
credits: {
enabled: false
},
colors: [
"#00968c",
"#06b6d4",
"#d97706",
"#7c3aed",
"#dc2626",
"#16a34a",
"#0172ad",
"#9333ea"
],
legend: {
enabled: true
},
plotOptions: {
item: {
rows: 3,
size: "90%",
itemPadding: 0.15,
layoutAlgorithm: "square"
}
},
series: [
{
type: "item",
name: "Active",
data: [
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1
]
},
{
type: "item",
name: "Invited",
data: [
1,
1,
1,
1,
1,
1
]
}
]
});
// render inside any mates template — give the wrapper a height:
export const MyChart = () =>
html`<div style="height: 22rem">${Chart(chart)}</div>`;
Target vs actual against qualitative ranges — the compact KPI gauge for dashboards.
import { html } from "mates";
import { Chart, chartAtom } from "mates-charts";
const chart = chartAtom({
chart: {
type: "bullet"
},
title: {
text: "Quarterly KPIs"
},
credits: {
enabled: false
},
colors: [
"#00968c",
"#06b6d4",
"#d97706",
"#7c3aed",
"#dc2626",
"#16a34a",
"#0172ad",
"#9333ea"
],
legend: {
enabled: true
},
xAxis: {
categories: [
"Revenue",
"Uptime",
"NPS"
]
},
yAxis: {
title: {
text: ""
},
plotBands: [
{
from: 0,
to: 60,
color: "rgba(148, 163, 184, 0.25)"
},
{
from: 60,
to: 85,
color: "rgba(148, 163, 184, 0.15)"
}
]
},
plotOptions: {
bullet: {
targetOptions: {
borderWidth: 0,
borderColor: "#0f172a"
}
}
},
series: [
{
type: "bullet",
name: "Actual",
data: [
{
y: 78,
target: 85
},
{
y: 97,
target: 99
},
{
y: 62,
target: 55
}
]
}
]
});
// render inside any mates template — give the wrapper a height:
export const MyChart = () =>
html`<div style="height: 22rem">${Chart(chart)}</div>`;
One base series, two derived series: the histogram bins raw values, the bellcurve overlays the normal distribution.
import { html } from "mates";
import { Chart, chartAtom } from "mates-charts";
const chart = chartAtom({
chart: {
animation: false
},
title: {
text: "Response time distribution"
},
credits: {
enabled: false
},
colors: [
"#00968c",
"#06b6d4",
"#d97706",
"#7c3aed",
"#dc2626",
"#16a34a",
"#0172ad",
"#9333ea"
],
legend: {
enabled: true
},
xAxis: {
title: {
text: "ms"
}
},
yAxis: [
{
title: {
text: "Frequency"
}
},
{
title: {
text: "Density"
},
opposite: true,
visible: false
}
],
series: [
{
type: "scatter",
name: "Samples",
data: [
84,
92,
95,
98,
101,
104,
108,
112,
115,
118,
121,
125,
128,
132,
138,
145,
152,
160,
171,
185
],
visible: false
},
{
type: "histogram",
name: "Histogram",
baseSeries: 0,
zIndex: -1,
xAxis: 0,
yAxis: 0,
binsWidth: 15
},
{
type: "bellcurve",
name: "Bell curve",
baseSeries: 0,
xAxis: 0,
yAxis: 1,
intervalsPerCurve: 6
}
]
});
// render inside any mates template — give the wrapper a height:
export const MyChart = () =>
html`<div style="height: 22rem">${Chart(chart)}</div>`;
Columns plus the cumulative-percentage line — the 80/20 view. The pareto series derives from the first series automatically.
import { html } from "mates";
import { Chart, chartAtom } from "mates-charts";
const chart = chartAtom({
chart: {
animation: false
},
title: {
text: "Defects by cause"
},
credits: {
enabled: false
},
colors: [
"#00968c",
"#06b6d4",
"#d97706",
"#7c3aed",
"#dc2626",
"#16a34a",
"#0172ad",
"#9333ea"
],
legend: {
enabled: true
},
xAxis: {
categories: [
"Config",
"Auth",
"Timeout",
"Validation",
"Network"
]
},
yAxis: [
{
title: {
text: "Count"
}
},
{
title: {
text: "Cumulative %"
},
opposite: true,
max: 100,
labels: {
format: "{value}%"
}
}
],
series: [
{
type: "column",
name: "Defects",
data: [
142,
96,
58,
31,
12
],
yAxis: 0
},
{
type: "pareto",
name: "Cumulative %",
yAxis: 1
}
]
});
// render inside any mates template — give the wrapper a height:
export const MyChart = () =>
html`<div style="height: 22rem">${Chart(chart)}</div>`;
Columns clipped to an SVG path — bars shaped like the thing they measure.
import { html } from "mates";
import { Chart, chartAtom } from "mates-charts";
const chart = chartAtom({
chart: {
type: "pictorial"
},
title: {
text: "Cups of coffee per day"
},
credits: {
enabled: false
},
colors: [
"#00968c",
"#06b6d4",
"#d97706",
"#7c3aed",
"#dc2626",
"#16a34a",
"#0172ad",
"#9333ea"
],
legend: {
enabled: false
},
xAxis: {
categories: [
"Mon",
"Tue",
"Wed",
"Thu",
"Fri"
]
},
yAxis: {
title: {
text: "cups"
}
},
plotOptions: {
series: {
dataLabels: {
enabled: true
}
}
},
paths: [
{
definition: "M20 2 L28 2 L28 44 L20 44 Z M14 2 L14 8 L8 8 L8 14 L14 14 L14 20 L8 20 L8 26 L14 26 L14 32 L8 32 L8 38 L14 38 L14 44 L20 44 L20 2"
}
],
series: [
{
type: "pictorial",
name: "Cups",
data: [
2,
3,
4,
3,
5
],
paths: [
0
]
}
]
});
// render inside any mates template — give the wrapper a height:
export const MyChart = () =>
html`<div style="height: 22rem">${Chart(chart)}</div>`;
Two value series as dots per category with connecting stems — a friendlier alternative to grouped bars for narrow ranges.
import { html } from "mates";
import { Chart, chartAtom } from "mates-charts";
const chart = chartAtom({
chart: {
type: "dot"
},
title: {
text: "Preference by age group"
},
credits: {
enabled: false
},
colors: [
"#00968c",
"#06b6d4",
"#d97706",
"#7c3aed",
"#dc2626",
"#16a34a",
"#0172ad",
"#9333ea"
],
legend: {
enabled: true
},
xAxis: {
categories: [
"18–24",
"25–34",
"35–44",
"45–54",
"55+"
]
},
yAxis: {
title: {
text: "% preferring X"
}
},
series: [
{
type: "dot",
name: "2024",
marker: {
fillColor: "#94a3b8"
},
data: [
[
0,
34,
1
],
[
1,
41,
1
],
[
2,
48,
1
],
[
3,
55,
1
],
[
4,
62,
1
]
]
},
{
type: "dot",
name: "2026",
data: [
[
0,
45,
2
],
[
1,
49,
2
],
[
2,
52,
2
],
[
3,
57,
2
],
[
4,
60,
2
]
]
}
]
});
// render inside any mates template — give the wrapper a height:
export const MyChart = () =>
html`<div style="height: 22rem">${Chart(chart)}</div>`;
The xrange series draws interval bars on a datetime axis — resource bookings, project phases, room occupancy. Data is [start, end] or { x, x2, y, partialFill }.
import "highcharts/modules/xrange";
import { html } from "mates";
import { Chart, chartAtom } from "mates-charts";
const chart = chartAtom({
chart: {
type: "xrange"
},
title: {
text: "Meeting room bookings"
},
credits: {
enabled: false
},
colors: [
"#00968c",
"#06b6d4",
"#d97706",
"#7c3aed",
"#dc2626",
"#16a34a",
"#0172ad",
"#9333ea"
],
legend: {
enabled: false
},
xAxis: {
type: "datetime",
labels: {
format: "{value:%H:%M}"
}
},
yAxis: {
categories: [
"Aurora",
"Borealis",
"Cascade",
"Denali"
],
title: {
text: ""
},
reversed: true
},
plotOptions: {
xrange: {
borderRadius: 6,
borderColor: "#ffffff"
}
},
series: [
{
type: "xrange",
name: "Bookings",
colorByPoint: true,
data: [
{
x: 1780304400000,
x2: 1780311600000,
y: 0
},
{
x: 1780318800000,
x2: 1780327800000,
y: 0
},
{
x: 1780308000000,
x2: 1780315200000,
y: 1
},
{
x: 1780306200000,
x2: 1780317900000,
y: 2
},
{
x: 1780322400000,
x2: 1780333200000,
y: 3
}
]
}
]
});
// render inside any mates template — give the wrapper a height:
export const MyChart = () =>
html`<div style="height: 22rem">${Chart(chart)}</div>`;
partialFill shades completion inside each bar — the lightweight project-progress view.
import { html } from "mates";
import { Chart, chartAtom } from "mates-charts";
const chart = chartAtom({
chart: {
type: "xrange"
},
title: {
text: "Feature progress"
},
credits: {
enabled: false
},
colors: [
"#00968c",
"#06b6d4",
"#d97706",
"#7c3aed",
"#dc2626",
"#16a34a",
"#0172ad",
"#9333ea"
],
legend: {
enabled: false
},
xAxis: {
type: "datetime",
labels: {
format: "{value:%b}"
}
},
yAxis: {
categories: [
"Design",
"API",
"Frontend",
"QA"
],
title: {
text: ""
},
reversed: true
},
plotOptions: {
xrange: {
borderRadius: 6,
borderColor: "#ffffff"
}
},
series: [
{
type: "xrange",
name: "Phases",
colorByPoint: true,
data: [
{
x: 1767225600000,
x2: 1772323200000,
y: 0,
partialFill: 1
},
{
x: 1771113600000,
x2: 1777593600000,
y: 1,
partialFill: 0.7
},
{
x: 1775001600000,
x2: 1782864000000,
y: 2,
partialFill: 0.35
},
{
x: 1780272000000,
x2: 1788220800000,
y: 3,
partialFill: 0.1
}
]
}
]
});
// render inside any mates template — give the wrapper a height:
export const MyChart = () =>
html`<div style="height: 22rem">${Chart(chart)}</div>`;
Options reference
mates-charts passes options straight through to Highcharts — these are the keys that matter for specialty charts. See the full Highcharts API for everything else.
| Option | Type | Default | Description |
|---|---|---|---|
chart.type |
"dumbbell" | "lollipop" | … | — | Each specialty type registers via its highcharts/modules/* import. |
series[].data (dumbbell) |
[low, high][] | — | Stem endpoints per category. |
series[].data (variwide) |
[name, y, z][] | — | z scales column width. |
series[].data (vector) |
[x, y, length, angle][] | — | Arrow origin, magnitude and direction. |
series[].data (venn) |
{ sets, value, name }[] | — | Single sets and intersections. |
series[].baseSeries (histogram/pareto) |
number | — | Index of the source series the derived series computes from. |
series[].binsWidth (histogram) |
number | auto | Bin width of the histogram. |
series[].paths (pictorial) |
number[] | — | Indices into series[].paths — SVG path definitions. |