Clustered box-plot
This demo shows how we can implement clustered box-plot chart with multiple columns per category/date.
The code
Section titled “The code”The box-plot chart in amCharts consists of these parts:
- A candlestick series which creates body of the box plot.
- A step line series to show a median threshold line over candles.
Candlestick series will automatically cluster itself if there are multiple series.
Step line series will need to do some tinkering, though.
The secret is to set stepWidth to 100 / seriesCount percent (50 in case there are two box plots).
If we’d have three, set it to 33. This will make the step to occupy only part of a cell.
Additionally, we’ll need to set location (0.25 for the first and 0.75 for the second median series).
The location can be calculated using this formula: 1 / seriesCount * (seriesIndex + 1) - 1 / seriesCount / 2
So, if we’d have three box plots, locations will be 1/6, 1/2 and 5/6.
let medianaSeries = chart.series.push( am5xy.StepLineSeries.new(root, { stroke: root.interfaceColors.get("background"), xAxis: xAxis, yAxis: yAxis, valueYField: "mediana", valueXField: "date", noRisers: true, stepWidth: am5.percent(50), locationX: 0.25 }));var medianaSeries = chart.series.push( am5xy.StepLineSeries.new(root, { stroke: root.interfaceColors.get("background"), xAxis: xAxis, yAxis: yAxis, valueYField: "mediana", valueXField: "date", noRisers: true, stepWidth: am5.percent(50), locationX: 0.25 }));The demo
Section titled “The demo”/** * --------------------------------------- * This demo was created using amCharts 5. * * For more information visit: * https://www.amcharts.com/ * * Documentation is available at: * https://www.amcharts.com/docs/v5/ * --------------------------------------- */
// Create root element// https://www.amcharts.com/docs/v5/getting-started/#Root_elementvar root = am5.Root.new("chartdiv");
// Set themes// https://www.amcharts.com/docs/v5/concepts/themes/root.setThemes([am5themes_Animated.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, panX: true, panY: true, wheelX: "panX", wheelY: "zoomX" }));
// 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 }, renderer: am5xy.AxisRendererX.new(root, {}), tooltip: am5.Tooltip.new(root, {}) }));
var yAxis = chart.yAxes.push( am5xy.ValueAxis.new(root, { renderer: am5xy.AxisRendererY.new(root, {}) }));
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: "MDXI", xAxis: xAxis, yAxis: yAxis, valueYField: "close", openValueYField: "open", lowValueYField: "low", highValueYField: "high", valueXField: "date", tooltip: am5.Tooltip.new(root, { pointerOrientation: "horizontal", labelText: "open: {openValueY}\nlow: {lowValueY}\nhigh: {highValueY}\nclose: {valueY},\nmediana: {mediana}" }) }));
// Add series// https://www.amcharts.com/docs/v5/charts/xy-chart/series/var series2 = chart.series.push( am5xy.CandlestickSeries.new(root, { fill: color, stroke: am5.color(0x000000), name: "MDXI", xAxis: xAxis, yAxis: yAxis, valueYField: "close2", openValueYField: "open2", lowValueYField: "low2", highValueYField: "high2", valueXField: "date", tooltip: am5.Tooltip.new(root, { pointerOrientation: "horizontal", labelText: "open: {openValueY}\nlow: {lowValueY}\nhigh: {highValueY}\nclose: {valueY},\nmediana: {mediana2}" }) }));
// mediana seriesvar medianaSeries = chart.series.push( am5xy.StepLineSeries.new(root, { stroke: root.interfaceColors.get("background"), xAxis: xAxis, yAxis: yAxis, valueYField: "mediana", valueXField: "date", noRisers: true, stepWidth: am5.percent(50), locationX: 0.25 }));
// mediana seriesvar medianaSeries2 = chart.series.push( am5xy.StepLineSeries.new(root, { stroke: root.interfaceColors.get("background"), xAxis: xAxis, yAxis: yAxis, valueYField: "mediana2", valueXField: "date", noRisers: true, stepWidth: am5.percent(50), locationX: 0.75 }));
// Add cursor// https://www.amcharts.com/docs/v5/charts/xy-chart/cursor/var cursor = chart.set( "cursor", am5xy.XYCursor.new(root, { xAxis: xAxis }));
cursor.lineY.set("visible", false);
var data = [ { date: "2019-08-01", open: 132.3, high: 136.96, low: 131.15, close: 136.49,
open2: 132.3 + 2, high2: 136.96 + 2, low2: 131.15 + 2, close2: 136.49 + 2 },
{ date: "2019-08-02", open: 135.26, high: 135.95, low: 131.5, close: 131.85, open2: 135.26 + 2, high2: 135.95 + 2, low2: 131.5 + 2, close2: 131.85 + 2 },
{ date: "2019-08-03", open: 129.9, high: 133.27, low: 128.3, close: 132.25, open2: 129.9 + 2, high2: 133.27 + 2, low2: 128.3 + 2, close2: 132.25 + 2 },
{ date: "2019-08-04", open: 132.94, high: 136.24, low: 132.63, close: 135.03, open2: 132.94 + 2, high2: 136.24 + 2, low2: 132.63 + 2, close2: 135.03 + 2 }];
addMediana();
function addMediana() { for (var i = 0; i < data.length; i++) { var dataItem = data[i]; dataItem.mediana = Number(dataItem.low) + (Number(dataItem.high) - Number(dataItem.low)) / 2; dataItem.mediana2 = Number(dataItem.low2) + (Number(dataItem.high2) - Number(dataItem.low2)) / 2; }}
series.data.processor = am5.DataProcessor.new(root, { dateFields: ["date"], dateFormat: "yyyy-MM-dd"});
series.data.setAll(data);series2.data.setAll(data);medianaSeries.data.setAll(data);medianaSeries2.data.setAll(data);
// Make stuff animate on load// https://www.amcharts.com/docs/v5/concepts/animations/series.appear(1000, 100);medianaSeries.appear(1000, 100);series2.appear(1000, 100);medianaSeries2.appear(1000, 100);chart.appear(1000, 100);<div id="chartdiv"></div>body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";}
#chartdiv { width: 100%; height: 95vh;}{ "type": "XYChart", "settings": { "focusable": true, "panX": true, "panY": true, "wheelX": "panX", "wheelY": "zoomX", "cursor": { "type": "XYCursor", "settings": { "xAxis": "#axis-0" }, "properties": { "lineY": { "settings": { "visible": false } } } } }, "properties": { "series": [ "#series-0", "#series-1", "#series-2", "#series-3" ], "xAxes": [ "#axis-0" ], "yAxes": [ "#axis-1" ] }, "refs": [ { "data-0": [ { "date": 1564606800000, "open": 132.3, "high": 136.96, "low": 131.15, "close": 136.49, "open2": 134.3, "high2": 138.96, "low2": 133.15, "close2": 138.49, "mediana": 134.055, "mediana2": 136.055 }, { "date": 1564693200000, "open": 135.26, "high": 135.95, "low": 131.5, "close": 131.85, "open2": 137.26, "high2": 137.95, "low2": 133.5, "close2": 133.85, "mediana": 133.725, "mediana2": 135.725 }, { "date": 1564779600000, "open": 129.9, "high": 133.27, "low": 128.3, "close": 132.25, "open2": 131.9, "high2": 135.27, "low2": 130.3, "close2": 134.25, "mediana": 130.78500000000003, "mediana2": 132.78500000000003 }, { "date": 1564866000000, "open": 132.94, "high": 136.24, "low": 132.63, "close": 135.03, "open2": 134.94, "high2": 138.24, "low2": 134.63, "close2": 137.03, "mediana": 134.435, "mediana2": 136.435 } ] }, { "axis-0": { "type": "DateAxis", "settings": { "baseInterval": { "timeUnit": "day", "count": 1 }, "renderer": { "type": "AxisRendererX" }, "tooltip": { "type": "Tooltip" } } } }, { "axis-1": { "type": "ValueAxis", "settings": { "renderer": { "type": "AxisRendererY" } } } }, { "series-0": { "type": "CandlestickSeries", "settings": { "fill": "@root.interfaceColors.get('background')", "stroke": "@root.interfaceColors.get('background')", "name": "MDXI", "xAxis": "#axis-0", "yAxis": "#axis-1", "valueYField": "close", "openValueYField": "open", "lowValueYField": "low", "highValueYField": "high", "valueXField": "date", "tooltip": { "type": "Tooltip", "settings": { "pointerOrientation": "horizontal", "labelText": "open: {openValueY}\nlow: {lowValueY}\nhigh: {highValueY}\nclose: {valueY},\nmediana: {mediana}" } } }, "properties": { "data": "#data-0" } } }, { "series-1": { "type": "CandlestickSeries", "settings": { "fill": "@root.interfaceColors.get('background')", "stroke": { "type": "Color", "value": "#000000" }, "name": "MDXI", "xAxis": "#axis-0", "yAxis": "#axis-1", "valueYField": "close2", "openValueYField": "open2", "lowValueYField": "low2", "highValueYField": "high2", "valueXField": "date", "tooltip": { "type": "Tooltip", "settings": { "pointerOrientation": "horizontal", "labelText": "open: {openValueY}\nlow: {lowValueY}\nhigh: {highValueY}\nclose: {valueY},\nmediana: {mediana2}" } } }, "properties": { "data": "#data-0" } } }, { "series-2": { "type": "StepLineSeries", "settings": { "stroke": "@root.interfaceColors.get('background')", "xAxis": "#axis-0", "yAxis": "#axis-1", "valueYField": "mediana", "valueXField": "date", "noRisers": true, "stepWidth": { "type": "Percent", "value": 50 }, "locationX": 0.25 }, "properties": { "data": "#data-0" } } }, { "series-3": { "type": "StepLineSeries", "settings": { "stroke": "@root.interfaceColors.get('background')", "xAxis": "#axis-0", "yAxis": "#axis-1", "valueYField": "mediana2", "valueXField": "date", "noRisers": true, "stepWidth": { "type": "Percent", "value": 50 }, "locationX": 0.75 }, "properties": { "data": "#data-0" } } } ]}multiple-box-plot-chart