Bubble
Bubble charts encode a third dimension as marker size: each point is [x, y, z]. sizing controls whether area or diameter represents z — always use area for honest visuals.
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: "bubble"
},
title: {
text: "Product portfolio"
},
credits: {
enabled: false
},
colors: [
"#00968c",
"#06b6d4",
"#d97706",
"#7c3aed",
"#dc2626",
"#16a34a",
"#0172ad",
"#9333ea"
],
legend: {
enabled: true
},
xAxis: {
title: {
text: "Growth %"
}
},
yAxis: {
title: {
text: "Market share %"
}
},
plotOptions: {
bubble: {
sizing: "area",
minSize: 8,
maxSize: 52
}
},
series: [
{
type: "bubble",
name: "Cloud suite",
data: [
[
14,
38,
420
]
]
},
{
type: "bubble",
name: "Mobile app",
data: [
[
26,
22,
180
]
]
},
{
type: "bubble",
name: "Desktop",
data: [
[
-4,
31,
260
]
]
},
{
type: "bubble",
name: "Plugins",
data: [
[
8,
12,
60
]
]
},
{
type: "bubble",
name: "Consulting",
data: [
[
2,
8,
90
]
]
}
]
});
// render inside any mates template — give the wrapper a height:
export const MyChart = () =>
html`<div style="height: 22rem">${Chart(chart)}</div>`;
Live examples
Growth vs share, bubble size = revenue. sizing = "area" keeps visual area proportional to the value.
import { html } from "mates";
import { Chart, chartAtom } from "mates-charts";
const chart = chartAtom({
chart: {
type: "bubble"
},
title: {
text: "Product portfolio"
},
credits: {
enabled: false
},
colors: [
"#00968c",
"#06b6d4",
"#d97706",
"#7c3aed",
"#dc2626",
"#16a34a",
"#0172ad",
"#9333ea"
],
legend: {
enabled: true
},
xAxis: {
title: {
text: "Growth %"
}
},
yAxis: {
title: {
text: "Market share %"
}
},
plotOptions: {
bubble: {
sizing: "area",
minSize: 8,
maxSize: 52
}
},
series: [
{
type: "bubble",
name: "Cloud suite",
data: [
[
14,
38,
420
]
]
},
{
type: "bubble",
name: "Mobile app",
data: [
[
26,
22,
180
]
]
},
{
type: "bubble",
name: "Desktop",
data: [
[
-4,
31,
260
]
]
},
{
type: "bubble",
name: "Plugins",
data: [
[
8,
12,
60
]
]
},
{
type: "bubble",
name: "Consulting",
data: [
[
2,
8,
90
]
]
}
]
});
// render inside any mates template — give the wrapper a height:
export const MyChart = () =>
html`<div style="height: 22rem">${Chart(chart)}</div>`;
displayNegative and zThreshold let single-series bubbles colour by value — no separate series needed.
import { html } from "mates";
import { Chart, chartAtom } from "mates-charts";
const chart = chartAtom({
chart: {
type: "bubble"
},
title: {
text: "City populations (millions)"
},
credits: {
enabled: false
},
colors: [
"#00968c",
"#06b6d4",
"#d97706",
"#7c3aed",
"#dc2626",
"#16a34a",
"#0172ad",
"#9333ea"
],
legend: {
enabled: false
},
xAxis: {
title: {
text: "Longitude index"
}
},
yAxis: {
title: {
text: "Latitude index"
}
},
plotOptions: {
bubble: {
sizing: "area",
minSize: 6,
maxSize: 60,
displayNegative: false,
zThreshold: 0
}
},
series: [
{
type: "bubble",
name: "Cities",
data: [
{
x: 1,
y: 5,
z: 37,
name: "Tokyo"
},
{
x: 2,
y: 7,
z: 26,
name: "Delhi"
},
{
x: 3,
y: 4,
z: 22,
name: "Shanghai"
},
{
x: 4,
y: 8,
z: 19,
name: "São Paulo"
},
{
x: 5,
y: 3,
z: 16,
name: "Cairo"
},
{
x: 6,
y: 6,
z: 9,
name: "London"
}
],
dataLabels: {
enabled: true,
format: "{point.name}",
style: {
fontSize: "0.65rem"
}
}
}
]
});
// render inside any mates template — give the wrapper a height:
export const MyChart = () =>
html`<div style="height: 22rem">${Chart(chart)}</div>`;
plotBands turn a bubble chart into a 2×2 prioritisation matrix — the classic product portfolio view.
import { html } from "mates";
import { Chart, chartAtom } from "mates-charts";
const chart = chartAtom({
chart: {
type: "bubble"
},
title: {
text: "Feature prioritisation"
},
credits: {
enabled: false
},
colors: [
"#00968c",
"#06b6d4",
"#d97706",
"#7c3aed",
"#dc2626",
"#16a34a",
"#0172ad",
"#9333ea"
],
legend: {
enabled: false
},
xAxis: {
title: {
text: "User value →"
},
min: 0,
max: 10
},
yAxis: {
title: {
text: "Effort →"
},
min: 0,
max: 10
},
plotOptions: {
bubble: {
sizing: "area",
minSize: 10,
maxSize: 46
}
},
series: [
{
type: "bubble",
name: "Features",
data: [
{
x: 8,
y: 2,
z: 90,
name: "SSO"
},
{
x: 6,
y: 3,
z: 60,
name: "Exports"
},
{
x: 3,
y: 7,
z: 40,
name: "AI labels"
},
{
x: 7,
y: 8,
z: 70,
name: "Plugins"
},
{
x: 2,
y: 4,
z: 20,
name: "Themes"
}
],
dataLabels: {
enabled: true,
format: "{point.name}"
}
}
]
});
// 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 bubble charts. See the full Highcharts API for everything else.
| Option | Type | Default | Description |
|---|---|---|---|
chart.type |
"bubble" | — | Scatter variant with size as the third dimension. |
series[].data |
[x, y, z][] | — | z drives bubble size. |
plotOptions.bubble.sizing |
"area" | "width" | "area" | Use area for honest proportionality. |
plotOptions.bubble.minSize / maxSize |
number | string | 8 / 20% | Bubble size bounds (px or % of plot area). |
plotOptions.bubble.displayNegative |
boolean | false | Render bubbles below zThreshold. |
series[].dataLabels |
DataLabelsOptions | — | Name bubbles — {point.name} in the format. |