Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
215 views
in Technique[技术] by (71.8m points)

javascript - How to create an average line for an irregular time graph?

I'm building irregular time graphs with HighCharts that at the moment look like so:

graph

And I'm wondering if it's possible to create an 'average' line for the three (or possibly more in future) lines.

It would start following the blue line, then go closer to the green line mid-January, etc.

At the moment the code I'm working with looks like:

$('#chart').highcharts({
  chart: { type: 'spline' },
  title: { text: '' },
  xAxis: { type: 'datetime' },
  yAxis: {
    title: { text: '' }
  }
  series: [{
    name: 'Line 1',
    data: [
      [Date.UTC(2014,0,16), 173.33],
      [Date.UTC(2014,0,23), 163.33],
      [Date.UTC(2014,0,30), 137.67],
      [Date.UTC(2014,1,6), 176.33],
      [Date.UTC(2014,1,13), 178.67],
      [Date.UTC(2014,1,27), 167.33],
    ],
    color: 'purple'
  },
  {
    name: 'Line 2',
    data: [
      [Date.UTC(2014,0,11), 156.33],
      [Date.UTC(2014,1,15), 167.67],
    ],
    color: 'green'
  },
  {
    name: 'Line 3',
    data: [
      [Date.UTC(2014,0,1), 135],
      [Date.UTC(2014,0,5), 146.33],
      [Date.UTC(2014,0,27), 146.75],
    ],
    color: 'blue'
  }]
});
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

What you are describing is called a trend or regression line. Highcharts doesn't have a built in ability to add these lines, but the math isn't too difficult (and besides, it's more fun to do it yourself). I've coded up the simplest example I can using least squared linear regression.

/////////////////////
//utility functions//
////////////////////
// linear regression
// given array of x values and array of y values
// returns rV object with slope/intercept
lineFit = function(xs, ys, rV){
    rV.slope = 0.0;
    rV.intercept = 0.0;
    rV.rSquared = 1.0; // assume perfection

    if (xs.length < 2)
    {
        return false;
    }

    if (xs.Count != ys.Count)
    {
        return false;
    }

    var N = xs.length;
    var sumX = sumFunc(xs,null);
    var sumY = sumFunc(ys,null);
    var funcSq = function(i){return (i*i);}
    var funcSq2 = function(i,j){return (i*j);}
    var sumXx = sumFunc(xs, funcSq);
    var sumYy = sumFunc(ys, funcSq);
    var sumXy = sumFunc(zip(xs,ys),funcSq2); 

    rV.slope = ((N * sumXy) - (sumX * sumY)) / (N * sumXx - (sumX*sumX));
    rV.intercept = (sumY - rV.slope * sumX) / N;
    rV.rSquared = Math.abs((rV.slope * (sumXy - (sumX * sumY) / N)) / (sumYy - ((sumY * sumY) / N)));
    return true;
}   

// sums arrays with optional function transformation
sumFunc = function(arr, func){
    var total = 0;
    $.each(arr, function(i,k){
        if ($.isArray(k)){
            if (func == null){
                k = k[0] + k[1];
            }else{                
                k = func(k[0],k[1]);
            }
        } else {
            if (func != null){
                k = func(k);
            }
        }
        total += k;
    });
    return total;
}

// python style zip function
// to pair to array together
zip = function(arr1,arr2) {
    var rV = [];
    for(var i=0; i<arr1.length; i++){
       rV.push([arr1[i],arr2[i]]);
    }
    return rV;
}

The lineFit function will return the rV object (by reference) with attributes of slope and intercept. After that you can add a line to Highcharts with good old fashioned y = slope * x + intercept and minX is the starting value for the regression line and maxX is the ending value.

 {
    name: 'Regression Line',
    data: [[minX, reg.slope * minX + reg.intercept], 
           [maxX, reg.slope * maxX + reg.intercept]],
    color: 'red',
    marker:{enabled:false},
    lineWidth: 5
  }

Working fiddle here.

enter image description here


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...