[Chartjs]-ChartJS: Mapping Non numeric Y and X

7πŸ‘

βœ…

In order to use a category scale for both the X and Y axis, you must use the traditional data format of an array of values. Per the chart.js api docs…

Scatter line charts can be created by changing the X axis to a linear axis. To use a scatter chart, data must be passed as objects containing X and Y properties

This implies that you can only use the data format {x: ' ', y: ' '} when at least the X axis is a linear scale (but I’m betting it only works if both the X and Y axis are linear).

Since you are limited to only using an array of values for your data, you must use at least 2 datasets in order to plot multiple values on the X axis (like what you are trying to do).

Here is a chart configuration that gives what you are looking for.

var ctx = document.getElementById("canvas").getContext("2d");
var myLine = new Chart(ctx, {
  type: 'line',
  data: {
    xLabels: ["January", "February", "March", "April", "May", "June", "July"],
    yLabels: ['Request Added', 'Request Viewed', 'Request Accepted', 'Request Solved', 'Solving Confirmed'],
    datasets: [{
      label: "My First dataset",
      data: ['Request Added', 'Request Viewed', 'Request Added'],
      fill: false,
      showLine: false,
      borderColor: chartColors.red,
      backgroundColor: chartColors.red
    }, {
      label: "My First dataset",
      data: [null, 'Request Accepted', 'Request Accepted'],
      fill: false,
      showLine: false,
      borderColor: chartColors.red,
      backgroundColor: chartColors.red
    }]
  },
  options: {
    responsive: true,
    title:{
      display: true,
      text: 'Chart.js - Non Numeric X and Y Axis'
    },
    legend: {
      display: false
    },
    scales: {
      xAxes: [{
        display: true,
        scaleLabel: {
          display: true,
          labelString: 'Month'
        }
      }],
      yAxes: [{
        type: 'category',
        position: 'left',
        display: true,
        scaleLabel: {
          display: true,
          labelString: 'Request State'
        },
        ticks: {
          reverse: true
        },
      }]
    }
  }
});

You can see what it looks like from this codepen.

If you are for whatever reason tied to using the {x: ' ', y: ' '} dataformat, then you will have to change both your scales to linear, map your data to numerical values, then use the ticks.callback property to map your numerical ticks back to string values.

Here is an example that demonstrates this approach.

var xMap = ["January", "February", "March", "April", "May", "June", "July"];
var yMap = ['Request Added', 'Request Viewed', 'Request Accepted', 'Request Solved', 'Solving Confirmed'];

var mapDataPoint = function(xValue, yValue) {
  return {
    x: xMap.indexOf(xValue),
    y: yMap.indexOf(yValue)
  };
};

var ctx2 = document.getElementById("canvas2").getContext("2d");
var myLine2 = new Chart(ctx2, {
  type: 'line',
  data: {
    datasets: [{
      label: "My First dataset",
      data: [
        mapDataPoint("January", "Request Added"),
        mapDataPoint("February", "Request Viewed"),
        mapDataPoint("February", "Request Accepted"),
        mapDataPoint("March", "Request Added"),
        mapDataPoint("March", "Request Accepted"),
      ],
      fill: false,
      showLine: false,
      borderColor: chartColors.red,
      backgroundColor: chartColors.red
    }]
  },
  options: {
    responsive: true,
    title: {
      display: true,
      text: 'Chart.js - Scatter Chart Mapping X and Y to Non Numeric'
    },
    legend: {
      display: false
    },
    scales: {
      xAxes: [{
        type: 'linear',
        position: 'bottom',
        scaleLabel: {
          display: true,
          labelString: 'Month'
        },
        ticks: {
          min: 0,
          max: xMap.length - 1,
          callback: function(value) {
            return xMap[value];
          },
        },
      }],
      yAxes: [{
        scaleLabel: {
          display: true,
          labelString: 'Request State'
        },
        ticks: {
          reverse: true,
          min: 0,
          max: yMap.length - 1,
          callback: function(value) {
            return yMap[value];
          },
        },
      }]
    }
  }
});

You can see this in action at the same codepen.

Leave a comment