4

Examples within. For reference, I am using the latest version of ChartJS (3.2.1) and the latest version of react-chartjs-2 (3.0.3).

I want to know how to make my bar chart display in a specific way given multiple, varying datasets. I'd like for the bars on the chart to render at their standard widths, while also allowing side-by-side overlapping where necessary.

ChartJS will handle this in my "ideal" way when you're using one dataset which may have two values that fall on the same X-Axis coordinate, but I can't seem to mimic this behavior when using multiple datasets.

It seems as though whenever two datasets share an axis, the bar widths either adjust to accommodate both sets of data even if they don't occupy the same space, or they stack on top of one another when should they occupy the same space. My goal is to only have the bars "shrink" their width when necessary, and keep their full-width otherwise.

Here is an example of what I would like to see with multiple datasets (this is how ChartJS handles the rendering when there is one dataset with barThickness: "flex" set):

In the middle, you'll notice the bar widths automatically adjusted to make room for one another. ChartJS bar widths, single dataset

Here is an example of what I get when I use two datasets that do not have any points where they overlap (barThickness: "flex" is set on both): ChartJS bar widths, multiple datasets

And, lastly, here is an example with some points of overlap when using two datasets: enter image description here

So far the only way I've even sniffed a way around this is by creating multiple x-axes, one for one dataset, one for the other, and one for overlap. Then, by manipulating my data structures, creating datasets for each axis that contain exactly the datapoints that correspond to the desired bar widths.

That's certainly a solution, but I am dealing with a production codebase, thousands of rows of data, and several additional datasets (all of which have varying states, conditions for visibility, and rules). It becomes next-to-impossible to manage all of them together like this, let alone in a maintainable way. I've gone through the vast majority of StackOverflow questions and ChartJS documentation trying to find a cleaner solution, but have come up short thus far and would appreciate your help.

A simplified version of the code below. I've included some unused bits and pieces (mostly commented out) just to show the things I've tried thus far:

var ctx1 = document.getElementById("canvas1").getContext("2d");
var ctx2 = document.getElementById("canvas2").getContext("2d");
var ctx3 = document.getElementById("canvas3").getContext("2d");

function getBackgroundColor(data) {
  const bar = data.dataset.data[data.dataIndex];
  return bar.projection ? "green" : "black";
}
const dataset1Labels = ['Mar 2021', 'Apr 2021', 'May 2021', 'Jun 2021', 'Jul 2021', 'Aug 2021']
const dataset2Labels = ['Jan 2020', 'Feb 2020', 'Mar 2020', 'Apr 2020', ...dataset1Labels]
const dataset3Labels = ['Jan 2020', 'Feb 2020', 'Mar 2020', 'Apr 2020', 'May 2020', 'Jun 2020', 'Jul 2020', 'Aug 2020', ...dataset1Labels]

const dataset1 = [
  { x: "Mar 2021", y: 1, projection: false },
  { x: "Apr 2021", y: 4, projection: false },
  { x: "May 2021", y: 6, projection: false },
  { x: "May 2021", y: 9, projection: true },
  { x: "Jun 2021", y: 11, projection: true },
  { x: "Jul 2021", y: 13, projection: true },
  { x: "Aug 2021", y: 16, projection: true },
]
const dataset2 = [
  { x: "Jan 2020", y: 1 },
  { x: "Feb 2020", y: 4 },
  { x: "Mar 2020", y: 6 },
  { x: "Apr 2020", y: 8 },
  { x: "Mar 2021", y: 6 },
  { x: "Apr 2021", y: 8 },
]

const dataset3 = [
  { x: "Jan 2020", y: 1 },
  { x: "Feb 2020", y: 4 },
  { x: "Mar 2020", y: 6 },
  { x: "Apr 2020", y: 8 },
  { x: "May 2020", y: 10 },
  { x: "Jun 2020", y: 12 },
  { x: "Jul 2020", y: 12 },
  { x: "Aug 2020", y: 16 },
  { x: "Mar 2021", y: 1 },
  { x: "Apr 2021", y: 4 },
  { x: "May 2021", y: 6 },
]

var myChart = new Chart(ctx1, {
  type: 'bar',
  data: {
    labels: dataset1Labels,
    datasets: [{
      label: "2 data types, distinguished by color",
      data: dataset1,
      backgroundColor: getBackgroundColor,
      barThickness: "flex",
    }]
  },
  options: {
    plugins: {
      title: {
        display: true,
        text: '1 dataset. Can Overlap. Full width bars.'
      },
      legend: {
        position: "bottom",
      },
    },
    scales: {
      x: {
        id: "dates",
        offset: true,
      },
    }
  }
});

var myChart2 = new Chart(ctx2, {
  type: 'bar',
  data: {
    labels: dataset2Labels,
    datasets: [
    {
      label: "previous year",
      data: dataset2,
      backgroundColor: "blue",
      xAxisID: "dates",

    },
    {
      label: "current year",
      data: dataset1,
      backgroundColor: "green",
    },
  ]},
  options: {
    plugins: {
      title: {
        display: true,
        text: '2 datasets. Cannot Overlap. Full width bars.'
      },
      legend: {
        position: "bottom",
      },
    },
    scales: {
      x: {
        id: "dates2",
        display: false,
        stacked: false,
        bounds: "ticks",
        grid: {
          offset: true,
        },
      },
    }
  }
});

var myChart3 = new Chart(ctx3, {
  type: 'bar',
  data: {
    labels: dataset3Labels,
    datasets: [
    {
      label: "previous year",
      data: dataset3,
      backgroundColor: "blue",
      // group: false,
      // barThickness: "flex",
      // categoryPercentage: 1,
      // barPercentage: 1,
    },
    {
      label: "current year",
      data: dataset1,
      backgroundColor: "green",
      // group: false,
      // categoryPercentage: 1,
      // barThickness: "flex",
      // barPercentage: 1,
    },
  ]},
  options: {
    plugins: {
      title: {
        display: true,
        text: '2 datasets. Can overlap. Half-width bars.'
      },
      legend: {
        position: "bottom",
      },
    },
    scales: {
      x: {
        id: "dates3",
        display: false,
        grid: {
          offset: true,
        },
      },
    }
  }
});
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.2.1/dist/chart.min.js"></script>
<h2>Chart #1</h2>
<canvas id="canvas1"></canvas>
<h2>Chart #2</h2>
<p>Note that March and April 2021 both have data from both datasets, but only one dataset is visible</p>
<canvas id="canvas2"></canvas>
<h2>Chart #3</h2>
<canvas id="canvas3"></canvas>

0 Answers0