0

I've been trying to implement a Stacked Area Line Chart using Chart.js, which in turn uses multiple datasets as an input for each line graph.

Although I'am able to view the final stacked chart with the associated dataset, I can clearly notice that y-axis data is falsely represented(hover on data-point) w.r.t x-axis for each dataset, which is a major issue.

Major issues are:

  1. x-axis and y-axis mapping issue for 2nd dataset chart onwards
  2. x-axis values (dates) are repetitive and not in order - causes an abrupt display of chart

To be more clear, I need dataset1[ {x: "2030*08-03", y: 8},{}...] to precisely map keys x and y to the respective x-axis and y-axis of chart1, similary, dataset2[ {x: "2030*08-10", y: 8},{}...] mapping to the 2nd chart respectively and so on.

This is the sample codepen implementation replicating the issue.

Also, I'm adding the complete code snippet for a clear understanding.

var ctx = document.getElementById("myChart").getContext("2d");

const colors = {
      green: {
        fill: 'rgb(0,128,0,0.2)',
        stroke: 'green',
      },
      grey: {
        fill: 'rgb(128,128,128, 0.2)',
          stroke: 'grey',
      },
      red: {
        fill: 'rgba(255, 0, 0, 0.2)',
        stroke: 'red',
      }
};

const data1 = [
        {x: "2030*08-03", y: 8},
        {x: "2030-08-04", y: 1},
        {x: "2030-08-08", y: 2},
        {x: "2030-08-09", y: 10},
        {x: "2030-08-10", y: 2},
        {x: "2030-08-12", y: 34} ];
const data2 = [
        {x: "2030-08-09", y: 1},
        {x: "2030-08-12", y: 12},
        {x: "2030-08-13", y: 3},
        {x: "2030-08-15", y: 3}
];
const data3 = [
        {x: "2030-08-06", y: 1},
        {x: "2030-08-09", y: 12},
        {x: "2030-08-10", y: 3},
        {x: "2030-08-12", y: 3} , ];


const myChart = new Chart(ctx, {
  type: 'line',
  data: {
    datasets: [
      {
        label: "Data1",
        fill: true,
        backgroundColor: colors.green.fill,
        pointBackgroundColor: colors.green.stroke,
        borderColor: colors.green.stroke,
        pointHighlightStroke: colors.green.stroke,
        borderCapStyle: 'butt',
        data: data1,
      },
      {
        label: "Data2",
        fill: true,
        backgroundColor: colors.grey.fill,
        pointBackgroundColor: colors.grey.stroke,
        borderColor: colors.grey.stroke,
        pointHighlightStroke: colors.grey.stroke,
        data: data2,
      },
      {
        label: "Data3",
        fill: true,
        backgroundColor: colors.red.fill,
        pointBackgroundColor: colors.red.stroke,
        borderColor: colors.red.stroke,
        pointHighlightStroke: colors.red.stroke,
        data: data3,
       }
    ]
  },
  options: {
    plugins: {
      responsive: true,
      legend: {
        display: true,
        position: 'bottom',
      },
      title: {
        display: true,
        text: 'Status',
        padding: {
          top: 20,
          bottom: 15
        },
        font: {
          weight: "bold",
          size: 25
        }
      }
    },
    layout: {
      padding: {
        left: 20,
        right: 0,
        top: 0,
        bottom: 25
      }
    },
    scales: {
      x: {
        ticks: {
          align: "center"
        }
      },
      y: {
        stacked: true,
        title: {
          display: true,
          text: "Count",
          font: {
            weight: "bold",
            size: 20
          }
        }
      },
    },
    parsing: {
      xAxisKey: 'x',
      yAxisKey: 'y'
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.0/chart.min.js"></script>
<canvas id="myChart" width="400" height="200"></canvas>

Any help will be greatly appreciated. Thanks in advance.

1 Answer 1

2

This behaviour is happening because chart.js automatically adds the labels if they are not there and doesnt care about ordering, you have 2 ways of fixing it, providing a labels array with all the labels in correct order already:

var ctx = document.getElementById("myChart").getContext("2d");

const colors = {
  green: {
    fill: 'rgb(0,128,0,0.2)',
    stroke: 'green',
  },
  grey: {
    fill: 'rgb(128,128,128, 0.2)',
    stroke: 'grey',
  },
  red: {
    fill: 'rgba(255, 0, 0, 0.2)',
    stroke: 'red',
  }
};

const data1 = [{
    x: "2030-08-03",
    y: 8
  },
  {
    x: "2030-08-04",
    y: 1
  },
  {
    x: "2030-08-08",
    y: 2
  },
  {
    x: "2030-08-09",
    y: 10
  },
  {
    x: "2030-08-10",
    y: 2
  },
  {
    x: "2030-08-12",
    y: 34
  }
];
const data2 = [{
    x: "2030-08-09",
    y: 1
  },
  {
    x: "2030-08-12",
    y: 12
  },
  {
    x: "2030-08-13",
    y: 3
  },
  {
    x: "2030-08-15",
    y: 3
  }
];
const data3 = [{
    x: "2030-08-06",
    y: 1
  },
  {
    x: "2030-08-09",
    y: 12
  },
  {
    x: "2030-08-10",
    y: 3
  },
  {
    x: "2030-08-12",
    y: 3
  },
];


const myChart = new Chart(ctx, {
  type: 'line',
  data: {
    labels: ["2030-08-03", "2030-08-04", "2030-08-06", "2030-08-08", "2030-08-09", "2030-08-10", "2030-08-12", "2030-08-13", "2030-08-15"],
    datasets: [{
        label: "Data1",
        fill: true,
        backgroundColor: colors.green.fill,
        pointBackgroundColor: colors.green.stroke,
        borderColor: colors.green.stroke,
        pointHighlightStroke: colors.green.stroke,
        borderCapStyle: 'butt',
        data: data1,
      },
      {
        label: "Data2",
        fill: true,
        backgroundColor: colors.grey.fill,
        pointBackgroundColor: colors.grey.stroke,
        borderColor: colors.grey.stroke,
        pointHighlightStroke: colors.grey.stroke,
        data: data2,
      },
      {
        label: "Data3",
        fill: true,
        backgroundColor: colors.red.fill,
        pointBackgroundColor: colors.red.stroke,
        borderColor: colors.red.stroke,
        pointHighlightStroke: colors.red.stroke,
        data: data3,
      }
    ]
  },
  options: {
    plugins: {
      responsive: true,
      legend: {
        display: true,
        position: 'bottom',
      },
      title: {
        display: true,
        text: 'Status',
        padding: {
          top: 20,
          bottom: 15
        },
        font: {
          weight: "bold",
          size: 25
        }
      }
    },
    layout: {
      padding: {
        left: 20,
        right: 0,
        top: 0,
        bottom: 25
      }
    },
    scales: {
      x: {
        ticks: {
          align: "center"
        }
      },
      y: {
        stacked: true,
        title: {
          display: true,
          text: "Count",
          font: {
            weight: "bold",
            size: 20
          }
        }
      },
    },
    parsing: {
      xAxisKey: 'x',
      yAxisKey: 'y'
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.0/chart.min.js"></script>
<canvas id="myChart" width="400" height="100"></canvas>

Codepen: https://codepen.io/leelenaleee/pen/gOWNXKm?editors=1010

Or you can use a time axis:

var ctx = document.getElementById("myChart").getContext("2d");

const colors = {
  green: {
    fill: 'rgb(0,128,0,0.2)',
    stroke: 'green',
  },
  grey: {
    fill: 'rgb(128,128,128, 0.2)',
    stroke: 'grey',
  },
  red: {
    fill: 'rgba(255, 0, 0, 0.2)',
    stroke: 'red',
  }
};

const data1 = [{
    x: "2030-08-03",
    y: 8
  },
  {
    x: "2030-08-04",
    y: 1
  },
  {
    x: "2030-08-08",
    y: 2
  },
  {
    x: "2030-08-09",
    y: 10
  },
  {
    x: "2030-08-10",
    y: 2
  },
  {
    x: "2030-08-12",
    y: 34
  }
];
const data2 = [{
    x: "2030-08-09",
    y: 1
  },
  {
    x: "2030-08-12",
    y: 12
  },
  {
    x: "2030-08-13",
    y: 3
  },
  {
    x: "2030-08-15",
    y: 3
  }
];
const data3 = [{
    x: "2030-08-06",
    y: 1
  },
  {
    x: "2030-08-09",
    y: 12
  },
  {
    x: "2030-08-10",
    y: 3
  },
  {
    x: "2030-08-12",
    y: 3
  },
];


const myChart = new Chart(ctx, {
  type: 'line',
  data: {
    datasets: [{
        label: "Data1",
        fill: true,
        backgroundColor: colors.green.fill,
        pointBackgroundColor: colors.green.stroke,
        borderColor: colors.green.stroke,
        pointHighlightStroke: colors.green.stroke,
        borderCapStyle: 'butt',
        data: data1,
      },
      {
        label: "Data2",
        fill: true,
        backgroundColor: colors.grey.fill,
        pointBackgroundColor: colors.grey.stroke,
        borderColor: colors.grey.stroke,
        pointHighlightStroke: colors.grey.stroke,
        data: data2,
      },
      {
        label: "Data3",
        fill: true,
        backgroundColor: colors.red.fill,
        pointBackgroundColor: colors.red.stroke,
        borderColor: colors.red.stroke,
        pointHighlightStroke: colors.red.stroke,
        data: data3,
      }
    ]
  },
  options: {
    plugins: {
      responsive: true,
      legend: {
        display: true,
        position: 'bottom',
      },
      title: {
        display: true,
        text: 'Status',
        padding: {
          top: 20,
          bottom: 15
        },
        font: {
          weight: "bold",
          size: 25
        }
      }
    },
    layout: {
      padding: {
        left: 20,
        right: 0,
        top: 0,
        bottom: 25
      }
    },
    scales: {
      x: {
        type: 'time',
        ticks: {
          align: "center"
        }
      },
      y: {
        stacked: true,
        title: {
          display: true,
          text: "Count",
          font: {
            weight: "bold",
            size: 20
          }
        }
      },
    },
    parsing: {
      xAxisKey: 'x',
      yAxisKey: 'y'
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.0/chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
<canvas id="myChart" width="400" height="100"></canvas>

Codepen: https://codepen.io/leelenaleee/pen/GRmbOxN?editors=1010

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you Lee for the efforts. I've had the workaround implementation done the same way as your first approach: Providing all labels ordered in a Label array. Just wanted to learn about a better technique which automatically maps [{x,y}..{}] to x-axis and y-axis for each dataset defined. - Second approach. However, in both the simulation implementation you've shared, only Data1 has a proper mapping of datapoints, whereas, Data2 and Data3 have false y-axis datapoints representation (you can notice in the tooltip). It would be great if you could look into it and let me know. Thanks
They do represent correctly, because you tell chart.js to stack the y axis it stacks the line on top of the last one so if first point that is drawn has a value of 12 and the second a value of 3, the 3 gets drawn 3 spaces higher because you want it stacked so it draws it at the 15 mark, if you dont want this behaviour your should not use a stacked y axis
Thank you for the clarification Lee. Stacked - y-axis was not the result I'm expecting, so removed the "stacked y-axis" option and works perfectly as per my requirement. Thanks again.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.