A Mekko chart is a stacked column chart whose columns have different widths: the width shows how big each column is, the height how it splits up. Here, five columns of different sizes, each stacked from trucks, SUVs and cars.
A Mekko chart shows two things at once: how big each group is, by its width, and what it is made of, by its stack. It suits market maps, where each column is a market, as wide as its share, and the stack shows its products.
Built with amCharts 5, a JavaScript library. The code includes your theme and renderer (canvas or SVG), but not the changes you make with the controls.
npm install @amcharts/amcharts5. See Getting started.
The same chart as a JSON config. Chart Maker reads and writes this format, the library's JSON parser turns it into a chart, and the <am5-chart> element puts it on a page with no code."type" is the class to create and "settings" what you would pass to its new() in code; "properties" fill in its parts, lists such as series and axes or templates such as columns.template; "refs" holds objects used in more than one place ("#series-0" stands for the one named series-0); a string starting with "@" takes a value from another object, such as "@series.get('fill')".
A complete page. Save it as an .html file and open it in a browser.
Paste this into an AI coding assistant to build the chart from scratch. More in amCharts & AI.
// Create root element
// https://www.amcharts.com/docs/v5/getting-started/#Root_element
var root = am5.Root.new("chartdiv");
// Set themes
// https://www.amcharts.com/docs/v5/concepts/themes/
root.setThemes([
am5themes_Animated.new(root),
am5themes_Responsive.new(root)
]);
// Create chart
// https://www.amcharts.com/docs/v5/charts/xy-chart/
var chart = root.container.children.push(am5xy.XYChart.new(root, {
panX: false, // no dragging to pan...
panY: false, // ...in either direction
layout: root.verticalLayout // the plot and the legend stacked top to bottom
}));
// Add legend
// https://www.amcharts.com/docs/v5/charts/xy-chart/legend-xy-series/
var legend = chart.children.push(
am5.Legend.new(root, {
centerX: am5.p50, // the legend's middle...
x: am5.p50 // ...at the middle of the chart's width
})
);
// no cursor, so no values for the legend: without the empty value labels its items stay compact
legend.valueLabels.template.set("forceHidden", true);
// Create axes
// https://www.amcharts.com/docs/v5/charts/xy-chart/axes/
// The horizontal axis runs from 0 to 100: each column's width is its share of the whole
var xAxis = chart.xAxes.push(am5xy.ValueAxis.new(root, {
min: 0,
max: 100,
renderer: am5xy.AxisRendererX.new(root, {})
}));
var yAxis = chart.yAxes.push(am5xy.ValueAxis.new(root, {
min: 0, // the stacks start at zero
renderer: am5xy.AxisRendererY.new(root, {})
}));
// Add series
// https://www.amcharts.com/docs/v5/charts/xy-chart/series/
// Each segment is a stacked step line: every point starts a column at "ax" with
// a height of "ay", so the steps draw columns of different widths
function createSeries(name, data) {
var series = chart.series.push(am5xy.StepLineSeries.new(root, {
name: name,
xAxis: xAxis,
yAxis: yAxis,
baseAxis: xAxis, // x is the base, so the values stack upward
valueYField: "ay",
valueXField: "ax",
stacked: true // each series sits on top of the one before
}));
series.strokes.template.setAll({
strokeWidth: 3 // a 3px line along the steps
});
series.fills.template.setAll({
fillOpacity: 0.2, // a faint fill...
visible: true // ...under the steps
});
series.data.setAll(data);
// Make stuff animate on load
// https://www.amcharts.com/docs/v5/concepts/animations/
series.appear();
// A hidden column series, stacked the same way, holds a label in the middle of each block
var bulletSeries = chart.series.push(am5xy.ColumnSeries.new(root, {
name: name,
xAxis: xAxis,
yAxis: yAxis,
baseAxis: xAxis, // x is the base, as for the step line
valueYField: "ay",
valueXField: "ax",
stacked: true // stacked like the step lines, so the labels land in their blocks
}));
bulletSeries.columns.template.setAll({
forceHidden: true // the columns themselves never show
});
// one label per block: in the middle of its width, with the block's height as value
var bulletSeriesData = [];
for(var i = 1; i < data.length; i++) {
bulletSeriesData.push({
"ax": data[i].ax - (data[i].ax - data[i-1].ax) / 2, // halfway between this point and the one before
"ay": data[i-1].ay // the block's height
})
}
bulletSeries.data.setAll(bulletSeriesData);
// a value label in the middle of each block
bulletSeries.bullets.push(function () {
return am5.Bullet.new(root, {
locationX: 0.5, // in the middle of the column...
locationY: 0.5, // ...halfway up
sprite: am5.Label.new(root, {
text: "{valueY}", // the block's height...
centerY: am5.p50, // ...centered on that point...
centerX: am5.p50, // ...both ways...
populateText: true, // ...filled in from the data item
background: am5.RoundedRectangle.new(root, { // on a box in the background color
fill: root.interfaceColors.get("background")
})
})
});
});
// the labels hide and show with their series, as its legend item is clicked
series.on("visible", function(visible, series) {
if (visible) {
bulletSeries.show();
}
else {
bulletSeries.hide();
}
})
legend.data.push(series); // a legend item for the step line only
return series;
}
var series1 = createSeries(
"Trucks",
[
{ "ax": 0, "ay": 20 },
{ "ax": 30, "ay": 10 },
{ "ax": 40, "ay": 35 },
{ "ax": 55, "ay": 43 },
{ "ax": 80, "ay": 33 },
{ "ax": 100, "ay": 33 }
]
);
var series2 = createSeries(
"SUVs",
[
{ "ax": 0, "ay": 10 },
{ "ax": 30, "ay": 39 },
{ "ax": 40, "ay": 22 },
{ "ax": 55, "ay": 26 },
{ "ax": 80, "ay": 15 },
{ "ax": 100, "ay": 15 }
]
);
var series3 = createSeries(
"Cars",
[
{ "ax": 0, "ay": 25 },
{ "ax": 30, "ay": 25 },
{ "ax": 40, "ay": 22 },
{ "ax": 55, "ay": 19 },
{ "ax": 80, "ay": 30 },
{ "ax": 100, "ay": 30 }
]
);
// Make stuff animate on load
// https://www.amcharts.com/docs/v5/concepts/animations/
chart.appear(1000, 100);