我有下面的图表,其中我有一个'Scope'行和'Total Effort Done'行和每个点的渐变趋势线。 (由于Highcharts不支持趋势线,我只是用虚线连接数据的第一个和最后一个点。)我正在使用this plugin作为趋势线。
目标是扩展虚线趋势线并找到这两条线在右侧相交的日期(x轴值)(如果可能且不太远)。我怎么能这样做?
代码:http://jsfiddle.net/AjJZD/6/
$(function () {
var data1 = [
[Date.UTC(2013, 4, 28), 40],
[Date.UTC(2013, 5, 26), 40],
[Date.UTC(2013, 5, 29), 48],
[Date.UTC(2013, 7, 21), 48]
];
var data2 = [
[Date.UTC(2013, 4, 28), 0],
[Date.UTC(2013, 5, 10), 20],
[Date.UTC(2013, 5, 19), 22],
[Date.UTC(2013, 5, 20), 24],
[Date.UTC(2013, 5, 30), 26],
[Date.UTC(2013, 6, 1), 28],
[Date.UTC(2013, 7, 21), 30]
];
var chart_linear = new Highcharts.Chart({
chart: {
renderTo: 'container'
},
colors: ['#912120', '#C00402', '#115DA9', '#115DA9'],
xAxis: {
type: 'datetime',
gridLineWidth: 1,
gridLineDashStyle: 'shortdot'
},
yAxis: {
min: 0,
gridLineDashStyle: 'shortdot'
},
plotOptions: {
series: {
marker: {
symbol: 'circle'
}
}
},
series: [{
name: 'Scope',
data: data1
}, {
name: 'Scope Change Trend',
type: 'line',
marker: {
enabled: false
},
dashStyle: 'longDash',
data: (function () {
return fitData(data1).data;
})()
}, {
name: 'Total Effort Done',
data: data2
}, {
name: 'Velocity',
type: 'line',
marker: {
enabled: false
},
dashStyle: 'longDash',
data: (function () {
return fitData(data2).data;
})()
}]
});
});
答案 0 :(得分:2)
答案取决于一些事情......
简短的回答:不,没有一种直接而简单的方法来预测使用Highcharts API。
此外,基于这两条线的这种性质的预测,它们的方式,在现实中将是完全无用的 - 那些趋势线不是基于任何统计,然后你推断超出顶部的数据那... ...
为了获得有用的趋势指标,您需要对每个数据集运行线性回归分析,并使用斜率和截距来计算趋势线(http://en.wikipedia.org/wiki/Linear_regression)。
您可以使用相同的结果来预测这两条趋势线何时相交。 但是,在绝大多数情况下,不会给你任何准确的预测。
要获得准确的预测,您需要考虑各种因素的算法:历史性能,季节性趋势,任意数量的控制变量,当前和预期条件等。
TL; DR:
从你所拥有的东西中计算你所要求的东西所需的数学是复杂的,并且不会给你任何有用的东西。
答案 1 :(得分:2)
感谢另外两个答案(尤其是John Kiernander),我编写了自己的名为'line_intersection.js'的库,它提供了一个函数来查找两条直线的交集,并提供了一个从图表中生成趋势线的函数数据
使用该库的getTrendlineData和getLineIntersectionData函数,您可以执行以下操作
代码:
jQuery(function () {
var data1 = [
[Date.UTC(2013, 0, 1), 50],
[Date.UTC(2013, 0, 2), 58],
[Date.UTC(2013, 0, 3), 58],
[Date.UTC(2013, 0, 4), 58]
];
var data2 = [
[Date.UTC(2013, 0, 1), 0],
[Date.UTC(2013, 0, 2), 12],
[Date.UTC(2013, 0, 3), 18],
[Date.UTC(2013, 0, 4), 22]
];
var data1_t = getTrendlineData(data1).data;
var data2_t = getTrendlineData(data2).data;
var options = {
icptPoint: {
//name: 'Possible release date',
marker: {
enabled: true,
fillColor: '#003300',
lineColor: '#003300'
}
},
validateIntersection: function(icptX, icptY) {
// Don't connect the lines if the intersection point is
// to the left of the chart
if (icptX < data1_t[0][0] || icptX < data2_t[0][0]) {
return false;
}
}
};
var forecast = getLineIntersectionData(data1_t, data2_t, options);
var chart_linear = new Highcharts.Chart({
chart: {
renderTo: 'container'
},
colors: ['#990000', '#4679BD', '#990000', '#4679BD'],
xAxis: {
type: 'datetime',
gridLineWidth: 1,
gridLineDashStyle: 'shortdot'
},
yAxis: {
min: 0,
gridLineDashStyle: 'shortdot'
},
title: {
text: 'Estimating release date'
},
series: [{
name: 'Total issues',
data: data1
}, {
name: 'Closed issues',
data: data2
}, {
name: 'Total issues trend',
//getLineIntersectionData() may return undefined if lines can not intersect
data: forecast && forecast.line1_data || data1_t,
marker: {
enabled: false
},
dashStyle: 'longDash'
}, {
name: 'Closed issues trend',
data: forecast && forecast.line2_data || data2_t,
marker: {
enabled: false
},
dashStyle: 'longDash',
}]
});
输出:
现场演示:http://vigneshwaranr.github.io/line_intersection.js/demo.html
非常感谢John Kiernander为图书馆提供基础的例子!
答案 2 :(得分:1)
我决定进一步考虑我的计算并将它们应用到您的测试用例中。这是代码,它将回答您原来的问题:
$(function () {
var scope = [
[Date.UTC(2013, 4, 28), 40],
[Date.UTC(2013, 5, 26), 40],
[Date.UTC(2013, 5, 29), 48],
[Date.UTC(2013, 7, 21), 48]
],
effort = [
[Date.UTC(2013, 4, 28), 0],
[Date.UTC(2013, 5, 10), 20],
[Date.UTC(2013, 5, 19), 22],
[Date.UTC(2013, 5, 20), 24],
[Date.UTC(2013, 5, 30), 26],
[Date.UTC(2013, 6, 1), 28],
[Date.UTC(2013, 7, 21), 30]
],
// Change in X for scope
scopeDX = (scope[scope.length - 1][0] - scope[0][0]),
// Change in Y for scope
scopeDY = (scope[scope.length - 1][1] - scope[0][1]),
// Change in X for effort
effortDX = (effort[effort.length - 1][0] - effort[0][0]),
// Change in Y for effort
effortDY = (effort[effort.length - 1][1] - effort[0][1]),
// Slope for scope
scopeG = scopeDY / scopeDX,
// Slope for effort
effortG = effortDY / effortDX,
// Intercept for scope
scopeI = scope[0][1] - scopeG * scope[0][0],
// Intercept for effort
effortI = effort[0][1] - effortG * effort[0][0],
// X Coordinate for the intersection
icptX = -1 * (scopeI - effortI) / (scopeG - effortG),
// Y Coordinate for the intersection
icptY = scopeG * icptX + scopeI;
$('#container').highcharts({
chart: {},
colors: [ '#912120', '#C00402', '#115DA9', '#115DA9' ],
xAxis: {
type: 'datetime',
gridLineWidth: 1,
gridLineDashStyle: 'shortdot'
},
yAxis: {
min: 0,
gridLineDashStyle: 'shortdot'
},
plotOptions: {
series: {
marker: {
symbol: 'circle'
}
}
},
series: [{
name: 'Scope',
data: scope
}, {
name: 'Scope Change Trend',
data: [
[scope[0][0], scope[0][1]],
[scope[scope.length - 1][0], scope[scope.length - 1][1]],
[icptX, icptY]
],
dashStyle: 'longDash'
}, {
name: 'Total Effort Done',
data: effort
}, {
name: 'Velocity',
data: [
[effort[0][0], effort[0][1]],
[effort[effort.length - 1][0], effort[effort.length - 1][1]],
[icptX, icptY]
],
dashStyle: 'longDash'
}]
});
});
我相信这适用于线条不平行的任何情况。