A waffle chart displays proportions using a grid of equal-sized squares where colored squares represent parts of a whole. Each square typically represents 1% of the total, making it easy to count and compare values visually. It provides an intuitive alternative to pie charts, offering more accurate perception of proportions.

// anyplot.ai
// waffle-basic: Basic Waffle Chart
// Library: echarts 6.1.0 | JavaScript 22.23.2
// Quality: 89/100 | Created: 2026-09-09
//# anyplot-orientation: square
const t = window.ANYPLOT_TOKENS;
// --- Data (in-memory, deterministic) ----------------------------------------
// Annual engineering-org budget allocation, in whole percentage points
// (sums to 100 — each of the 100 squares below represents exactly 1%).
const categories = [
{ name: "Product Development", value: 32 },
{ name: "Marketing", value: 24 },
{ name: "Sales Operations", value: 18 },
{ name: "Customer Support", value: 14 },
{ name: "Research & Development", value: 12 },
];
// Fill a 10x10 grid top-to-bottom, left-to-right, one cell per percentage
// point, in category order — the largest category anchors the top row.
const GRID = 10;
let cursor = 0;
const series = categories.map((cat, i) => {
const points = [];
for (let n = 0; n < cat.value; n += 1) {
const col = cursor % GRID;
const row = GRID - 1 - Math.floor(cursor / GRID);
points.push([col, row]);
cursor += 1;
}
const s = {
name: `${cat.name} — ${cat.value}%`,
type: "scatter",
symbol: "rect",
symbolSize: 72,
data: points,
itemStyle: {
color: t.palette[i],
borderColor: t.pageBg,
borderWidth: 3,
},
};
// Callout on the largest category's corner square, anchored via markPoint
// so echarts positions it in data space rather than hand-computed pixels.
if (i === 0) {
s.markPoint = {
symbol: "circle",
symbolSize: 1,
itemStyle: { color: "transparent", borderColor: "transparent" },
label: {
show: true,
position: "top",
distance: 50,
color: t.ink,
fontSize: 13,
fontWeight: 600,
formatter: `Largest share — ${cat.value}%`,
},
data: [{ coord: [0, GRID - 1] }],
};
}
return s;
});
// --- Init --------------------------------------------------------------------
const chart = echarts.init(document.getElementById("container"));
// --- Option -------------------------------------------------------------------
chart.setOption({
animation: false,
backgroundColor: "transparent",
title: {
text: "waffle-basic · javascript · echarts · anyplot.ai",
left: "center",
top: 24,
textStyle: { color: t.ink, fontSize: 22, fontWeight: 500 },
},
legend: {
bottom: 16,
left: "center",
itemWidth: 16,
itemHeight: 16,
icon: "rect",
textStyle: { color: t.inkSoft, fontSize: 15 },
itemGap: 20,
},
grid: {
top: 150,
bottom: 150,
left: 150,
right: 150,
},
xAxis: {
type: "value",
min: -0.5,
max: GRID - 0.5,
interval: 1,
show: false,
},
yAxis: {
type: "value",
min: -0.5,
max: GRID - 0.5,
interval: 1,
show: false,
},
series,
});
Runnable source as JSON, for any HTTP client: https://api.anyplot.ai/specs/waffle-basic/echarts/code. Any spec id and library id listed in llms-full.txt fit the same URL shape; every URL below is complete and callable.
{
"spec_id": "waffle-basic",
"language": "javascript",
"library": "echarts",
"page": "https://anyplot.ai/waffle-basic/javascript/echarts",
"hub": "https://anyplot.ai/waffle-basic",
"code_json": "https://api.anyplot.ai/specs/waffle-basic/echarts/code",
"spec_json": "https://api.anyplot.ai/specs/waffle-basic",
"render_light_png": "https://storage.googleapis.com/anyplot-images/plots/waffle-basic/javascript/echarts/plot-light.png",
"render_dark_png": "https://storage.googleapis.com/anyplot-images/plots/waffle-basic/javascript/echarts/plot-dark.png",
"interactive_light_html": "https://storage.googleapis.com/anyplot-images/plots/waffle-basic/javascript/echarts/plot-light.html",
"interactive_dark_html": "https://storage.googleapis.com/anyplot-images/plots/waffle-basic/javascript/echarts/plot-dark.html",
"quality_score": 89.0,
"license": "MIT",
"guide": "https://anyplot.ai/llms.txt"
}Part of Basic Waffle Chart on anyplot.ai.