A clustered column chart puts the series side by side in each category, so you compare them group by group. Here, six regions over three years, each column labeled with its value.
Clustering keeps every column on the same baseline, so each value can be read and compared exactly: across regions within a year, or for one region across years. It gets crowded fast: with six series and three years, this chart is near the limit.
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, // the plot doesn't pan when dragged
panY: false,
paddingLeft: 0, // the value labels sit at the chart's left edge
wheelX: "panX", // a horizontal wheel or trackpad swipe pans the years
wheelY: "zoomX", // the vertical wheel zooms in on them
layout: root.verticalLayout // the plot on top, the legend under it
}));
// 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
})
);
// no cursor, so no values for the legend: without the empty value labels its items stay compact
legend.valueLabels.template.set("forceHidden", true);
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, {
// the gap between year groups: each group takes the middle 80% of its category
cellStartLocation: 0.1,
cellEndLocation: 0.9,
minorGridEnabled: true // a grid line for every year, even one whose label is skipped
})
var xAxis = chart.xAxes.push(am5xy.CategoryAxis.new(root, {
categoryField: "year",
renderer: xRenderer
}));
xRenderer.grid.template.setAll({
// draw each grid line at the end of its year's cell instead of at its start
location: 1
})
xAxis.data.setAll(data);
var yAxis = chart.yAxes.push(am5xy.ValueAxis.new(root, {
renderer: am5xy.AxisRendererY.new(root, {
strokeOpacity: 0.1 // a faint axis line
})
}));
// Add series
// https://www.amcharts.com/docs/v5/charts/xy-chart/series/
// Where the value labels sit on the columns: 0 at the bottom, 0.5 in the middle, 1 at the top
var labelLocation = 1;
// All value labels share one template, so a change to it reaches every label at once
var labelTemplate = am5.Template.new({
text: "{valueY}", // the column's value
// above the column, in the color of text on the background
fill: root.interfaceColors.get("alternativeBackground"),
centerY: am5.p100, // the label's bottom on the bullet point...
centerX: am5.p50, // ...centered over the column
populateText: true // fill in {valueY} from the data item
});
function makeSeries(name, fieldName) {
var series = chart.series.push(am5xy.ColumnSeries.new(root, {
name: name,
xAxis: xAxis,
yAxis: yAxis,
valueYField: fieldName,
categoryXField: "year",
// labels moved to the top of a column may stand above the plot, so they are not cut off at its edge
maskBullets: false
}));
series.columns.template.setAll({
tooltipText: "{name}, {categoryX}: {valueY}", // region, year and value
width: am5.percent(90), // each column takes 90% of its slot, leaving thin gaps
tooltipY: 0, // the tooltip points at the top of the column
strokeOpacity: 0 // no outline
});
series.data.setAll(data);
// Make stuff animate on load
// https://www.amcharts.com/docs/v5/concepts/animations/
series.appear();
series.bullets.push(function () {
return am5.Bullet.new(root, {
locationY: labelLocation, // where on the column, from labelLocation above
sprite: am5.Label.new(root, {}, labelTemplate) // the shared settings
});
});
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,
"wheelX": "panX",
"wheelY": "zoomX",
"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
}
]
},
{
"template-0": {
"type": "Template",
"settings": {
"text": "{valueY}",
"fill": "@root.interfaceColors.get('alternativeBackground')",
"centerY": {
"type": "Percent",
"value": 100
},
"centerX": {
"type": "Percent",
"value": 50
},
"populateText": true
}
}
},
{
"template-1": {
"type": "Template",
"settings": {
"text": "{valueY}",
"fill": "@root.interfaceColors.get('alternativeBackground')",
"centerY": {
"type": "Percent",
"value": 100
},
"centerX": {
"type": "Percent",
"value": 50
},
"populateText": true
}
}
},
{
"template-2": {
"type": "Template",
"settings": {
"text": "{valueY}",
"fill": "@root.interfaceColors.get('alternativeBackground')",
"centerY": {
"type": "Percent",
"value": 100
},
"centerX": {
"type": "Percent",
"value": 50
},
"populateText": true
}
}
},
{
"template-3": {
"type": "Template",
"settings": {
"text": "{valueY}",
"fill": "@root.interfaceColors.get('alternativeBackground')",
"centerY": {
"type": "Percent",
"value": 100
},
"centerX": {
"type": "Percent",
"value": 50
},
"populateText": true
}
}
},
{
"template-4": {
"type": "Template",
"settings": {
"text": "{valueY}",
"fill": "@root.interfaceColors.get('alternativeBackground')",
"centerY": {
"type": "Percent",
"value": 100
},
"centerX": {
"type": "Percent",
"value": 50
},
"populateText": true
}
}
},
{
"template-5": {
"type": "Template",
"settings": {
"text": "{valueY}",
"fill": "@root.interfaceColors.get('alternativeBackground')",
"centerY": {
"type": "Percent",
"value": 100
},
"centerX": {
"type": "Percent",
"value": 50
},
"populateText": true
}
}
},
{
"axis-0": {
"type": "CategoryAxis",
"settings": {
"categoryField": "year",
"renderer": {
"type": "AxisRendererX",
"settings": {
"cellStartLocation": 0.1,
"cellEndLocation": 0.9,
"minorGridEnabled": true
},
"properties": {
"grid": {
"properties": {
"template": {
"settings": {
"location": 1
}
}
}
}
}
}
},
"properties": {
"data": "#data-0"
}
}
},
{
"axis-1": {
"type": "ValueAxis",
"settings": {
"renderer": {
"type": "AxisRendererY",
"settings": {
"strokeOpacity": 0.1
}
}
}
}
},
{
"series-0": {
"type": "ColumnSeries",
"settings": {
"name": "Europe",
"xAxis": "#axis-0",
"yAxis": "#axis-1",
"valueYField": "europe",
"categoryXField": "year",
"maskBullets": false
},
"properties": {
"data": "#data-0",
"columns": {
"properties": {
"template": {
"settings": {
"tooltipText": "{name}, {categoryX}: {valueY}",
"width": {
"type": "Percent",
"value": 90
},
"tooltipY": 0,
"strokeOpacity": 0
}
}
}
},
"bullets": [
{
"type": "Bullet",
"settings": {
"locationY": 1,
"sprite": {
"type": "Label",
"properties": {
"template": "#template-0"
}
}
}
}
]
}
}
},
{
"series-1": {
"type": "ColumnSeries",
"settings": {
"name": "North America",
"xAxis": "#axis-0",
"yAxis": "#axis-1",
"valueYField": "namerica",
"categoryXField": "year",
"maskBullets": false
},
"properties": {
"data": "#data-0",
"columns": {
"properties": {
"template": {
"settings": {
"tooltipText": "{name}, {categoryX}: {valueY}",
"width": {
"type": "Percent",
"value": 90
},
"tooltipY": 0,
"strokeOpacity": 0
}
}
}
},
"bullets": [
{
"type": "Bullet",
"settings": {
"locationY": 1,
"sprite": {
"type": "Label",
"properties": {
"template": "#template-1"
}
}
}
}
]
}
}
},
{
"series-2": {
"type": "ColumnSeries",
"settings": {
"name": "Asia",
"xAxis": "#axis-0",
"yAxis": "#axis-1",
"valueYField": "asia",
"categoryXField": "year",
"maskBullets": false
},
"properties": {
"data": "#data-0",
"columns": {
"properties": {
"template": {
"settings": {
"tooltipText": "{name}, {categoryX}: {valueY}",
"width": {
"type": "Percent",
"value": 90
},
"tooltipY": 0,
"strokeOpacity": 0
}
}
}
},
"bullets": [
{
"type": "Bullet",
"settings": {
"locationY": 1,
"sprite": {
"type": "Label",
"properties": {
"template": "#template-2"
}
}
}
}
]
}
}
},
{
"series-3": {
"type": "ColumnSeries",
"settings": {
"name": "Latin America",
"xAxis": "#axis-0",
"yAxis": "#axis-1",
"valueYField": "lamerica",
"categoryXField": "year",
"maskBullets": false
},
"properties": {
"data": "#data-0",
"columns": {
"properties": {
"template": {
"settings": {
"tooltipText": "{name}, {categoryX}: {valueY}",
"width": {
"type": "Percent",
"value": 90
},
"tooltipY": 0,
"strokeOpacity": 0
}
}
}
},
"bullets": [
{
"type": "Bullet",
"settings": {
"locationY": 1,
"sprite": {
"type": "Label",
"properties": {
"template": "#template-3"
}
}
}
}
]
}
}
},
{
"series-4": {
"type": "ColumnSeries",
"settings": {
"name": "Middle East",
"xAxis": "#axis-0",
"yAxis": "#axis-1",
"valueYField": "meast",
"categoryXField": "year",
"maskBullets": false
},
"properties": {
"data": "#data-0",
"columns": {
"properties": {
"template": {
"settings": {
"tooltipText": "{name}, {categoryX}: {valueY}",
"width": {
"type": "Percent",
"value": 90
},
"tooltipY": 0,
"strokeOpacity": 0
}
}
}
},
"bullets": [
{
"type": "Bullet",
"settings": {
"locationY": 1,
"sprite": {
"type": "Label",
"properties": {
"template": "#template-4"
}
}
}
}
]
}
}
},
{
"series-5": {
"type": "ColumnSeries",
"settings": {
"name": "Africa",
"xAxis": "#axis-0",
"yAxis": "#axis-1",
"valueYField": "africa",
"categoryXField": "year",
"maskBullets": false
},
"properties": {
"data": "#data-0",
"columns": {
"properties": {
"template": {
"settings": {
"tooltipText": "{name}, {categoryX}: {valueY}",
"width": {
"type": "Percent",
"value": 90
},
"tooltipY": 0,
"strokeOpacity": 0
}
}
}
},
"bullets": [
{
"type": "Bullet",
"settings": {
"locationY": 1,
"sprite": {
"type": "Label",
"properties": {
"template": "#template-5"
}
}
}
}
]
}
}
}
]
}