javascriptboxplotcandlestick-chartamcharts5

boxplot chart with amchart5, custom colors for boxplot elements


I am trying to migrate the boxplot chart below from amcharts3 to amcharts5 and could use a hand.

enter image description here

There is a demo which looks close to what I need: text. The issue here is that I can't find a way to change the sticks colors and the box below and above the median.

The way it was done with amcharts 3 was by stacking graphs with the adjustment of the Y axis values: (the first graph represents the bottom green stick, the second is the yellow box and so on)

defaultBoxPlotOptions.graphs = [
        {
            "name": "Lower Limit",
            "type": "candlestick",
            "fill": ConfigService.chartColorsCandlestick('lower'),
            'colorKey': 'lower',
            "fillAlphas": 0,
            "openField": "bottomOpen",
            "highField": "lowOpen",
            "lowField": "bottomOpen",
            "closeField": "bottomOpen",
            lineThickness: 2
        },
        {
            "name": "Middle",
            "type": "candlestick",
            "fill": ConfigService.chartColorsCandlestick('open'),
            "fillColors": ConfigService.chartColorsCandlestick('open'),
            'colorKey': 'open',
            "fillAlphas": 1,
            "openField": "bottomOpen",
            "highField": "middle",
            "lowField": "bottomOpen",
            "closeField": "middle"
        },
.....
]

I understand that the equivalent of the graps in amcharts v5 are series, I tried the implementation in a vue3 component below. If I include stacked: true, then I am getting the result below, otherwise I have the cluestered as default (one next to the other)

 <template>
    <div
        id="chartdiv"
        style="width: 100%; height: 500px"
    ></div>
</template>

<script setup lang="ts">
import { onMounted } from 'vue';
import * as am5 from '@amcharts/amcharts5';
import * as am5xy from '@amcharts/amcharts5/xy';
import am5themes_Animated from '@amcharts/amcharts5/themes/Animated';

onMounted(() => {
    // Sample data
    let data = [
        { date: '2019-08-01', open: 32.3, high: 36.96, low: 31.15, close: 36.49, median: 0 },
        { date: '2019-08-02', open: 35.26, high: 35.95, low: 31.5, close: 31.85, median: 0 },
        { date: '2019-08-03', open: 29.9, high: 33.27, low: 28.3, close: 32.25, median: 0 },
    ];
    // Create root element
    let root = am5.Root.new('chartdiv');

    // Set themes
    root.setThemes([
        am5themes_Animated.new(root),
    ]);

    // Create chart
    let chart = root.container.children.push(
        am5xy.XYChart.new(root, {
            focusable: true,
            panX: true,
            panY: true,
            wheelX: 'panX',
            wheelY: 'zoomX',
        }),
    );

    // Create axes
    let xAxis = chart.xAxes.push(
        am5xy.DateAxis.new(root, {
            baseInterval: { timeUnit: 'day', count: 1 },
            renderer: am5xy.AxisRendererX.new(root, {
                pan: 'zoom',
                minorGridEnabled: true,
                minGridDistance: 70,
            }),
            tooltip: am5.Tooltip.new(root, {}),
        }),
    );

    let yAxis = chart.yAxes.push(
        am5xy.ValueAxis.new(root, {
            renderer: am5xy.AxisRendererY.new(root, {
                pan: 'zoom',
            }),
        }),
    );

    // Add series
    let series = chart.series.push(
        am5xy.CandlestickSeries.new(root, {
            name: 'MDXI',
            xAxis: xAxis,
            yAxis: yAxis,
            valueYField: 'close',
            openValueYField: 'open',
            lowValueYField: 'close',
            highValueYField: 'open',
            valueXField: 'date',
            stacked: true,
            tooltip: am5.Tooltip.new(root, {
                pointerOrientation: 'horizontal',
                labelText:
                    'open: {openValueY}\nlow: {lowValueY}\nhigh: {highValueY}\nclose: {valueY}\nmedian: {median}',
            }),
        }),
    );

    let series2 = chart.series.push(
        am5xy.CandlestickSeries.new(root, {
            name: 'wefwdfwd',
            xAxis: xAxis,
            yAxis: yAxis,
            valueYField: 'open',
            openValueYField: 'low',
            lowValueYField: 'low',
            highValueYField: 'low',
            valueXField: 'date',
            stacked: true,
        }),
    );

    // Add median to data
    data.forEach((item) => {
        item.median = item.low + (item.high - item.low) / 2;
    });

    series.data.processor = am5.DataProcessor.new(root, {
        dateFields: ['date'],
        dateFormat: 'yyyy-MM-dd',
    });

    series.data.setAll(data);
    series2.data.setAll(data);

    // Median series
    let medianSeries = chart.series.push(
        am5xy.StepLineSeries.new(root, {
            stroke: am5.color(0xff0000),
            xAxis: xAxis,
            yAxis: yAxis,
            valueYField: 'median',
            valueXField: 'date',
            noRisers: true,
        }),
    );

    medianSeries.data.setAll(data);

    // Add cursor
    let cursor = chart.set(
        'cursor',
        am5xy.XYCursor.new(root, {
            xAxis: xAxis,
        }),
    );
    cursor.lineY.set('visible', false);

    // Make stuff animate on load
    series.appear(1000, 100);
    series2.appear(1000, 100);
    medianSeries.appear(1000, 100);
    chart.appear(1000, 100);
});
</script>

Stacked series

I can see two ways of achieving the boxplot chart in version 5 but I failed getting a result. Any tips would be greatly appreciated.

  1. change the colors of the candlestick series elements, add a triangle shaped median
  2. have multiple candlestick elements stacked

Solution

  • I have found that to create a candlestick chart like that we need to use ColumnSeries instead of CandlestickSeries

    const boxplotSectionSeries = chart.series.push(
      am5xy.ColumnSeries.new(root, {
        name: "boxplotSection",
        xAxis: xAxis,
        yAxis: yAxis,
        valueYField: "upper",
        openValueYField: "up",
        categoryXField: "category",
        clustered: false,
        fill: am5.color("#FFFFFF"),
      })
    );
    boxplotSectionSeries.columns.template.setAll({
      width: 50,
      strokeWidth: 2,
      tooltipText: " {openValueY}\nUpper: {valueY}",
      tooltipY: am5.percent(10),
    });
    boxplotSectionSeries.data.setAll(data);
    
    
    
    clustered: false, //will make the series stack
    width: 50, // sets the width
    fill: am5.color("#FFFFFF"), // sets the color
    

    Hopefully this will help someone