Skip to main content

Pareto Chart

A Pareto chart combines sorted bars with a cumulative percentage line to show which categories contribute most of the total. It answers 80/20 questions like "which customers drive most of our revenue?" at a glance.

CustomChartDef pareto_chart {
label: 'Pareto Chart'
description: "A Pareto chart combines sorted bars with a cumulative percentage line to show which categories contribute most of the total."
fields {
field category {
type: 'dimension'
label: 'Category'
}
field value {
type: 'measure'
label: 'Value'
}
}
options {
option bar_color {
type: 'color-picker'
label: 'Bar Color'
default_value: '#255dd4'
}
option line_color {
type: 'color-picker'
label: 'Cumulative Line Color'
default_value: '#e5484d'
}
option show_threshold {
type: 'toggle'
label: 'Show 80% threshold line'
default_value: true
}
option threshold {
type: 'number-input'
label: 'Threshold (0 to 1)'
default_value: 0.8
}
}
template: @vgl
{
"data": {"values": @{values}},
"transform": [
{
"sort": [{"field": @{fields.value.name}, "order": "descending"}],
"window": [{"op": "sum", "field": @{fields.value.name}, "as": "cumulative_sum"}],
"frame": [null, 0]
},
{
"joinaggregate": [{"op": "sum", "field": @{fields.value.name}, "as": "grand_total"}]
},
{
"calculate": "datum.cumulative_sum / datum.grand_total",
"as": "cumulative_percent"
},
{
"calculate": "datum['@{fields.value.name}'] / datum.grand_total",
"as": "item_share"
},
{
"joinaggregate": [{"op": "min", "field": @{fields.value.name}, "as": "min_value"}]
},
{
"calculate": "datum['@{fields.value.name}'] === datum.min_value ? (format(@{options.threshold.value}, '.0%') + ' of total') : ''",
"as": "threshold_label"
}
],
"encoding": {
"x": {
"field": @{fields.category.name},
"type": "nominal",
"sort": {"field": @{fields.value.name}, "order": "descending"},
"title": null,
"scale": {"paddingInner": 0.25},
"axis": {
"labelOverlap": true,
"domain": false,
"ticks": false,
"grid": false,
"labelPadding": 8
}
}
},
"layer": [
{
"mark": {
"type": "bar",
"color": @{options.bar_color.value}
},
"encoding": {
"y": {
"field": @{fields.value.name},
"type": "quantitative",
"title": null,
"axis": {
"format": @{fields.value.format},
"formatType": "holisticsFormat",
"domain": false,
"tickColor": "#E5E7EB",
"grid": true,
"gridColor": "#F3F4F6",
"gridOpacity": 1
}
},
"tooltip": [
{"field": @{fields.category.name}, "type": "nominal", "title": "Category"},
{"field": @{fields.value.name}, "type": "quantitative", "title": "Value", "format": @{fields.value.format}, "formatType": "holisticsFormat"},
{"field": "item_share", "type": "quantitative", "title": "Share of Total", "format": ".1%"},
{"field": "cumulative_percent", "type": "quantitative", "title": "Cumulative", "format": ".1%"}
]
}
},
{
"layer": [
{
"mark": {
"type": "line",
"point": {"filled": true, "size": 50, "fill": @{options.line_color.value}, "stroke": "white", "strokeWidth": 1},
"color": @{options.line_color.value}
},
"encoding": {
"y": {
"field": "cumulative_percent",
"type": "quantitative",
"axis": {
"format": ".0%",
"title": "Cumulative %",
"orient": "right",
"titleColor": @{options.line_color.value},
"domain": false,
"tickColor": "#E5E7EB",
"grid": false
},
"scale": {"domain": [0, 1]}
},
"tooltip": [
{"field": @{fields.category.name}, "type": "nominal", "title": "Category"},
{"field": "cumulative_percent", "type": "quantitative", "title": "Cumulative", "format": ".1%"}
]
}
},
{
"mark": {
"type": "rule",
"strokeDash": [4, 4],
"color": "#9ba1a6",
"opacity": {"expr": "@{options.show_threshold.value} ? 1 : 0"}
},
"encoding": {
"x": null,
"y": {"datum": @{options.threshold.value}, "type": "quantitative"}
}
},
{
"mark": {
"type": "text",
"align": "right",
"baseline": "bottom",
"dx": 6,
"dy": -5,
"fontSize": 10,
"color": "#9ba1a6",
"opacity": {"expr": "@{options.show_threshold.value} ? 1 : 0"}
},
"encoding": {
"y": {"datum": @{options.threshold.value}, "type": "quantitative"},
"text": {"field": "threshold_label"}
}
}
]
}
],
"resolve": {"scale": {"y": "independent"}},
"config": {
"background": null,
"view": {
"stroke": null
},
"axis": {
"labelFontSize": 12,
"titleFontSize": 12,
"labelFontWeight": 400,
"titleFontWeight": 500
},
"legend": {
"labelFontSize": 12,
"titleFontSize": 12,
"labelFontWeight": 400,
"symbolStrokeWidth": 0
},
"bar": {
"cornerRadius": 2
}
}
}
;;
}

Open Markdown
Let us know what you think about this document :)