A Pareto chart sorts the columns from largest to smallest and adds a line that sums them up as it goes. Here, visits from 10 countries: the first four bring two thirds of all visits.
A Pareto chart shows which few causes make up most of the total, so you know where to act first. Read the line against the right-hand axis: where it passes 80%, the columns to its left are the vital few, and the ones to its right add little.
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, // no dragging to pan...
panY: false, // ...in either direction
wheelX: "panX", // a horizontal wheel or trackpad swipe pans...
wheelY: "zoomX", // ...and the vertical wheel zooms in on the countries
paddingLeft: 0, // the value labels sit at the chart's left edge...
paddingRight: 0, // ...and the percent labels at its right edge
layout: root.verticalLayout // the chart's parts are stacked top to bottom
}));
// Add cursor: drag across the plot to zoom in on a few countries
// https://www.amcharts.com/docs/v5/charts/xy-chart/cursor/
var cursor = chart.set("cursor", am5xy.XYCursor.new(root, {
behavior: "zoomX"
}));
cursor.lineY.set("visible", false); // only the vertical cursor line, no horizontal one
var data = [{
country: "US",
visits: 725
}, {
country: "UK",
visits: 625
}, {
country: "China",
visits: 602
}, {
country: "Japan",
visits: 509
}, {
country: "Germany",
visits: 322
}, {
country: "France",
visits: 214
}, {
country: "India",
visits: 204
}, {
country: "Spain",
visits: 198
}, {
country: "Netherlands",
visits: 165
}, {
country: "Canada",
visits: 41
}];
prepareParetoData(); // adds a pareto field to each row
// each country's running total, as a percent of all visits
function prepareParetoData() {
var total = 0;
for (var i = 0; i < data.length; i++) { // the total of all visits...
var value = data[i].visits;
total += value;
}
var sum = 0;
for (var i = 0; i < data.length; i++) { // ...then each country's running total, in percent
var value = data[i].visits;
sum += value;
data[i].pareto = sum / total * 100;
}
}
// Create axes
// https://www.amcharts.com/docs/v5/charts/xy-chart/axes/
var xRenderer = am5xy.AxisRendererX.new(root, {
// a label under every column
minGridDistance: 20,
minorGridEnabled: true // fainter grid lines between the labeled ones
})
var xAxis = chart.xAxes.push(am5xy.CategoryAxis.new(root, {
categoryField: "country",
renderer: xRenderer
}));
xRenderer.grid.template.setAll({
location: 1 // grid lines between the countries, not through their middle
})
xRenderer.labels.template.setAll({
paddingTop: 20, // 20px below the axis
// long names wrap onto a second line instead of running into the next one
oversizedBehavior: "wrap-no-break",
textAlign: "center" // wrapped lines centered
});
// each label may be as wide as its category's cell
xAxis.onPrivate("cellWidth", function (cellWidth) {
xRenderer.labels.template.set("maxWidth", cellWidth);
});
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
})
}));
var paretoAxisRenderer = am5xy.AxisRendererY.new(root, { opposite: true }); // on the right side
var paretoAxis = chart.yAxes.push(am5xy.ValueAxis.new(root, {
renderer: paretoAxisRenderer,
min: 0,
max: 100,
// the percent scale stays exactly 0 to 100, without rounding
strictMinMax: true
}));
paretoAxisRenderer.grid.template.set("forceHidden", true); // no grid lines of its own: the left axis draws them
paretoAxis.set("numberFormat", "#'%"); // whole numbers with a percent sign
// Add series
// https://www.amcharts.com/docs/v5/charts/xy-chart/series/
var series = chart.series.push(am5xy.ColumnSeries.new(root, {
name: "Visits",
xAxis: xAxis,
yAxis: yAxis,
valueYField: "visits",
categoryXField: "country",
// Each column takes its own color from the series palette
colorByDataItem: true
}));
series.columns.template.setAll({
tooltipText: "{categoryX}: {valueY}", // the country and its visits on hover
tooltipY: 0, // the tooltip points at the top of the column
strokeOpacity: 0, // no outline
cornerRadiusTL: 6, // rounded top corners
cornerRadiusTR: 6
});
// pareto series
var paretoSeries = chart.series.push(am5xy.LineSeries.new(root, {
name: "Cumulative share",
xAxis: xAxis,
yAxis: paretoAxis,
valueYField: "pareto",
categoryXField: "country",
stroke: root.interfaceColors.get("alternativeBackground"), // a line in the contrast color
// the last dot, at 100%, may draw past the top of the plot instead of being cut
maskBullets: false
}));
// a dot on each country's running total
paretoSeries.bullets.push(function () {
return am5.Bullet.new(root, {
locationY: 1,
sprite: am5.Circle.new(root, {
radius: 5, // 5px radius
fill: series.get("fill"), // filled in the column series' color...
stroke: root.interfaceColors.get("alternativeBackground") // ...and outlined in the contrast color
})
})
})
series.data.setAll(data);
paretoSeries.data.setAll(data);
// Make stuff animate on load
// https://www.amcharts.com/docs/v5/concepts/animations/
series.appear();
chart.appear(1000, 100);
{
"type": "XYChart",
"settings": {
"panX": false,
"panY": false,
"wheelX": "panX",
"wheelY": "zoomX",
"paddingLeft": 0,
"paddingRight": 0,
"layout": {
"type": "VerticalLayout"
},
"cursor": {
"type": "XYCursor",
"settings": {
"behavior": "zoomX"
},
"properties": {
"lineY": {
"settings": {
"visible": false
}
}
}
}
},
"properties": {
"series": [
"#series-0",
"#series-1"
],
"xAxes": [
"#axis-0"
],
"yAxes": [
"#axis-1",
"#axis-2"
]
},
"refs": [
{
"data-0": [
{
"country": "US",
"visits": 725,
"pareto": 20.110957004160888
},
{
"country": "UK",
"visits": 625,
"pareto": 37.447988904299585
},
{
"country": "China",
"visits": 602,
"pareto": 54.14701803051317
},
{
"country": "Japan",
"visits": 509,
"pareto": 68.26629680998613
},
{
"country": "Germany",
"visits": 322,
"pareto": 77.19833564493759
},
{
"country": "France",
"visits": 214,
"pareto": 83.13453536754508
},
{
"country": "India",
"visits": 204,
"pareto": 88.79334257975034
},
{
"country": "Spain",
"visits": 198,
"pareto": 94.28571428571428
},
{
"country": "Netherlands",
"visits": 165,
"pareto": 98.8626907073509
},
{
"country": "Canada",
"visits": 41,
"pareto": 100
}
]
},
{
"axis-0": {
"type": "CategoryAxis",
"settings": {
"categoryField": "country",
"renderer": {
"type": "AxisRendererX",
"settings": {
"minGridDistance": 20,
"minorGridEnabled": true
},
"properties": {
"labels": {
"properties": {
"template": {
"settings": {
"paddingTop": 20,
"oversizedBehavior": "wrap-no-break",
"textAlign": "center",
"maxWidth": 89.726171875
}
}
}
},
"grid": {
"properties": {
"template": {
"settings": {
"location": 1
}
}
}
}
}
}
},
"properties": {
"data": "#data-0"
}
}
},
{
"axis-1": {
"type": "ValueAxis",
"settings": {
"renderer": {
"type": "AxisRendererY",
"settings": {
"strokeOpacity": 0.1
}
}
}
}
},
{
"axis-2": {
"type": "ValueAxis",
"settings": {
"renderer": {
"type": "AxisRendererY",
"settings": {
"opposite": true
},
"properties": {
"grid": {
"properties": {
"template": {
"settings": {
"forceHidden": true
}
}
}
}
}
},
"min": 0,
"max": 100,
"strictMinMax": true,
"numberFormat": "##'%"
}
}
},
{
"series-0": {
"type": "ColumnSeries",
"settings": {
"name": "Visits",
"xAxis": "#axis-0",
"yAxis": "#axis-1",
"valueYField": "visits",
"categoryXField": "country",
"colorByDataItem": true
},
"properties": {
"data": "#data-0",
"columns": {
"properties": {
"template": {
"settings": {
"tooltipText": "{categoryX}: {valueY}",
"tooltipY": 0,
"strokeOpacity": 0,
"cornerRadiusTL": 6,
"cornerRadiusTR": 6
}
}
}
}
}
}
},
{
"series-1": {
"type": "LineSeries",
"settings": {
"name": "Cumulative share",
"xAxis": "#axis-0",
"yAxis": "#axis-2",
"valueYField": "pareto",
"categoryXField": "country",
"stroke": "@root.interfaceColors.get('alternativeBackground')",
"maskBullets": false
},
"properties": {
"data": "#data-0",
"bullets": [
{
"type": "Bullet",
"settings": {
"locationY": 1,
"sprite": {
"type": "Circle",
"settings": {
"radius": 5,
"fill": {
"type": "Color",
"value": "#67b7dc"
},
"stroke": "@series.get('stroke')"
}
}
}
}
]
}
}
}
]
}