chart.js

Stacked bar chart with multiple bars of the same type in each stack


I'm trying to recreate the top graph in chartjs. The one at the bottom is my attempt using a bar chart in chartjs.How to recreate the top graph in chartjs. Bottom graph is my attempt in chartjs

I don't know how I can add multiple good and bad bars on each row. Furthermore, each bar needs a tooltip.

// my attempt at creating this in chartjs
const config = {
    type: 'bar',
    data: {
        labels: ['stream 1', 'stream 2', ... ],
        datasets: [
            {
                label: 'good',
                data: [[x1, x2], ...],
            },
            {
                label: 'bad',
                data: [[x1, x2], ...],
            },
        ],
    },
    options: {
        indexAxis: 'y',
        scales: { x: { type: 'time', min: minTime, max: maxTime }, y: { stacked: true } },
    },
};

Ideally I can pass in data like this

// Ideally I can pass in data like this 
[{
    "name": "Good",
    "data": [
        {
            "x1": x1,
            "x2": x2,
            "y": streamIndex,
        }, ...
    ]
},
{
    "name": "Bad",
    "data": [
        {
            "x1": x1,
            "x2": x2,
            "y": streamIndex,
        }, ...
    ],
}]

I also tried recreating it using scatter graph with showLines: true and null in the data where I don't want the points to connect with a line. But with this approach I'm having trouble getting the tooltip to show at the correct time for the lines. As it's actually a scatter graph I can get the tool tip to show for the nearest point but I need it to show for the whole line without having the tooltip jump from the start of the line to the end of the line as I move the cursor. Plus there are can be two points at the exact same point making it hard to figure which point to show in the tooltip.

Is it possible to recreate the first graph in chartjs?


Solution

  • The data point format should be:

    {x: [110, 150], y: 'stream 1'}
    

    to draw a bar at y = 'stream 1', starting at x = 110 and ending at x = 150, see object in Data structures docs section, and floating bars example. Using the y axis index instead of the actual category label won't work (although one would expect it to from the documentation).

    Here's an example:

    const data = {
       labels: ['stream 1', 'stream 2'],
       datasets: [
          {
             label: 'good',
             data: [
                {x: [0, 50], y: 'stream 1'}, 
                {x: [110, 150], y: 'stream 1'}, 
                {x: [0, 100], y: 'stream 2'}
             ],
          },
          {
             label: 'bad',
             data: [
                {x: [60, 100], y: 'stream 1'}, 
                {x: [160, 200], y: 'stream 1'}, 
                {x: [110, 200], y: 'stream 2'}
             ],
          },
       ],
    };
    
    const options = {
       indexAxis: 'y',
       responsive: true,
       grouped: false,
       maintainAspectRatio: false,
       plugins: {
          legend: {
             display: true,
          },
       }
    };
    
    new Chart('barChart', {
       type: 'bar',
       data: data,
       options: options,
    });
    <div style="height:150px">
    <canvas id="barChart"></canvas>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>

    And a similar example with an x axis of type: "time": fiddle