Cat_Enthusiast
Cat_Enthusiast

Reputation: 15688

HighCharts Data Structure - Multiple Independent Series, Stacked Column Chart

I'm trying to create a highchart that resembles the following but am not sure how to configure my parameters and rather confused about the data structure

enter image description here Notes: Each column should be independent. They do not share any data/series amongst each other. Data within a column should be contained within its own column.

Essentially, I want to have five different series on the y-axis, where each series will stack its data and not pass that data into the other axises.

ie: Asset Class has data for Stocks, ETFS, Cash and that data should only be in the Asset Class column. Similarly, Industry will have data for Sector Level and etc.

Currently, my output resembles the standard stacked-bar-chart layout

enter image description here

Here is my current data structure, which I am sure will need a big revision:

categories: ["", "Utilities", "Energy", "Funds", "Financial", "Consumer, Cyclical", "Consumer, Non-cyclical", "Communications", "Basic Materials", "Industrial", "Technology", "Other", "Government"]

series: [
 {name: "Cash", data: Array(13)},
 {name: "Equity", data: Array(13)},
 {name: "Fixed Income", data: Array(13)},
 {name: "Fund", data: Array(13)}
]

My chart code if needed:

this.options = {
          chart: {
            type: 'column',
            height: 500,
            style: {
              fontFamily: "Arial"
            }
          },
          title: {
            text: ""
          },
          xAxis: {
            categories: categories,
            labels: {
              style: {
                fontSize: "14px"
              }
            }
          },
          yAxis: {
            min: 0,
            title: {
              text: ""
            },
            labels: {
              formatter: function () {
                let valueString = (
                  this.value > 999.99 && this.value <= 999999.99 ?
                    "$" + (this.value / 1000).toFixed(0) + "K" : this.value > 999999.99 ?
                      "$" + (this.value / 1000000).toFixed(1) + "M" : this.value
                )
                return valueString
              },
              style: {
                fontSize: "14px",
              }
            }

          },
          legend: {
            align: 'right',
            verticalAlign: 'top',
            layout: "vertical",
            x: 0,
            y: 50,
            itemStyle: {
              fontSize: "16px",
              color: "#6c6c6c",
            },
            symbolPadding: 8,
            itemMarginTop: 10,
            shadow: false,
            labelFormatter: function () {
              return `${this.name}`
            }
          },
          tooltip: {
            formatter: function () {
              let name = this.series.name
              let value = this.y
              let valueString = `$${value.toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}`
              let total = this.point.stackTotal
              let percentage = ((value / total) * 100).toFixed(2)
              let percentageString = `(${percentage})%`

              return `<b>${name}</b> <br> ${valueString} ${percentageString}`
            },
            style: {
              fontSize: "14px",
            },
            backgroundColor: "#ffffff"
          },
          plotOptions: {
            column: {
              stacking: 'normal',
              dataLabels: {
                enabled: false
              }
            },
            series: {
              borderColor: "rgba(0, 0, 0, 0)"
            }
          },
          series: series
        }

We also discussed whether it would be possible to have a list of categories, and only use a portion of those categories depending on the column we have selected. Any help will be greatly appreciated :)

Upvotes: 2

Views: 735

Answers (1)

ppotaczek
ppotaczek

Reputation: 39069

Relative to the description, your series structure should look this way:

series = [{
        name: "Cash",
        data: [
            {x: 0, y: 5},
            {x: 0, y: 2},
            {x: 0, y: 4}
        ]
    }, {
        name: "Equity",
        data: [
            {x: 1, y: 4},
            {x: 1, y: 3},
            {x: 1, y: 4}
        ]
    }, {
        name: "Fixed Income",
        data: [
            {x: 2, y: 4},
            {x: 2, y: 5},
            {x: 2, y: 2}
        ]
    }]

To make the hover series look 'active', you can use update method for the series points in mouseOver and mouseOut events:

var categories = ["Utilities", "Energy", "Funds"],
    colors = ['red', 'green', 'blue'],
    series = [...],
    i = 0,
    newCategories,
    chartCategories = [];

for (; i < series.length; i++) {
    chartCategories.push('');
}

Highcharts.chart('container', {
    ...,
    plotOptions: {
        column: {
            ...,
            events: {
                mouseOver: function() {
                    this.points.forEach(function(p, i) {
                        p.update({
                            color: colors[i]
                        });
                    }, this);

                    newCategories = chartCategories.slice();

                    newCategories.splice(
                        this.index, 1, categories[this.index]
                    );

                    this.xAxis.setCategories(
                        newCategories
                    );
                },
                mouseOut: function() {
                    this.points.forEach(function(p) {
                        p.update({
                            color: ''
                        });
                    }, this);

                    this.xAxis.setCategories(
                        chartCategories
                    );
                }
            }
        }
    }
});

Live demo: http://jsfiddle.net/BlackLabel/Ljfqe0ts/

API Reference: https://api.highcharts.com/highcharts/series.column.events

Upvotes: 3

Related Questions