# Ridgeline Chart > A ridgeline chart compares the distribution of a numeric value across categories, drawing one overlapping density curve per category. A ridgeline chart compares the distribution of a numeric value across categories, drawing one smooth density curve per category in a compact stack. Use it for questions like "how do delivery times differ by carrier?" or "what does order value look like per customer segment?": where a box plot shows summary statistics, a ridgeline shows the actual shape (skew, peaks, outlier tails) of each group. Feed it raw observations (one row per record), not pre-aggregated values: the chart estimates each category's density with KDE. To keep extreme outliers from crushing the axis, the visible range is clamped to the Tukey fences (1.5 IQR beyond the quartiles); by default every ridge is scaled to its own shape, with an option to scale heights by record count instead. Hovering a ridge highlights it and fades the others. Adapted from the Vega "U-District Cuisine" example. ![](https://media.holistics.io/bd9412d7-ridgeline-chart.png) ```aml CustomChartDef ridgeline_chart { label: 'Ridgeline Chart' description: 'To compare the distribution of a numeric value across categories, with one overlapping density curve per category.' fields { field dimension { label: 'Dimension' type: 'dimension' sort { apply_order: 1 direction: 'asc' } } field value { label: 'Value' type: 'dimension' // numeric; use a row-level number, not an aggregated measure data_type: 'number' sort { apply_order: 2 direction: 'asc' } } } options { option overlap { label: 'Ridge overlap' type: 'select' options: [1, 1.5, 2, 2.5, 3] default_value: 2 } option bandwidth { label: 'KDE bandwidth (0 = automatic)' type: 'number-input' default_value: 0 } option scale_by_count { label: 'Scale ridge height by record count' type: 'toggle' default_value: false } option color_scheme { label: 'Color scheme' type: 'select' options: ['tableau10', 'category10', 'accent', 'dark2', 'paired', 'set2'] default_value: 'tableau10' } } template: @vg { "$schema": "https://vega.github.io/schema/vega/v5.json", "signals": [ { "name": "width", "init": "containerSize()[0] - 16", "on": [{ "events": "window:resize", "update": "containerSize()[0] - 16" }] }, { "name": "height", "init": "containerSize()[1] - 44", "on": [{ "events": "window:resize", "update": "containerSize()[1] - 44" }] }, {"name": "overlap", "update": "@{options.overlap.value}"}, {"name": "bandwidth", "update": "@{options.bandwidth.value}"}, {"name": "ext", "update": "length(data('value_extent')) ? data('value_extent')[0] : null"}, {"name": "iqr", "update": "ext ? ext.q3 - ext.q1 : 0"}, {"name": "vmin", "update": "ext ? (iqr > 0 ? max(ext.raw_min, ext.q1 - 1.5 * iqr) : ext.raw_min) : 0"}, {"name": "vmax", "update": "ext ? (iqr > 0 ? min(ext.raw_max, ext.q3 + 1.5 * iqr) : ext.raw_max) : 1"}, {"name": "domainMax", "update": "length(data('density_max')) ? data('density_max')[0].dmax : 1"}, { "name": "hovered", "value": null, "on": [ {"events": "@ridge:mouseover", "update": "datum.category"}, {"events": "@ridge:mouseout", "update": "null"} ] } ], "data": [ { "name": "source", "values": @{values}, "transform": [ {"type": "formula", "expr": "datum['@{fields.dimension.name}']", "as": "category"}, {"type": "formula", "expr": "datum['@{fields.value.name}']", "as": "amount"}, {"type": "filter", "expr": "datum.amount != null"} ] }, { "name": "value_extent", "source": "source", "transform": [ { "type": "aggregate", "fields": ["amount", "amount", "amount", "amount"], "ops": ["min", "max", "q1", "q3"], "as": ["raw_min", "raw_max", "q1", "q3"] } ] }, { "name": "density", "source": "source", "transform": [ {"type": "filter", "expr": "datum.amount >= vmin && datum.amount <= vmax"}, { "type": "kde", "groupby": ["category"], "field": "amount", "bandwidth": {"signal": "bandwidth"}, "extent": {"signal": "[vmin, vmax]"}, "steps": 200, "counts": @{options.scale_by_count.value} } ] }, { "name": "density_max", "source": "density", "transform": [ {"type": "aggregate", "fields": ["density"], "ops": ["max"], "as": ["dmax"]} ] } ], "scales": [ { "name": "xscale", "type": "linear", "range": [0, {"signal": "width"}], "zero": false, "nice": true, "domain": {"signal": "[vmin, vmax]"} }, { "name": "yscale", "type": "band", "range": [0, {"signal": "height"}], "round": true, "padding": 0, "domain": {"data": "source", "field": "category", "sort": true} }, { "name": "color", "type": "ordinal", "domain": {"data": "source", "field": "category", "sort": true}, "range": {"scheme": @{options.color_scheme.value}} } ], "axes": [ {"orient": "bottom", "scale": "xscale"}, { "orient": "right", "scale": "yscale", "encode": { "labels": { "update": { "dx": {"value": -4}, "dy": {"value": -2}, "y": {"scale": "yscale", "field": "value", "band": 1}, "align": {"value": "right"}, "baseline": {"value": "bottom"}, "fill": {"value": "#374151"}, "fontWeight": { "signal": "hovered === datum.value ? 600 : 400" } } } } } ], "marks": [ { "type": "group", "from": { "facet": {"data": "density", "name": "cat_density", "groupby": "category"} }, "encode": { "update": { "y": {"scale": "yscale", "field": "category"}, "width": {"signal": "width"}, "height": {"signal": "bandwidth('yscale')"} } }, "sort": {"field": "y", "order": "ascending"}, "signals": [ {"name": "bandH", "update": "bandwidth('yscale')"} ], "scales": [ { "name": "yinner", "type": "linear", "range": [{"signal": "bandH"}, {"signal": "0 - overlap * bandH"}], "domain": [0, {"signal": "domainMax"}] } ], "marks": [ { "type": "rule", "interactive": false, "encode": { "update": { "x": {"value": 0}, "x2": {"signal": "width"}, "y": {"signal": "bandH", "offset": -0.5}, "stroke": {"value": "#E5E7EB"}, "strokeWidth": {"value": 0.5} } } }, { "type": "area", "name": "ridge", "from": {"data": "cat_density"}, "encode": { "update": { "x": {"scale": "xscale", "field": "value"}, "y": {"scale": "yinner", "field": "density"}, "y2": {"scale": "yinner", "value": 0}, "fill": {"scale": "color", "field": "category"}, "fillOpacity": { "signal": "hovered === null ? 0.7 : (hovered === datum.category ? 0.92 : 0.2)" }, "stroke": {"value": "white"}, "strokeWidth": {"value": 1}, "tooltip": {"signal": "datum.category"} } } } ] } ], "config": { "axis": {"domain": false, "ticks": false, "labelFontSize": 12}, "axisX": {"grid": false, "labelPadding": 8} } };; } ```