How the EU grew: the inner ring is each enlargement, from the founding members in 1957 to 2007, and the outer ring the countries that joined, sized by their population today.
When data has two levels, totals and the items inside them, a nested pie shows both: each inner slice is the sum of the outer slices around it. Here that is each round of EU enlargement and the countries it brought in.
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/percent-charts/pie-chart/
// start and end angle must be set both for chart and series
var chart = root.container.children.push(am5percent.PieChart.new(root, {
layout: root.verticalLayout,
radius: am5.percent(85), // the pie takes 85% of the space it has
// start at three o'clock, so the many small slices of the later years end up on the right, where their labels have room
startAngle: 0,
endAngle: 360 // a full circle
}));
// Create series
// https://www.amcharts.com/docs/v5/charts/percent-charts/pie-chart/#Series
// start and end angle must be set both for chart and series
var series0 = chart.series.push(am5percent.PieSeries.new(root, {
valueField: "population",
categoryField: "year",
alignLabels: false, // each year stays inside its slice
startAngle: 0,
endAngle: 360,
radius: am5.percent(80), // the inner pie, from 25% to 80% of the radius...
innerRadius: am5.percent(25) // ...with a hole in the middle
}));
// the theme's background color, for the gaps between slices
var bgColor = root.interfaceColors.get("background");
series0.ticks.template.setAll({ forceHidden: true }); // no ticks: the years sit inside their slices
// years inside their slices, along the radius, ending 10px in from the outer edge
series0.labels.template.setAll({
radius: -10,
text: "{category}",
textType: "radial",
centerX: am5.percent(100)
});
// each year takes the next color of the theme
series0.slices.template.setAll({
stroke: bgColor, // 2px gaps in the background color
strokeWidth: 2,
tooltipText: "Joined in {category}: {value.formatNumber('#.0a')} people today"
});
// a hovered year shrinks a little instead of growing into the outer ring
series0.slices.template.states.create("hover", { scale: 0.95 });
var series1 = chart.series.push(am5percent.PieSeries.new(root, {
valueField: "population",
categoryField: "country",
alignLabels: true, // the country names line up in columns at the sides
startAngle: 0,
endAngle: 360,
innerRadius: am5.percent(80), // the outer ring, from 80% out to the full radius
radius: am5.percent(100)
}));
series1.slices.template.setAll({
stroke: bgColor,
strokeWidth: 2,
templateField: "settings" // each country takes its fill from the data: its year's color, set below
});
series1.labels.template.setAll({
text: "{category}" // just the country's name, no percent
});
series1.slices.template.set("tooltipText", "{category}: {value.formatNumber('#.0a')} people");
var data = {
"1957": [
{ country: "Belgium", population: 11589623 },
{ country: "France", population: 67413000 },
{ country: "Germany", population: 83190556 },
{ country: "Italy", population: 60359546 },
{ country: "Luxembourg", population: 626108 },
{ country: "Netherlands", population: 17479000 }
],
"1973": [
{ country: "Denmark", population: 5806081 },
{ country: "Ireland", population: 4948200 },
{ country: "United Kingdom", population: 66647112 }
],
"1981": [
{ country: "Greece", population: 10724599 }
],
"1986": [
{ country: "Portugal", population: 10196707 },
{ country: "Spain", population: 46722980 }
],
"1995": [
{ country: "Austria", population: 8902600 },
{ country: "Finland", population: 5523231 },
{ country: "Sweden", population: 10379295 }
],
"2004": [
{ country: "Cyprus", population: 1207359 },
{ country: "Czech Republic", population: 10708981 },
{ country: "Estonia", population: 1328976 },
{ country: "Hungary", population: 9771000 },
{ country: "Latvia", population: 1901548 },
{ country: "Lithuania", population: 2790844 },
{ country: "Malta", population: 514564 },
{ country: "Poland", population: 37846755 },
{ country: "Slovakia", population: 5459642 },
{ country: "Slovenia", population: 2073894 }
],
"2007": [
{ country: "Bulgaria", population: 6971487 },
{ country: "Romania", population: 19286123 }
]
};
// Generate series data
var innerData = [];
var outerData = [];
var yearIndex = 0;
am5.object.each(data, function(year, countries) {
// the year's color, as the inner ring gets it from the theme, a little lighter for its countries
var countryColor = am5.Color.lighten(series0.get("colors").getIndex(yearIndex++), 0.3);
var population = 0;
am5.array.each(countries, function(country) {
population += country.population;
country.settings = { fill: countryColor };
outerData.push(country);
});
innerData.push({
year: year,
population: population
});
});
// Set data
// https://www.amcharts.com/docs/v5/charts/percent-charts/pie-chart/#Setting_data
series0.data.setAll(innerData);
series1.data.setAll(outerData);
// Play initial series animation
// https://www.amcharts.com/docs/v5/concepts/animations/#Animation_of_series
series0.appear(1000, 100);
series1.appear(1000, 100);
{
"type": "PieChart",
"settings": {
"layout": {
"type": "VerticalLayout"
},
"radius": {
"type": "Percent",
"value": 85
},
"startAngle": 0,
"endAngle": 360
},
"properties": {
"series": [
"#series-0",
"#series-1"
]
},
"refs": [
{
"data-0": [
{
"year": "1957",
"population": 240657833
},
{
"year": "1973",
"population": 77401393
},
{
"year": "1981",
"population": 10724599
},
{
"year": "1986",
"population": 56919687
},
{
"year": "1995",
"population": 24805126
},
{
"year": "2004",
"population": 73603563
},
{
"year": "2007",
"population": 26257610
}
]
},
{
"data-1": [
{
"country": "Belgium",
"population": 11589623,
"settings": {
"fill": {
"type": "Color",
"value": "#95cde7"
},
"__parse": true
},
"__parse": true
},
{
"country": "France",
"population": 67413000,
"settings": {
"fill": {
"type": "Color",
"value": "#95cde7"
},
"__parse": true
},
"__parse": true
},
{
"country": "Germany",
"population": 83190556,
"settings": {
"fill": {
"type": "Color",
"value": "#95cde7"
},
"__parse": true
},
"__parse": true
},
{
"country": "Italy",
"population": 60359546,
"settings": {
"fill": {
"type": "Color",
"value": "#95cde7"
},
"__parse": true
},
"__parse": true
},
{
"country": "Luxembourg",
"population": 626108,
"settings": {
"fill": {
"type": "Color",
"value": "#95cde7"
},
"__parse": true
},
"__parse": true
},
{
"country": "Netherlands",
"population": 17479000,
"settings": {
"fill": {
"type": "Color",
"value": "#95cde7"
},
"__parse": true
},
"__parse": true
},
{
"country": "Denmark",
"population": 5806081,
"settings": {
"fill": {
"type": "Color",
"value": "#95b4e7"
},
"__parse": true
},
"__parse": true
},
{
"country": "Ireland",
"population": 4948200,
"settings": {
"fill": {
"type": "Color",
"value": "#95b4e7"
},
"__parse": true
},
"__parse": true
},
{
"country": "United Kingdom",
"population": 66647112,
"settings": {
"fill": {
"type": "Color",
"value": "#95b4e7"
},
"__parse": true
},
"__parse": true
},
{
"country": "Greece",
"population": 10724599,
"settings": {
"fill": {
"type": "Color",
"value": "#959ce7"
},
"__parse": true
},
"__parse": true
},
{
"country": "Portugal",
"population": 10196707,
"settings": {
"fill": {
"type": "Color",
"value": "#a695e7"
},
"__parse": true
},
"__parse": true
},
{
"country": "Spain",
"population": 46722980,
"settings": {
"fill": {
"type": "Color",
"value": "#a695e7"
},
"__parse": true
},
"__parse": true
},
{
"country": "Austria",
"population": 8902600,
"settings": {
"fill": {
"type": "Color",
"value": "#bf95e7"
},
"__parse": true
},
"__parse": true
},
{
"country": "Finland",
"population": 5523231,
"settings": {
"fill": {
"type": "Color",
"value": "#bf95e7"
},
"__parse": true
},
"__parse": true
},
{
"country": "Sweden",
"population": 10379295,
"settings": {
"fill": {
"type": "Color",
"value": "#bf95e7"
},
"__parse": true
},
"__parse": true
},
{
"country": "Cyprus",
"population": 1207359,
"settings": {
"fill": {
"type": "Color",
"value": "#d895e7"
},
"__parse": true
},
"__parse": true
},
{
"country": "Czech Republic",
"population": 10708981,
"settings": {
"fill": {
"type": "Color",
"value": "#d895e7"
},
"__parse": true
},
"__parse": true
},
{
"country": "Estonia",
"population": 1328976,
"settings": {
"fill": {
"type": "Color",
"value": "#d895e7"
},
"__parse": true
},
"__parse": true
},
{
"country": "Hungary",
"population": 9771000,
"settings": {
"fill": {
"type": "Color",
"value": "#d895e7"
},
"__parse": true
},
"__parse": true
},
{
"country": "Latvia",
"population": 1901548,
"settings": {
"fill": {
"type": "Color",
"value": "#d895e7"
},
"__parse": true
},
"__parse": true
},
{
"country": "Lithuania",
"population": 2790844,
"settings": {
"fill": {
"type": "Color",
"value": "#d895e7"
},
"__parse": true
},
"__parse": true
},
{
"country": "Malta",
"population": 514564,
"settings": {
"fill": {
"type": "Color",
"value": "#d895e7"
},
"__parse": true
},
"__parse": true
},
{
"country": "Poland",
"population": 37846755,
"settings": {
"fill": {
"type": "Color",
"value": "#d895e7"
},
"__parse": true
},
"__parse": true
},
{
"country": "Slovakia",
"population": 5459642,
"settings": {
"fill": {
"type": "Color",
"value": "#d895e7"
},
"__parse": true
},
"__parse": true
},
{
"country": "Slovenia",
"population": 2073894,
"settings": {
"fill": {
"type": "Color",
"value": "#d895e7"
},
"__parse": true
},
"__parse": true
},
{
"country": "Bulgaria",
"population": 6971487,
"settings": {
"fill": {
"type": "Color",
"value": "#e795dd"
},
"__parse": true
},
"__parse": true
},
{
"country": "Romania",
"population": 19286123,
"settings": {
"fill": {
"type": "Color",
"value": "#e795dd"
},
"__parse": true
},
"__parse": true
}
]
},
{
"series-0": {
"type": "PieSeries",
"settings": {
"valueField": "population",
"categoryField": "year",
"alignLabels": false,
"startAngle": 0,
"endAngle": 360,
"radius": {
"type": "Percent",
"value": 80
},
"innerRadius": {
"type": "Percent",
"value": 25
}
},
"properties": {
"data": "#data-0",
"slices": {
"properties": {
"template": {
"settings": {
"stroke": "@root.interfaceColors.get('background')",
"strokeWidth": 2,
"tooltipText": "Joined in {category}: {value.formatNumber('#.0a')} people today"
},
"states": [
{
"key": "hover",
"settings": {
"scale": 0.95
}
}
]
}
}
},
"labels": {
"properties": {
"template": {
"settings": {
"radius": -10,
"text": "{category}",
"textType": "radial",
"centerX": {
"type": "Percent",
"value": 100
}
}
}
}
},
"ticks": {
"properties": {
"template": {
"settings": {
"forceHidden": true
}
}
}
}
}
}
},
{
"series-1": {
"type": "PieSeries",
"settings": {
"valueField": "population",
"categoryField": "country",
"alignLabels": true,
"startAngle": 0,
"endAngle": 360,
"innerRadius": {
"type": "Percent",
"value": 80
},
"radius": {
"type": "Percent",
"value": 100
}
},
"properties": {
"data": "#data-1",
"slices": {
"properties": {
"template": {
"settings": {
"stroke": "@root.interfaceColors.get('background')",
"strokeWidth": 2,
"templateField": "settings",
"tooltipText": "{category}: {value.formatNumber('#.0a')} people"
}
}
}
},
"labels": {
"properties": {
"template": {
"settings": {
"text": "{category}"
}
}
}
}
}
}
}
]
}