A thin ring of parts inside a wider, see-through band that groups some of them together. Here the band shows that First and Second belong together.
Sometimes the parts belong to bigger groups: products to product lines, costs to departments. A second ring shows both at once, the detail in the middle and the grouping around it, without a second chart.
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/
var chart = root.container.children.push(
am5percent.PieChart.new(root, {
layout: root.verticalLayout
})
);
// Create series
// https://www.amcharts.com/docs/v5/charts/percent-charts/pie-chart/#Series
// two pie series in one chart: a faint outer ring for the group, a thinner one for its parts
var series0 = chart.series.push(
am5percent.PieSeries.new(root, {
valueField: "value",
categoryField: "category",
alignLabels: false, // each label stays by its slice, not lined up in columns
radius: am5.percent(100), // the ring fills the chart's whole radius...
innerRadius: am5.percent(80) // ...from 80% of it outward
})
);
// hidden, the ring shrinks to a point at the left (180 degrees)
series0.states.create("hidden", {
startAngle: 180,
endAngle: 180
});
series0.slices.template.setAll({
fillOpacity: 0.5, // a faint ring
strokeOpacity: 0, // no outline
templateField: "settings" // the Unused slice takes its forceHidden from the data
});
// slices neither grow on hover nor pull out when clicked
series0.slices.template.states.create("hover", { scale: 1 });
series0.slices.template.states.create("active", { shiftRadius:0 });
series0.labels.template.setAll({
templateField: "settings" // so its label hides too...
});
series0.ticks.template.setAll({
templateField: "settings" // ...and its tick
});
series0.labels.template.setAll({
textType: "circular", // names curve along the ring
radius: 30 // 30px out from the ring
});
// Set data
// https://www.amcharts.com/docs/v5/charts/percent-charts/pie-chart/#Setting_data
series0.data.setAll([
{
category: "First + Second",
value: 60
},
{
category: "Unused",
value: 30,
// takes its share of the ring, but its slice, label and tick are hidden
settings: { forceHidden: true }
}
]);
// Create series
// https://www.amcharts.com/docs/v5/charts/percent-charts/pie-chart/#Series
var series1 = chart.series.push(
am5percent.PieSeries.new(root, {
// a thinner ring in the middle of the faint ring's band, which runs from 80% to 100%
radius: am5.percent(95),
innerRadius: am5.percent(85),
valueField: "value",
categoryField: "category",
alignLabels: false // each label stays by its slice
})
);
series1.states.create("hidden", {
startAngle: 180,
endAngle: 180
});
series1.slices.template.setAll({
templateField: "sliceSettings", // the Remaining slice takes its gray from the data
strokeOpacity: 0 // no outline
});
series1.labels.template.setAll({
textType: "circular" // names curve along the ring
});
// a negative radius puts each name inside its slice, about halfway between the ring's edges
series1.labels.template.adapters.add("radius", function (radius, target) {
var dataItem = target.dataItem;
var slice = dataItem.get("slice");
return -(slice.get("radius") - slice.get("innerRadius")) / 2 - 10;
});
// as on the outer ring: no growing on hover, no pulling out on click
series1.slices.template.states.create("hover", { scale: 1 });
series1.slices.template.states.create("active", { shiftRadius:0 });
series1.ticks.template.setAll({
forceHidden: true // no ticks: the names sit inside their slices
});
// Set data
// https://www.amcharts.com/docs/v5/charts/percent-charts/pie-chart/#Setting_data
series1.data.setAll([{
category: "First",
value: 30
}, {
category: "Second",
value: 30
}, {
category: "Remaining",
value: 30,
// a gray from the theme, 15% of the way from the background to its contrast color: light in light mode,
// dark in dark mode, so the name on it stays readable
sliceSettings: { fill: am5.Color.interpolate(0.15, root.interfaceColors.get("background"), root.interfaceColors.get("alternativeBackground")) }
}]);
{
"type": "PieChart",
"settings": {
"layout": {
"type": "VerticalLayout"
}
},
"properties": {
"series": [
"#series-0",
"#series-1"
]
},
"refs": [
{
"data-0": [
{
"category": "First + Second",
"value": 60
},
{
"category": "Unused",
"value": 30,
"settings": {
"forceHidden": true
},
"__parse": true
}
]
},
{
"data-1": [
{
"category": "First",
"value": 30
},
{
"category": "Second",
"value": 30
},
{
"category": "Remaining",
"value": 30,
"sliceSettings": {
"fill": {
"type": "Color",
"value": "#d8d8d8"
},
"__parse": true
},
"__parse": true
}
]
},
{
"series-0": {
"type": "PieSeries",
"settings": {
"valueField": "value",
"categoryField": "category",
"alignLabels": false,
"radius": {
"type": "Percent",
"value": 100
},
"innerRadius": {
"type": "Percent",
"value": 80
}
},
"states": [
{
"key": "hidden",
"settings": {
"endAngle": 180,
"startAngle": 180
}
}
],
"properties": {
"data": "#data-0",
"slices": {
"properties": {
"template": {
"settings": {
"fillOpacity": 0.5,
"strokeOpacity": 0,
"templateField": "settings"
},
"states": [
{
"key": "hover",
"settings": {
"scale": 1
}
},
{
"key": "active",
"settings": {
"shiftRadius": 0
}
}
]
}
}
},
"labels": {
"properties": {
"template": {
"settings": {
"templateField": "settings",
"textType": "circular",
"radius": 30
}
}
}
},
"ticks": {
"properties": {
"template": {
"settings": {
"templateField": "settings"
}
}
}
}
}
}
},
{
"series-1": {
"type": "PieSeries",
"settings": {
"radius": {
"type": "Percent",
"value": 95
},
"innerRadius": {
"type": "Percent",
"value": 85
},
"valueField": "value",
"categoryField": "category",
"alignLabels": false
},
"states": [
{
"key": "hidden",
"settings": {
"endAngle": 180,
"startAngle": 180
}
}
],
"properties": {
"data": "#data-1",
"slices": {
"properties": {
"template": {
"settings": {
"templateField": "sliceSettings",
"strokeOpacity": 0
},
"states": [
{
"key": "hover",
"settings": {
"scale": 1
}
},
{
"key": "active",
"settings": {
"shiftRadius": 0
}
}
]
}
}
},
"labels": {
"properties": {
"template": {
"settings": {
"textType": "circular"
}
}
}
},
"ticks": {
"properties": {
"template": {
"settings": {
"forceHidden": true
}
}
}
}
}
}
}
]
}