Mohamed Taboubi
Mohamed Taboubi

Reputation: 7011

Not drawing null values using chart.js

I'm using Chart.js to draw a chart.. My dataset have some null values, Actually chart.js plot a line between points that are previous and successor of the null values in this way :

enter image description here

The red arrow indicate where are the null values

I want to find how can I not plot these null values enter image description here

The configuration I use is as simple as that :

var lineChartData = {
            "datasets": [{
                "label": "defi score",
                "data": data,
                "pointStrokeColor": "#fff",
                "fillColor": "rgba(220,220,220,0.5)",
                "pointColor": "rgba(220,220,220,1)",
                "strokeColor": "rgba(220,220,220,1)",
            }],
            "labels": labels
        };


        var ctx = document.getElementById("chart_per_week").getContext("2d");
        var myLine = new Chart(ctx).Line(lineChartData, {
            responsive: true,
            scaleFontColor: "#FF5972",
            bezierCurve: false
        });

Thank you for your help

Upvotes: 19

Views: 35546

Answers (4)

Selay
Selay

Reputation: 6464

In case you still reach this page, New version supports skipping missing data. . If you want the lines to be connected by skipping missing data, you can set spanGaps: true in the options.

Then if you have null or NaN for missing data, it will skip it and connect to the next point.

.....
 showTooltips: true,
        options: {
             spanGaps: true,
  ......

Documentation here

Upvotes: 37

Diesel
Diesel

Reputation: 5335

I know this is pretty old, but I think there is a better solution now. Replace all your null values with Number.NaN

http://www.chartjs.org/docs/#line-chart-chart-options

Below is a data point I replaced with NaN on the red line

Broken Line

Upvotes: 14

potatopeelings
potatopeelings

Reputation: 41075

Breaking (Broken) Lines using Chart.js

You can extend the line chart type to do this


Preview

enter image description here

Script

Chart.types.Line.extend({
  name: "LineAlt",
  initialize: function (data) {
    var fillColors = [];
    var strokeColors = [];
    data.datasets.forEach(function (dataset, i) {
      if (dataset.data.indexOf(null) !== -1) {
        fillColors.push(dataset.fillColor);
        strokeColors.push(dataset.strokeColor);
        dataset.fillColor = "rgba(0,0,0,0)"
        dataset.strokeColor = "rgba(0,0,0,0)"
      }
    })

    Chart.types.Line.prototype.initialize.apply(this, arguments);

    var self = this;
    data.datasets.forEach(function (dataset, i) {
      if (dataset.data.indexOf(null) !== -1) {
        self.datasets[i]._saved = {
          fillColor: fillColors.shift(),
          strokeColor: strokeColors.shift()
        }
      }
    })
  },
  draw: function () {
    Chart.types.Line.prototype.draw.apply(this, arguments);

    // from Chart.js library code
    var hasValue = function (point) {
      return point.value !== null;
    },
    nextPoint = function (point, collection, index) {
      return Chart.helpers.findNextWhere(collection, hasValue, index) || point;
    },
    previousPoint = function (point, collection, index) {
      return Chart.helpers.findPreviousWhere(collection, hasValue, index) || point;
    };

    var ctx = this.chart.ctx;
    var self = this;
    ctx.save();
    this.datasets.forEach(function (dataset) {
      if (dataset._saved) {
        ctx.lineWidth = self.options.datasetStrokeWidth;
        ctx.strokeStyle = dataset._saved.strokeColor;
        ctx.fillStyle = dataset._saved.fillColor;

        // adapted from Chart.js library code
        var pointsWithValues = Chart.helpers.where(dataset.points, hasValue);
        dataset.points.forEach(function (point, index) {
          if (index === 0 || (hasValue(point) && !hasValue(dataset.points[index - 1])))
            point.start = true;
        });
        var currentStartPoint = undefined;
        Chart.helpers.each(pointsWithValues, function (point, index) {
          if (point.start) {
            if (currentStartPoint) {
              ctx.lineTo(pointsWithValues[index - 1].x, self.scale.endPoint);
              ctx.lineTo(currentStartPoint.x, self.scale.endPoint);
              ctx.closePath();
              ctx.fill();
            }

            currentStartPoint = point;
            ctx.beginPath();
            ctx.moveTo(point.x, point.y);
          }
          else {
            if (self.options.bezierCurve) {
              var previous = previousPoint(point, pointsWithValues, index);
              ctx.bezierCurveTo(
                previous.controlPoints.outer.x,
                previous.controlPoints.outer.y,
                point.controlPoints.inner.x,
                point.controlPoints.inner.y,
                point.x,
                point.y
              );
            }
            else {
              ctx.lineTo(point.x, point.y);
            }
          }

          ctx.stroke();
        }, this);

        ctx.lineTo(pointsWithValues[pointsWithValues.length - 1].x, self.scale.endPoint);
        ctx.lineTo(currentStartPoint.x, self.scale.endPoint);
        ctx.closePath();
        ctx.fill();
      }
    })

    ctx.restore();
  }
});

and then

var data = {
    ...
    datasets: [
        {
            ...
            data: [65, 59, null, 81, 52, 62, null, 56, 40],
        }
    ],
};

...
new Chart(ctx).LineAlt(data);

Fiddle - https://jsfiddle.net/hbrhz2q4/

Upvotes: 8

S-Vuk
S-Vuk

Reputation: 369

I'm not sure if ChartJS itself can natively do this.

However one way I did something similar was to make the line graph out of multiple datasets. One dataset would end when a null value is reached, and the next dataset would start. This would of course requires parsing all this data before passing it into var linechartdata

You can make all the datasets have the same colors and highlights and the graph should render with spaces where null data would have been found.

Upvotes: 1

Related Questions