A box plot sums up a spread of values in one mark: the box holds the middle half, the line across it is the median, and the whiskers reach the lowest and highest values. Here, nine days side by side.
A box plot compares how values spread, not just their averages: where the middle half sits, how wide it is and how far the extremes reach. Nine boxes side by side show at a glance which days ran higher and which varied more.
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, {
focusable: true, // the chart can take keyboard focus, for keyboard users
panX: true, // drag the plot sideways to pan...
panY: true, // ...or up and down
wheelX: "panX", // a horizontal wheel or trackpad swipe pans
wheelY: "zoomX" // the vertical wheel zooms in on the dates
})
);
// Add scrollbar, hidden at first
// https://www.amcharts.com/docs/v5/charts/xy-chart/scrollbars/
chart.set("scrollbarX", am5.Scrollbar.new(root, { orientation: "horizontal", forceHidden: true }));
// Create axes
// https://www.amcharts.com/docs/v5/charts/xy-chart/axes/
var xAxis = chart.xAxes.push(
am5xy.DateAxis.new(root, {
baseInterval: { timeUnit: "day", count: 1 }, // one box per day
renderer: am5xy.AxisRendererX.new(root, {
// drag along the axis labels to zoom the axis in and out
pan: "zoom",
minorGridEnabled: true, // fainter grid lines between the labeled dates
minGridDistance: 70 // at least 70px between labels; on narrow screens some are skipped
}),
tooltip: am5.Tooltip.new(root, {}) // the cursor shows the date on the axis
})
);
var yAxis = chart.yAxes.push(
am5xy.ValueAxis.new(root, {
renderer: am5xy.AxisRendererY.new(root, {
pan: "zoom" // drag along the value labels to zoom them too
})
})
);
var color = root.interfaceColors.get("background");
// Add series
// https://www.amcharts.com/docs/v5/charts/xy-chart/series/
var series = chart.series.push(
am5xy.CandlestickSeries.new(root, {
fill: color,
stroke: color,
name: "Distribution",
xAxis: xAxis,
yAxis: yAxis,
// Box: first quartile (Q1) to third quartile (Q3); whiskers: minimum to maximum
valueYField: "q3",
openValueYField: "q1",
lowValueYField: "min",
highValueYField: "max",
valueXField: "date",
tooltip: am5.Tooltip.new(root, {
pointerOrientation: "horizontal", // the tooltip points sideways at the box
// the five numbers, top to bottom
labelText: "Max: {highValueY}\nQ3: {valueY}\nMedian: {median}\nQ1: {openValueY}\nMin: {lowValueY}"
})
})
);
// Box plots use one colour: override the candlestick rise/drop colouring
var boxColor = chart.get("colors").getIndex(0); // the theme's first color
am5.array.each(["riseFromOpen", "dropFromOpen", "riseFromPrevious", "dropFromPrevious"], function(state) {
series.columns.template.states.create(state, { fill: boxColor, stroke: boxColor });
});
// Median line inside each box: as wide as the box (candles are 50% of a day), with no risers between the days
var medianSeries = chart.series.push(
am5xy.StepLineSeries.new(root, {
stroke: root.interfaceColors.get("background"), // a line in the background color across the box
xAxis: xAxis,
yAxis: yAxis,
valueYField: "median",
valueXField: "date",
stepWidth: am5.percent(50),
noRisers: true
})
);
medianSeries.strokes.template.set("strokeWidth", 2); // a 2px median line
// Add cursor
// https://www.amcharts.com/docs/v5/charts/xy-chart/cursor/
var cursor = chart.set("cursor", am5xy.XYCursor.new(root, {
xAxis: xAxis // the cursor snaps to whole days
}));
cursor.lineY.set("visible", false); // no horizontal cursor line, only the vertical one
// Five-number summary for each day: minimum, first quartile, median, third quartile, maximum
var data = [
{
date: "2025-08-01",
min: 124.1,
q1: 129.6,
median: 132.2,
q3: 134.8,
max: 139.5
},
{
date: "2025-08-02",
min: 122.8,
q1: 128.4,
median: 131.0,
q3: 133.9,
max: 140.2
},
{
date: "2025-08-03",
min: 125.6,
q1: 130.1,
median: 133.4,
q3: 136.2,
max: 142.8
},
{
date: "2025-08-04",
min: 127.3,
q1: 131.8,
median: 134.0,
q3: 137.5,
max: 144.1
},
{
date: "2025-08-05",
min: 123.9,
q1: 129.2,
median: 131.7,
q3: 134.3,
max: 138.6
},
{
date: "2025-08-06",
min: 121.4,
q1: 127.5,
median: 130.3,
q3: 133.1,
max: 137.9
},
{
date: "2025-08-07",
min: 124.8,
q1: 130.6,
median: 133.9,
q3: 137.0,
max: 143.4
},
{
date: "2025-08-08",
min: 126.2,
q1: 131.4,
median: 134.6,
q3: 138.1,
max: 145.0
},
{
date: "2025-08-09",
min: 125.0,
q1: 130.2,
median: 132.8,
q3: 135.9,
max: 141.7
}
];
// turns the date strings into timestamps, in the data itself, so the median series gets them too
series.data.processor = am5.DataProcessor.new(root, {
dateFields: ["date"], // the field that holds dates...
dateFormat: "yyyy-MM-dd" // ...written like 2025-08-01
});
series.data.setAll(data);
medianSeries.data.setAll(data);
// Make stuff animate on load
// https://www.amcharts.com/docs/v5/concepts/animations/
series.appear(1000, 100);
medianSeries.appear(1000, 100);
chart.appear(1000, 100);
{
"type": "XYChart",
"settings": {
"focusable": true,
"panX": true,
"panY": true,
"wheelX": "panX",
"wheelY": "zoomX",
"scrollbarX": {
"type": "Scrollbar",
"settings": {
"orientation": "horizontal",
"forceHidden": true
}
},
"cursor": {
"type": "XYCursor",
"settings": {
"xAxis": "#axis-0"
},
"properties": {
"lineY": {
"settings": {
"visible": false
}
}
}
}
},
"properties": {
"series": [
"#series-0",
"#series-1"
],
"xAxes": [
"#axis-0"
],
"yAxes": [
"#axis-1"
]
},
"refs": [
{
"data-0": [
{
"date": 1753995600000,
"min": 124.1,
"q1": 129.6,
"median": 132.2,
"q3": 134.8,
"max": 139.5
},
{
"date": 1754082000000,
"min": 122.8,
"q1": 128.4,
"median": 131,
"q3": 133.9,
"max": 140.2
},
{
"date": 1754168400000,
"min": 125.6,
"q1": 130.1,
"median": 133.4,
"q3": 136.2,
"max": 142.8
},
{
"date": 1754254800000,
"min": 127.3,
"q1": 131.8,
"median": 134,
"q3": 137.5,
"max": 144.1
},
{
"date": 1754341200000,
"min": 123.9,
"q1": 129.2,
"median": 131.7,
"q3": 134.3,
"max": 138.6
},
{
"date": 1754427600000,
"min": 121.4,
"q1": 127.5,
"median": 130.3,
"q3": 133.1,
"max": 137.9
},
{
"date": 1754514000000,
"min": 124.8,
"q1": 130.6,
"median": 133.9,
"q3": 137,
"max": 143.4
},
{
"date": 1754600400000,
"min": 126.2,
"q1": 131.4,
"median": 134.6,
"q3": 138.1,
"max": 145
},
{
"date": 1754686800000,
"min": 125,
"q1": 130.2,
"median": 132.8,
"q3": 135.9,
"max": 141.7
}
]
},
{
"axis-0": {
"type": "DateAxis",
"settings": {
"baseInterval": {
"timeUnit": "day",
"count": 1
},
"renderer": {
"type": "AxisRendererX",
"settings": {
"pan": "zoom",
"minorGridEnabled": true,
"minGridDistance": 70
}
},
"tooltip": {
"type": "Tooltip"
}
}
}
},
{
"axis-1": {
"type": "ValueAxis",
"settings": {
"renderer": {
"type": "AxisRendererY",
"settings": {
"pan": "zoom"
}
}
}
}
},
{
"series-0": {
"type": "CandlestickSeries",
"settings": {
"fill": "@root.interfaceColors.get('background')",
"stroke": "@root.interfaceColors.get('background')",
"name": "Distribution",
"xAxis": "#axis-0",
"yAxis": "#axis-1",
"valueYField": "q3",
"openValueYField": "q1",
"lowValueYField": "min",
"highValueYField": "max",
"valueXField": "date",
"tooltip": {
"type": "Tooltip",
"settings": {
"pointerOrientation": "horizontal",
"labelText": "Max: {highValueY}\nQ3: {valueY}\nMedian: {median}\nQ1: {openValueY}\nMin: {lowValueY}"
}
}
},
"properties": {
"data": "#data-0",
"columns": {
"properties": {
"template": {
"states": [
{
"key": "riseFromOpen",
"settings": {
"fill": {
"type": "Color",
"value": "#67b7dc"
},
"stroke": {
"type": "Color",
"value": "#67b7dc"
}
}
},
{
"key": "dropFromOpen",
"settings": {
"fill": {
"type": "Color",
"value": "#67b7dc"
},
"stroke": {
"type": "Color",
"value": "#67b7dc"
}
}
},
{
"key": "riseFromPrevious",
"settings": {
"fill": {
"type": "Color",
"value": "#67b7dc"
},
"stroke": {
"type": "Color",
"value": "#67b7dc"
}
}
},
{
"key": "dropFromPrevious",
"settings": {
"fill": {
"type": "Color",
"value": "#67b7dc"
},
"stroke": {
"type": "Color",
"value": "#67b7dc"
}
}
}
]
}
}
}
}
}
},
{
"series-1": {
"type": "StepLineSeries",
"settings": {
"stroke": "@root.interfaceColors.get('background')",
"xAxis": "#axis-0",
"yAxis": "#axis-1",
"valueYField": "median",
"valueXField": "date",
"stepWidth": {
"type": "Percent",
"value": 50
},
"noRisers": true
},
"properties": {
"data": "#data-0",
"strokes": {
"properties": {
"template": {
"settings": {
"strokeWidth": 2
}
}
}
}
}
}
}
]
}