Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chart.js stacked and grouped bar chart

is there any way to do a stacked and grouped bar chart with Chart.js library?

It should look something like this http://www.highcharts.com/demo/column-stacked-and-grouped

like image 840
Tomas Javaišis Avatar asked May 28 '16 13:05

Tomas Javaišis


People also ask

What is the difference between stacked bar chart and bar chart?

The stacked bar chart (aka stacked bar graph) extends the standard bar chart from looking at numeric values across one categorical variable to two. Each bar in a standard bar chart is divided into a number of sub-bars stacked end to end, each one corresponding to a level of the second categorical variable.

Is multiple bar chart and grouped bar chart same?

A grouped bar chart (aka clustered bar chart, multi-series bar chart) extends the bar chart, plotting numeric values for levels of two categorical variables instead of one. Bars are grouped by position for levels of one categorical variable, with color indicating the secondary category level within each group.

What is better than a stacked bar chart?

Dot plot. An alternative to the bar or column panel charts is a dot plot. The advantage is that all points are plotted in the same XY space, allowing for easier comparisons.


1 Answers

OK, I found the solution. It's described in this GitHub issue and solution is in this JSFiddle

Chart.defaults.groupableBar = Chart.helpers.clone(Chart.defaults.bar);

var helpers = Chart.helpers;
Chart.controllers.groupableBar = Chart.controllers.bar.extend({
  calculateBarX: function (index, datasetIndex) {
    // position the bars based on the stack index
    var stackIndex = this.getMeta().stackIndex;
    return Chart.controllers.bar.prototype.calculateBarX.apply(this, [index, stackIndex]);
  },

  hideOtherStacks: function (datasetIndex) {
    var meta = this.getMeta();
    var stackIndex = meta.stackIndex;

    this.hiddens = [];
    for (var i = 0; i < datasetIndex; i++) {
      var dsMeta = this.chart.getDatasetMeta(i);
      if (dsMeta.stackIndex !== stackIndex) {
        this.hiddens.push(dsMeta.hidden);
        dsMeta.hidden = true;
      }
    }
  },

  unhideOtherStacks: function (datasetIndex) {
    var meta = this.getMeta();
    var stackIndex = meta.stackIndex;

    for (var i = 0; i < datasetIndex; i++) {
      var dsMeta = this.chart.getDatasetMeta(i);
      if (dsMeta.stackIndex !== stackIndex) {
        dsMeta.hidden = this.hiddens.unshift();
      }
    }
  },

  calculateBarY: function (index, datasetIndex) {
    this.hideOtherStacks(datasetIndex);
    var barY = Chart.controllers.bar.prototype.calculateBarY.apply(this, [index, datasetIndex]);
    this.unhideOtherStacks(datasetIndex);
    return barY;
  },

  calculateBarBase: function (datasetIndex, index) {
    this.hideOtherStacks(datasetIndex);
    var barBase = Chart.controllers.bar.prototype.calculateBarBase.apply(this, [datasetIndex, index]);
    this.unhideOtherStacks(datasetIndex);
    return barBase;
  },

  getBarCount: function () {
    var stacks = [];

    // put the stack index in the dataset meta
    Chart.helpers.each(this.chart.data.datasets, function (dataset, datasetIndex) {
      var meta = this.chart.getDatasetMeta(datasetIndex);
      if (meta.bar && this.chart.isDatasetVisible(datasetIndex)) {
        var stackIndex = stacks.indexOf(dataset.stack);
        if (stackIndex === -1) {
          stackIndex = stacks.length;
          stacks.push(dataset.stack);
        }
        meta.stackIndex = stackIndex;
      }
    }, this);

    this.getMeta().stacks = stacks;
    return stacks.length;
  },
});

var data = {
  labels: ["January", "February", "March"],
  datasets: [
    {
      label: "Apples",
      backgroundColor: "rgba(99,255,132,0.2)",
      data: [20, 10, 30],
      stack: 1
    },
    {
      label: "Bananas",
      backgroundColor: "rgba(99,132,255,0.2)",
      data: [40, 50, 20],
      stack: 1
    },
    {
      label: "Cookies",
      backgroundColor: "rgba(255,99,132,0.2)",
      data: [60, 20, 20],
      stack: 1
    },
    {
      label: "Apples",
      backgroundColor: "rgba(99,255,132,0.2)",
      data: [20, 10, 30],
      stack: 2
    },
    {
      label: "Bananas",
      backgroundColor: "rgba(99,132,255,0.2)",
      data: [40, 50, 20],
      stack: 2
    },
    {
      label: "Cookies",
      backgroundColor: "rgba(255,99,132,0.2)",
      data: [60, 20, 20],
      stack: 2
    },
    {
      label: "Apples",
      backgroundColor: "rgba(99,255,132,0.2)",
      data: [20, 10, 30],
      stack: 3
    },
    {
      label: "Bananas",
      backgroundColor: "rgba(99,132,255,0.2)",
      data: [40, 50, 20],
      stack: 3
    },
    {
      label: "Cookies",
      backgroundColor: "rgba(255,99,132,0.2)",
      data: [60, 20, 20],
      stack: 3
    },
  ]
};

var ctx = document.getElementById("myChart").getContext("2d");
new Chart(ctx, {
  type: 'groupableBar',
  data: data,
  options: {
    legend: {
      labels: {
        generateLabels: function(chart) {
          return Chart.defaults.global.legend.labels.generateLabels.apply(this, [chart]).filter(function(item, i){
                return i <= 2;
          });
        }
      }
    },
    scales: {
      yAxes: [{
        ticks: {
          max: 160,
        },
        stacked: true,
      }]
    }
  }
});
like image 54
Tomas Javaišis Avatar answered Sep 25 '22 23:09

Tomas Javaišis