2

我有下面的图表,其中我有一条“范围”线和“完成的总努力”线以及它们每个的虚线趋势线。(由于 Highcharts 不支持趋势线,我只是用虚线连接数据的第一个和最后一个点。)我正在使用这个插件来绘制趋势线。

目标是扩展虚线趋势线并找到这两条线将在右侧相遇的日期(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;
            })()
        }]
    });
});
4

3 回答 3

2

答案取决于几件事......

简短的回答:不,没有直接和简单的方法来预测使用 Highcharts API。

此外,基于这两条线的这种性质的预测,它们的方式,在现实中将完全没有用 - 这些趋势线不是基于任何统计数据,然后你在数据之上进行推断。 ..

为了获得有用的趋势指标,您需要对每个数据集进行线性回归分析,并使用斜率和截距来计算趋势线 ( http://en.wikipedia.org/wiki/Linear_regression )。

您可以使用相同的结果来预测这两条趋势线何时相交。但是 - 在绝大多数情况下,这不会给你任何准确的预测。

为了获得准确的预测,您需要考虑各种因素的算法:历史表现、季节性趋势、任意数量的控制变量、当前和预期条件等。

tl;博士:

从你所拥有的东西中计算你所要求的东西所需的数学是复杂的,并且不会给你任何有用的东西。

于 2013-09-17T12:50:46.237 回答
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 为图书馆提供了基础的示例!

于 2013-09-29T15:52:20.730 回答
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'

        }]
    });
});

我相信这适用于线条不平行的任何情况。

这是小提琴:http: //jsfiddle.net/VRf3n/

于 2013-09-17T13:09:41.770 回答