A stacked column chart piles the series on top of each other, so each column shows a total and what it is made of. Here, six regions over three years, with each value written on its segment where it fits.
Stacking shows two things at once: the total of each column and the parts that make it up. The totals and the bottom segments are easy to compare across columns; the segments higher up float on different baselines, so their labels do the work.
Built with amCharts 5, a JavaScript library. The JavaScript includes your theme and renderer (canvas or SVG); the JSON also follows 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 panning
panY: false,
paddingLeft: 0, // no gap at the chart's left edge
layout: root.verticalLayout // the legend goes below the plot
}));
var data = [{
"year": "2023",
"europe": 2.5,
"namerica": 2.5,
"asia": 2.1,
"lamerica": 1,
"meast": 0.8,
"africa": 0.4
}, {
"year": "2024",
"europe": 2.6,
"namerica": 2.7,
"asia": 2.2,
"lamerica": 0.5,
"meast": 0.4,
"africa": 0.3
}, {
"year": "2025",
"europe": 2.8,
"namerica": 2.9,
"asia": 2.4,
"lamerica": 0.3,
"meast": 0.9,
"africa": 0.5
}]
// Create axes
// https://www.amcharts.com/docs/v5/charts/xy-chart/axes/
var xRenderer = am5xy.AxisRendererX.new(root, {
minorGridEnabled: true // fainter grid lines between the main ones
});
var xAxis = chart.xAxes.push(am5xy.CategoryAxis.new(root, {
categoryField: "year",
renderer: xRenderer,
tooltip: am5.Tooltip.new(root, {})
}));
xRenderer.grid.template.setAll({
location: 1 // grid lines between the years, not through the middle of each
})
xAxis.data.setAll(data);
var yAxis = chart.yAxes.push(am5xy.ValueAxis.new(root, {
min: 0, // columns start at zero
renderer: am5xy.AxisRendererY.new(root, {
strokeOpacity: 0.1 // a faint axis line
})
}));
// 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, // centered...
x: am5.p50 // ...under the chart
}));
// no cursor, so no values for the legend: without the empty value labels its items stay compact
legend.valueLabels.template.set("forceHidden", true);
// Add series
// https://www.amcharts.com/docs/v5/charts/xy-chart/series/
// adds one region's segments, stacked on the regions added before
function makeSeries(name, fieldName) {
var series = chart.series.push(am5xy.ColumnSeries.new(root, {
name: name,
stacked: true, // the main trick: each segment starts where the one below it ends
xAxis: xAxis,
yAxis: yAxis,
valueYField: fieldName,
categoryXField: "year"
}));
series.columns.template.setAll({
tooltipText: "{name}, {categoryX}: {valueY}", // hover a segment for its region, year and value
// the tooltip points near the top of the segment, not at its middle
tooltipY: am5.percent(10)
});
series.data.setAll(data);
// Make stuff animate on load
// https://www.amcharts.com/docs/v5/concepts/animations/
series.appear();
// the value in the middle of each segment
series.bullets.push(function () {
return am5.Bullet.new(root, {
sprite: am5.Label.new(root, {
text: "{valueY}",
fill: root.interfaceColors.get("alternativeText"), // the theme's text color for use on colored fills
centerY: am5.p50, // centered on the segment...
centerX: am5.p50, // ...both ways
populateText: true // fill in {valueY} from the data
})
});
});
// hide the label of a segment too short to hold it; its tooltip still shows the value
series.columns.template.onPrivate("height", function (height, target) {
am5.array.each(target.dataItem.bullets || [], function (bullet) {
if (height > 20) { // 20px or taller: room for the label
bullet.get("sprite").show();
} else {
bullet.get("sprite").hide();
}
});
});
legend.data.push(series);
}
makeSeries("Europe", "europe");
makeSeries("North America", "namerica");
makeSeries("Asia", "asia");
makeSeries("Latin America", "lamerica");
makeSeries("Middle East", "meast");
makeSeries("Africa", "africa");
// Make stuff animate on load
// https://www.amcharts.com/docs/v5/concepts/animations/
chart.appear(1000, 100);
{
"type": "XYChart",
"settings": {
"panX": false,
"panY": false,
"paddingLeft": 0,
"layout": {
"type": "VerticalLayout"
}
},
"properties": {
"series": [
"#series-0",
"#series-1",
"#series-2",
"#series-3",
"#series-4",
"#series-5"
],
"xAxes": [
"#axis-0"
],
"yAxes": [
"#axis-1"
]
},
"children": [
{
"type": "Legend",
"settings": {
"centerX": {
"type": "Percent",
"value": 50
},
"x": {
"type": "Percent",
"value": 50
}
},
"properties": {
"data": [
"#series-0",
"#series-1",
"#series-2",
"#series-3",
"#series-4",
"#series-5"
],
"valueLabels": {
"properties": {
"template": {
"settings": {
"forceHidden": true
}
}
}
}
}
}
],
"refs": [
{
"data-0": [
{
"year": "2023",
"europe": 2.5,
"namerica": 2.5,
"asia": 2.1,
"lamerica": 1,
"meast": 0.8,
"africa": 0.4
},
{
"year": "2024",
"europe": 2.6,
"namerica": 2.7,
"asia": 2.2,
"lamerica": 0.5,
"meast": 0.4,
"africa": 0.3
},
{
"year": "2025",
"europe": 2.8,
"namerica": 2.9,
"asia": 2.4,
"lamerica": 0.3,
"meast": 0.9,
"africa": 0.5
}
]
},
{
"axis-0": {
"type": "CategoryAxis",
"settings": {
"categoryField": "year",
"renderer": {
"type": "AxisRendererX",
"settings": {
"minorGridEnabled": true
},
"properties": {
"grid": {
"properties": {
"template": {
"settings": {
"location": 1
}
}
}
}
}
},
"tooltip": {
"type": "Tooltip"
}
},
"properties": {
"data": "#data-0"
}
}
},
{
"axis-1": {
"type": "ValueAxis",
"settings": {
"min": 0,
"renderer": {
"type": "AxisRendererY",
"settings": {
"strokeOpacity": 0.1
}
}
}
}
},
{
"series-0": {
"type": "ColumnSeries",
"settings": {
"name": "Europe",
"stacked": true,
"xAxis": "#axis-0",
"yAxis": "#axis-1",
"valueYField": "europe",
"categoryXField": "year"
},
"properties": {
"data": "#data-0",
"columns": {
"properties": {
"template": {
"settings": {
"tooltipText": "{name}, {categoryX}: {valueY}",
"tooltipY": {
"type": "Percent",
"value": 10
}
}
}
}
},
"bullets": [
{
"type": "Bullet",
"settings": {
"sprite": {
"type": "Label",
"settings": {
"text": "{valueY}",
"fill": "@root.interfaceColors.get('alternativeText')",
"centerY": {
"type": "Percent",
"value": 50
},
"centerX": {
"type": "Percent",
"value": 50
},
"populateText": true
}
}
}
}
]
}
}
},
{
"series-1": {
"type": "ColumnSeries",
"settings": {
"name": "North America",
"stacked": true,
"xAxis": "#axis-0",
"yAxis": "#axis-1",
"valueYField": "namerica",
"categoryXField": "year"
},
"properties": {
"data": "#data-0",
"columns": {
"properties": {
"template": {
"settings": {
"tooltipText": "{name}, {categoryX}: {valueY}",
"tooltipY": {
"type": "Percent",
"value": 10
}
}
}
}
},
"bullets": [
{
"type": "Bullet",
"settings": {
"sprite": {
"type": "Label",
"settings": {
"text": "{valueY}",
"fill": "@root.interfaceColors.get('alternativeText')",
"centerY": {
"type": "Percent",
"value": 50
},
"centerX": {
"type": "Percent",
"value": 50
},
"populateText": true
}
}
}
}
]
}
}
},
{
"series-2": {
"type": "ColumnSeries",
"settings": {
"name": "Asia",
"stacked": true,
"xAxis": "#axis-0",
"yAxis": "#axis-1",
"valueYField": "asia",
"categoryXField": "year"
},
"properties": {
"data": "#data-0",
"columns": {
"properties": {
"template": {
"settings": {
"tooltipText": "{name}, {categoryX}: {valueY}",
"tooltipY": {
"type": "Percent",
"value": 10
}
}
}
}
},
"bullets": [
{
"type": "Bullet",
"settings": {
"sprite": {
"type": "Label",
"settings": {
"text": "{valueY}",
"fill": "@root.interfaceColors.get('alternativeText')",
"centerY": {
"type": "Percent",
"value": 50
},
"centerX": {
"type": "Percent",
"value": 50
},
"populateText": true
}
}
}
}
]
}
}
},
{
"series-3": {
"type": "ColumnSeries",
"settings": {
"name": "Latin America",
"stacked": true,
"xAxis": "#axis-0",
"yAxis": "#axis-1",
"valueYField": "lamerica",
"categoryXField": "year"
},
"properties": {
"data": "#data-0",
"columns": {
"properties": {
"template": {
"settings": {
"tooltipText": "{name}, {categoryX}: {valueY}",
"tooltipY": {
"type": "Percent",
"value": 10
}
}
}
}
},
"bullets": [
{
"type": "Bullet",
"settings": {
"sprite": {
"type": "Label",
"settings": {
"text": "{valueY}",
"fill": "@root.interfaceColors.get('alternativeText')",
"centerY": {
"type": "Percent",
"value": 50
},
"centerX": {
"type": "Percent",
"value": 50
},
"populateText": true
}
}
}
}
]
}
}
},
{
"series-4": {
"type": "ColumnSeries",
"settings": {
"name": "Middle East",
"stacked": true,
"xAxis": "#axis-0",
"yAxis": "#axis-1",
"valueYField": "meast",
"categoryXField": "year"
},
"properties": {
"data": "#data-0",
"columns": {
"properties": {
"template": {
"settings": {
"tooltipText": "{name}, {categoryX}: {valueY}",
"tooltipY": {
"type": "Percent",
"value": 10
}
}
}
}
},
"bullets": [
{
"type": "Bullet",
"settings": {
"sprite": {
"type": "Label",
"settings": {
"text": "{valueY}",
"fill": "@root.interfaceColors.get('alternativeText')",
"centerY": {
"type": "Percent",
"value": 50
},
"centerX": {
"type": "Percent",
"value": 50
},
"populateText": true
}
}
}
}
]
}
}
},
{
"series-5": {
"type": "ColumnSeries",
"settings": {
"name": "Africa",
"stacked": true,
"xAxis": "#axis-0",
"yAxis": "#axis-1",
"valueYField": "africa",
"categoryXField": "year"
},
"properties": {
"data": "#data-0",
"columns": {
"properties": {
"template": {
"settings": {
"tooltipText": "{name}, {categoryX}: {valueY}",
"tooltipY": {
"type": "Percent",
"value": 10
}
}
}
}
},
"bullets": [
{
"type": "Bullet",
"settings": {
"sprite": {
"type": "Label",
"settings": {
"text": "{valueY}",
"fill": "@root.interfaceColors.get('alternativeText')",
"centerY": {
"type": "Percent",
"value": 50
},
"centerX": {
"type": "Percent",
"value": 50
},
"populateText": true
}
}
}
}
]
}
}
}
]
}