A pie chart with the middle cut out. It shows how a whole splits into parts, and the hole holds the total: here, a $3,000 monthly budget.
A donut chart answers one question: how is a total divided? Each slice is a share of the whole, so it reads best with a handful of slices and one clear winner.
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, // the legend goes below the donut
innerRadius: am5.percent(55) // a hole 55% of the radius turns the pie into a donut
}));
// Create series
// https://www.amcharts.com/docs/v5/charts/percent-charts/pie-chart/#Series
var series = chart.series.push(am5percent.PieSeries.new(root, {
valueField: "value",
categoryField: "category",
alignLabels: false // labels stay on their slices, not lined up in columns at the sides
}));
// Labels follow the curve of the ring; the values are in the tooltips and the legend
series.labels.template.setAll({
textType: "circular",
text: "{category}", // just the name
centerX: 0, // no centering shift: the curved text keeps to its slice...
centerY: 0 // ...instead of moving by half its own size
});
series.slices.template.setAll({
// name, amount and share of the total, as "Food: $540 (18.0%)"
tooltipText: "{category}: ${value} ({valuePercentTotal.formatNumber('0.0')}%)"
});
// The total, in the hole
// https://www.amcharts.com/docs/v5/charts/percent-charts/pie-chart/#Label_in_the_middle
series.children.push(am5.Label.new(root, {
text: "[fontSize:13px]Monthly budget[/]\n[bold fontSize:26px]${valueSum.formatNumber('#,###')}[/]",
// fills in {valueSum} from the series the label belongs to
populateText: true,
textAlign: "center", // the two lines centered on each other
centerX: am5.percent(50), // the label's middle on the donut's center
centerY: am5.percent(50)
}));
// Set data
// https://www.amcharts.com/docs/v5/charts/percent-charts/pie-chart/#Setting_data
series.data.setAll([
{ value: 1050, category: "Housing" },
{ value: 540, category: "Food" },
{ value: 420, category: "Transport" },
{ value: 390, category: "Savings" },
{ value: 330, category: "Health" },
{ value: 270, category: "Leisure" }
]);
// Create legend
// https://www.amcharts.com/docs/v5/charts/percent-charts/legend-percent-series/
var legend = chart.children.push(am5.Legend.new(root, {
centerX: am5.percent(50), // the legend's middle...
x: am5.percent(50), // ...at the middle of the chart
marginTop: 15, // 15px of space above...
marginBottom: 15 // ...and below the legend
}));
legend.data.setAll(series.dataItems);
// Play initial series animation
// https://www.amcharts.com/docs/v5/concepts/animations/#Animation_of_series
series.appear(1000, 100);
{
"type": "PieChart",
"settings": {
"layout": {
"type": "VerticalLayout"
},
"innerRadius": {
"type": "Percent",
"value": 55
}
},
"properties": {
"series": [
"#series-0"
]
},
"children": [
{
"type": "Legend",
"settings": {
"centerX": {
"type": "Percent",
"value": 50
},
"x": {
"type": "Percent",
"value": 50
},
"marginTop": 15,
"marginBottom": 15
},
"properties": {
"data": "#series-0.dataItems"
}
}
],
"refs": [
{
"data-0": [
{
"value": 1050,
"category": "Housing"
},
{
"value": 540,
"category": "Food"
},
{
"value": 420,
"category": "Transport"
},
{
"value": 390,
"category": "Savings"
},
{
"value": 330,
"category": "Health"
},
{
"value": 270,
"category": "Leisure"
}
]
},
{
"series-0": {
"type": "PieSeries",
"settings": {
"valueField": "value",
"categoryField": "category",
"alignLabels": false
},
"properties": {
"data": "#data-0",
"slices": {
"properties": {
"template": {
"settings": {
"tooltipText": "{category}: ${value} ({valuePercentTotal.formatNumber('0.0')}%)"
}
}
}
},
"labels": {
"properties": {
"template": {
"settings": {
"textType": "circular",
"text": "{category}",
"centerX": 0,
"centerY": 0
}
}
}
}
},
"children": [
{
"type": "Label",
"settings": {
"text": "[fontSize:13px]Monthly budget[/]\n[bold fontSize:26px]${valueSum.formatNumber('#,###')}[/]",
"populateText": true,
"textAlign": "center",
"centerX": {
"type": "Percent",
"value": 50
},
"centerY": {
"type": "Percent",
"value": 50
}
}
}
]
}
}
]
}