A stacked bar chart bent into rings: each ring is an age group, and its bar runs around the circle, split by activity. Here, minutes a day spent on the phone.
Bent into rings, bars take less width and catch the eye, which suits dashboards and infographics. An outer ring is longer than an inner one for the same value, so put the longest bars on the outside and keep the scale in view. For careful comparisons, straight bars are easier to read.
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)
]);
// Data: minutes a day spent on the phone, by age group and activity (sample data)
// https://www.amcharts.com/docs/v5/charts/radar-chart/#Setting_data
var data = [
{ age: "65+", video: 25, social: 15, messaging: 20, games: 10, news: 35 },
{ age: "55-64", video: 35, social: 25, messaging: 25, games: 10, news: 30 },
{ age: "45-54", video: 45, social: 35, messaging: 30, games: 15, news: 25 },
{ age: "35-44", video: 60, social: 50, messaging: 35, games: 20, news: 20 },
{ age: "25-34", video: 80, social: 65, messaging: 40, games: 30, news: 15 },
{ age: "18-24", video: 95, social: 80, messaging: 45, games: 40, news: 10 }
];
// Create chart
// https://www.amcharts.com/docs/v5/charts/radar-chart/
var chart = root.container.children.push(am5radar.RadarChart.new(root, {
panX: false, // no dragging the plot around
panY: false,
wheelX: "panX", // a horizontal wheel or trackpad swipe moves a zoomed view around...
wheelY: "zoomX", // ...and the vertical wheel zooms in on part of the scale
// room around the circle for the minute labels, clear of the legend
radius: am5.percent(75),
innerRadius: am5.percent(30), // a hole in the middle, 30% of the radius
// three quarters of a circle: the empty quarter at the top left holds the age labels
startAngle: -90,
endAngle: 180,
// a vertical layout puts the legend under the chart
layout: root.verticalLayout
}));
// Every other color of the palette, so the activities stand apart
chart.get("colors").set("step", 2);
// Add cursor
// https://www.amcharts.com/docs/v5/charts/radar-chart/#Cursor
var cursor = chart.set("cursor", am5radar.RadarCursor.new(root, {
behavior: "zoomX" // drag around the circle to zoom in on part of the scale
}));
cursor.lineY.set("visible", false); // no circle through the pointer, only the line from the center
// Create axes and their renderers
// https://www.amcharts.com/docs/v5/charts/radar-chart/#Adding_axes
// The bars run along the circle: minutes a day
var xRenderer = am5radar.AxisRendererCircular.new(root, {
strokeOpacity: 0.1, // the outer circle, faint
minGridDistance: 70 // at least 70px between the minute labels
});
xRenderer.labels.template.setAll({
radius: 10, // the labels sit 10px outside the circle
maxPosition: 0.98 // no label at the very end of the scale
});
var xAxis = chart.xAxes.push(am5xy.ValueAxis.new(root, {
renderer: xRenderer,
min: 0, // the bars start at zero
// 10% of room past the longest bar
extraMax: 0.1,
numberFormat: "#' min'", // values shown as "30 min"
tooltip: am5.Tooltip.new(root, {}) // shows the value under the pointer at the edge
}));
// One ring per age group, the youngest on the outside
var yRenderer = am5radar.AxisRendererRadial.new(root, {
minGridDistance: 10 // small, so every age group keeps its label
});
// the labels end at the top line, in the empty quarter
yRenderer.labels.template.setAll({
centerX: am5.p100,
paddingRight: 8, // 8px from the line
paddingTop: 0, // no padding above or below...
paddingBottom: 0, // ...so the labels fit their rings
fontSize: 12 // small text, in pixels
});
var yAxis = chart.yAxes.push(am5xy.CategoryAxis.new(root, {
categoryField: "age",
renderer: yRenderer
}));
// Create series: one per activity, stacked along each ring
// https://www.amcharts.com/docs/v5/charts/radar-chart/#Adding_series
function createSeries(name, field) {
var series = chart.series.push(am5radar.RadarColumnSeries.new(root, {
stacked: true, // each activity starts where the one before it ends
name: name,
xAxis: xAxis,
yAxis: yAxis,
valueXField: field,
categoryYField: "age"
}));
// thin lines in the background color between the stacked pieces
series.set("stroke", root.interfaceColors.get("background"));
series.columns.template.setAll({
width: am5.p100, // each bar fills its ring's whole thickness
strokeOpacity: 1,
strokeWidth: 1,
tooltipText: "{categoryY}, {name}: {valueX} min" // the age group, the activity and its minutes
});
series.data.setAll(data);
series.appear(1000);
}
createSeries("Video", "video");
createSeries("Social", "social");
createSeries("Messaging", "messaging");
createSeries("Games", "games");
createSeries("News", "news");
// Add legend: the activities; click one to leave it out
// 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
}));
legend.data.setAll(chart.series.values);
yAxis.data.setAll(data);
// Animate chart and series in
// https://www.amcharts.com/docs/v5/concepts/animations/#Initial_animation
chart.appear(1000, 100);
{
"type": "RadarChart",
"settings": {
"panX": false,
"panY": false,
"wheelX": "panX",
"wheelY": "zoomX",
"radius": {
"type": "Percent",
"value": 75
},
"innerRadius": {
"type": "Percent",
"value": 30
},
"startAngle": -90,
"endAngle": 180,
"layout": {
"type": "VerticalLayout"
},
"cursor": {
"type": "RadarCursor",
"settings": {
"behavior": "zoomX"
},
"properties": {
"lineY": {
"settings": {
"visible": false
}
}
}
},
"colors": {
"type": "ColorSet",
"settings": {
"step": 2,
"passOptions": {
"hue": 0.05,
"saturation": 0,
"lightness": 0
},
"colors": [
{
"type": "Color",
"value": "#67b7dc"
},
{
"type": "Color",
"value": "#6794dc"
},
{
"type": "Color",
"value": "#6771dc"
},
{
"type": "Color",
"value": "#8067dc"
},
{
"type": "Color",
"value": "#a367dc"
},
{
"type": "Color",
"value": "#c767dc"
},
{
"type": "Color",
"value": "#dc67ce"
},
{
"type": "Color",
"value": "#dc67ab"
},
{
"type": "Color",
"value": "#dc6788"
}
],
"reuse": false,
"startIndex": 0,
"stateAnimationDuration": 600
}
}
},
"properties": {
"series": [
"#series-0",
"#series-1",
"#series-2",
"#series-3",
"#series-4"
],
"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"
]
}
}
],
"refs": [
{
"data-0": [
{
"age": "65+",
"video": 25,
"social": 15,
"messaging": 20,
"games": 10,
"news": 35
},
{
"age": "55-64",
"video": 35,
"social": 25,
"messaging": 25,
"games": 10,
"news": 30
},
{
"age": "45-54",
"video": 45,
"social": 35,
"messaging": 30,
"games": 15,
"news": 25
},
{
"age": "35-44",
"video": 60,
"social": 50,
"messaging": 35,
"games": 20,
"news": 20
},
{
"age": "25-34",
"video": 80,
"social": 65,
"messaging": 40,
"games": 30,
"news": 15
},
{
"age": "18-24",
"video": 95,
"social": 80,
"messaging": 45,
"games": 40,
"news": 10
}
]
},
{
"axis-0": {
"type": "ValueAxis",
"settings": {
"renderer": {
"type": "AxisRendererCircular",
"settings": {
"strokeOpacity": 0.1,
"minGridDistance": 70
},
"properties": {
"labels": {
"properties": {
"template": {
"settings": {
"radius": 10,
"maxPosition": 0.98
}
}
}
}
}
},
"min": 0,
"extraMax": 0.1,
"numberFormat": "##' min'",
"tooltip": {
"type": "Tooltip"
}
}
}
},
{
"axis-1": {
"type": "CategoryAxis",
"settings": {
"categoryField": "age",
"renderer": {
"type": "AxisRendererRadial",
"settings": {
"minGridDistance": 10
},
"properties": {
"labels": {
"properties": {
"template": {
"settings": {
"centerX": {
"type": "Percent",
"value": 100
},
"paddingRight": 8,
"paddingTop": 0,
"paddingBottom": 0,
"fontSize": 12
}
}
}
}
}
}
},
"properties": {
"data": "#data-0"
}
}
},
{
"series-0": {
"type": "RadarColumnSeries",
"settings": {
"stacked": true,
"name": "Video",
"xAxis": "#axis-0",
"yAxis": "#axis-1",
"valueXField": "video",
"categoryYField": "age",
"stroke": "@root.interfaceColors.get('background')"
},
"properties": {
"data": "#data-0",
"columns": {
"properties": {
"template": {
"settings": {
"width": {
"type": "Percent",
"value": 100
},
"strokeOpacity": 1,
"strokeWidth": 1,
"tooltipText": "{categoryY}, {name}: {valueX} min"
}
}
}
}
}
}
},
{
"series-1": {
"type": "RadarColumnSeries",
"settings": {
"stacked": true,
"name": "Social",
"xAxis": "#axis-0",
"yAxis": "#axis-1",
"valueXField": "social",
"categoryYField": "age",
"stroke": "@root.interfaceColors.get('background')"
},
"properties": {
"data": "#data-0",
"columns": {
"properties": {
"template": {
"settings": {
"width": {
"type": "Percent",
"value": 100
},
"strokeOpacity": 1,
"strokeWidth": 1,
"tooltipText": "{categoryY}, {name}: {valueX} min"
}
}
}
}
}
}
},
{
"series-2": {
"type": "RadarColumnSeries",
"settings": {
"stacked": true,
"name": "Messaging",
"xAxis": "#axis-0",
"yAxis": "#axis-1",
"valueXField": "messaging",
"categoryYField": "age",
"stroke": "@root.interfaceColors.get('background')"
},
"properties": {
"data": "#data-0",
"columns": {
"properties": {
"template": {
"settings": {
"width": {
"type": "Percent",
"value": 100
},
"strokeOpacity": 1,
"strokeWidth": 1,
"tooltipText": "{categoryY}, {name}: {valueX} min"
}
}
}
}
}
}
},
{
"series-3": {
"type": "RadarColumnSeries",
"settings": {
"stacked": true,
"name": "Games",
"xAxis": "#axis-0",
"yAxis": "#axis-1",
"valueXField": "games",
"categoryYField": "age",
"stroke": "@root.interfaceColors.get('background')"
},
"properties": {
"data": "#data-0",
"columns": {
"properties": {
"template": {
"settings": {
"width": {
"type": "Percent",
"value": 100
},
"strokeOpacity": 1,
"strokeWidth": 1,
"tooltipText": "{categoryY}, {name}: {valueX} min"
}
}
}
}
}
}
},
{
"series-4": {
"type": "RadarColumnSeries",
"settings": {
"stacked": true,
"name": "News",
"xAxis": "#axis-0",
"yAxis": "#axis-1",
"valueXField": "news",
"categoryYField": "age",
"stroke": "@root.interfaceColors.get('background')"
},
"properties": {
"data": "#data-0",
"columns": {
"properties": {
"template": {
"settings": {
"width": {
"type": "Percent",
"value": 100
},
"strokeOpacity": 1,
"strokeWidth": 1,
"tooltipText": "{categoryY}, {name}: {valueX} min"
}
}
}
}
}
}
}
]
}