Search code examples
javascriptdata-visualizationscatter-plotcanvasjstrend

How to add a line of best fit (trendline) to a scatter plot in CanvasJS?


I have scatter graph which contains a lot of data, too much to display to a user. I would like to add a line of best fit or 'trendline' to the graph to show the trend and make the scatter plots invisible. My data is stored in an external JSON file in the format:

{
    "X" : [1,2,3,4,5,6,7,8,9...],
    "Y" : [1,2,3,4,5,6,7,8,9...]
}

And I am displaying my data using this code:

function addData(data){
  console.log("Adding data");
  var gradeMaxLength = 0; 

  for( var i = 0; i < data.length; i++ ){
    if( gradeMaxLength < data[i].grade.length ){
      gradeMaxLength = data[i].grade.length;
    }
  }

  // addding datSeries
  for( var j = 0; j < gradeMaxLength; j++ ){
    chart.options.data.push({
      type:"scatter",
      dataPoints:[]
    });
  }

  // adding dataPoints
  for( var k = 0; k < data.length; k++ ){
    for( var l = 0; l < gradeMaxLength; l++ ){
      chart.options.data[l].dataPoints.push({
        x: data[k].present[l],
        y: data[k].grade[l]
      }
    );
  }
}
chart.render();
}

Is there a way I can add a line of best fit to my graph, of which I have included a photo of below?

Graph


Solution

  • For canvasJS you could use this piece of code. I use it for myself for a while now but it works perfectly!

    Add this after your chart.render();

        calculateTrendLine(chart);
        function calculateTrendLine(chart){
            var a, b, c, d, e, slope, yIntercept;
            var xSum = 0, ySum = 0, xySum = 0, xSquare = 0, dpsLength = chart.data[0].dataPoints.length;
            for(var i = 0; i < dpsLength; i++)
                xySum += (chart.data[0].dataPoints[i].x * chart.data[0].dataPoints[i].y)
            a = xySum * dpsLength;
    
            for(var i = 0; i < dpsLength; i++){
                xSum += chart.data[0].dataPoints[i].x;
                ySum += chart.data[0].dataPoints[i].y;
            }
            b = xSum * ySum;
    
            for(var i = 0; i < dpsLength; i++)
                xSquare += Math.pow(chart.data[0].dataPoints[i].x, 2);
            c = dpsLength * xSquare;
    
            d = Math.pow(xSum, 2);
            slope = (a-b)/(c-d);
            e = slope * xSum;
            yIntercept = (ySum - e) / dpsLength;
    
            var startPoint = getTrendLinePoint(chart.data[0].dataPoints[0].x, slope, yIntercept);
            var endPoint = getTrendLinePoint(chart.data[0].dataPoints[dpsLength-1].x, slope, yIntercept);
    
            chart.addTo("data",{
                type: "line", //Line series showing trend
                markerSize: 0,
                dataPoints: [startPoint, endPoint]
            });
        }
    
        function getTrendLinePoint(x, slope, intercept){
            return {x: x, y: ((slope * x) + intercept)};
        }