我使用(优秀的)D3创建了一个简单的折线图。它具有表示为水平红线的阈值。我想要做的是计算值线与阈值线相交的位置,如下所示:
我可以非常接近,因为我可以访问数据数组,但我需要非常准确,并且能够在各种规模上工作。如果有人可以提供帮助,我将非常感激。非常感谢。
<div id="chart"></div>
path.line { stroke-width: 2; fill: none; }
var data = [{
"time": "2014-02-25T19:00:00Z",
"temp": "39.08"
}, {
"time": "2014-02-25T21:00:00Z",
"temp": "39.51"
}, {
"time": "2014-02-25T23:00:00Z",
"temp": "39.14"
}, {
"time": "2014-02-26T01:00:00Z",
"temp": "40.79"
}, {
"time": "2014-02-26T03:00:00Z",
"temp": "41.17"
}, {
"time": "2014-02-26T05:00:00Z",
"temp": "40.39"
}, {
"time": "2014-02-26T07:00:00Z",
"temp": "40.49"
}, {
"time": "2014-02-26T09:00:00Z",
"temp": "40.29"
}, {
"time": "2014-02-26T11:00:00Z",
"temp": "39.90"
}, {
"time": "2014-02-26T13:00:00Z",
"temp": "39.66"
}, {
"time": "2014-02-26T15:00:00Z",
"temp": "39.01"
}, {
"time": "2014-02-26T17:00:00Z",
"temp": "37.91"
}, {
"time": "2014-02-26T19:00:00Z",
"temp": "39.64"
}, {
"time": "2014-02-26T21:00:00Z",
"temp": "38.21"
}, {
"time": "2014-02-26T23:00:00Z",
"temp": "39.60"
}, {
"time": "2014-02-27T01:00:00Z",
"temp": "40.13"
}, {
"time": "2014-02-27T03:00:00Z",
"temp": "40.51"
}, {
"time": "2014-02-27T05:00:00Z",
"temp": "40.78"
}, {
"time": "2014-02-27T07:00:00Z",
"temp": "40.54"
}, {
"time": "2014-02-27T09:00:00Z",
"temp": "40.29"
}, {
"time": "2014-02-27T11:00:00Z",
"temp": "40.24"
}, {
"time": "2014-02-27T13:00:00Z",
"temp": "40.00"
}, {
"time": "2014-02-27T15:00:00Z",
"temp": "40.01"
}, {
"time": "2014-02-27T17:00:00Z",
"temp": "38.96"
}, {
"time": "2014-02-27T19:00:00Z",
"temp": "39.20"
}, {
"time": "2014-02-27T21:00:00Z",
"temp": "40.14"
}, {
"time": "2014-02-27T23:00:00Z",
"temp": "38.71"
}, {
"time": "2014-02-28T01:00:00Z",
"temp": "40.88"
}, {
"time": "2014-02-28T03:00:00Z",
"temp": "40.98"
}, {
"time": "2014-02-28T05:00:00Z",
"temp": "41.05"
}, {
"time": "2014-02-28T07:00:00Z",
"temp": "40.60"
}, {
"time": "2014-02-28T09:00:00Z",
"temp": "40.47"
}, {
"time": "2014-02-28T11:00:00Z",
"temp": "40.39"
}, {
"time": "2014-02-28T13:00:00Z",
"temp": "40.44"
}, {
"time": "2014-02-28T15:00:00Z",
"temp": "37.58"
}, {
"time": "2014-02-28T17:00:00Z",
"temp": "38.26"
}, {
"time": "2014-02-28T19:00:00Z",
"temp": "37.83"
}, {
"time": "2014-02-28T21:00:00Z",
"temp": "39.26"
}, {
"time": "2014-02-28T23:00:00Z",
"temp": "38.25"
}, {
"time": "2014-03-01T01:00:00Z",
"temp": "39.60"
}, {
"time": "2014-03-01T03:00:00Z",
"temp": "40.09"
}, {
"time": "2014-03-01T05:00:00Z",
"temp": "39.92"
}, {
"time": "2014-03-01T07:00:00Z",
"temp": "39.67"
}, {
"time": "2014-03-01T09:00:00Z",
"temp": "39.73"
}, {
"time": "2014-03-01T11:00:00Z",
"temp": "39.93"
}, {
"time": "2014-03-01T13:00:00Z",
"temp": "39.90"
}, {
"time": "2014-03-01T15:00:00Z",
"temp": "39.82"
}, {
"time": "2014-03-01T17:00:00Z",
"temp": "37.47"
}, {
"time": "2014-03-01T19:00:00Z",
"temp": "38.30"
}, {
"time": "2014-03-01T21:00:00Z",
"temp": "39.17"
}, {
"time": "2014-03-01T23:00:00Z",
"temp": "38.87"
}, {
"time": "2014-03-02T01:00:00Z",
"temp": "40.01"
}, {
"time": "2014-03-02T03:00:00Z",
"temp": "40.31"
}, {
"time": "2014-03-02T05:00:00Z",
"temp": "39.31"
}, {
"time": "2014-03-02T07:00:00Z",
"temp": "39.78"
}, {
"time": "2014-03-02T09:00:00Z",
"temp": "40.32"
}, {
"time": "2014-03-02T11:00:00Z",
"temp": "40.48"
}, {
"time": "2014-03-02T13:00:00Z",
"temp": "39.94"
}, {
"time": "2014-03-02T15:00:00Z",
"temp": "38.42"
}, {
"time": "2014-03-02T17:00:00Z",
"temp": "39.41"
}, {
"time": "2014-03-02T19:00:00Z",
"temp": "39.56"
}, {
"time": "2014-03-02T21:00:00Z",
"temp": "36.89"
}, {
"time": "2014-03-02T23:00:00Z",
"temp": "39.53"
}, {
"time": "2014-03-03T01:00:00Z",
"temp": "40.97"
}, {
"time": "2014-03-03T03:00:00Z",
"temp": "40.58"
}, {
"time": "2014-03-03T05:00:00Z",
"temp": "38.17"
}, {
"time": "2014-03-03T07:00:00Z",
"temp": "39.50"
}, {
"time": "2014-03-03T09:00:00Z",
"temp": "40.47"
}, {
"time": "2014-03-03T11:00:00Z",
"temp": "40.28"
}, {
"time": "2014-03-03T13:00:00Z",
"temp": "37.48"
}, {
"time": "2014-03-03T15:00:00Z",
"temp": "38.13"
}, {
"time": "2014-03-03T17:00:00Z",
"temp": "39.17"
}, {
"time": "2014-03-03T19:00:00Z",
"temp": "39.27"
}, {
"time": "2014-03-03T21:00:00Z",
"temp": "38.65"
}, {
"time": "2014-03-03T23:00:00Z",
"temp": "39.78"
}, {
"time": "2014-03-04T01:00:00Z",
"temp": "39.62"
}, {
"time": "2014-03-04T03:00:00Z",
"temp": "39.49"
}, {
"time": "2014-03-04T05:00:00Z",
"temp": "39.65"
}, {
"time": "2014-03-04T07:00:00Z",
"temp": "40.07"
}, {
"time": "2014-03-04T09:00:00Z",
"temp": "40.72"
}, {
"time": "2014-03-04T11:00:00Z",
"temp": "40.46"
}, {
"time": "2014-03-04T13:00:00Z",
"temp": "38.86"
}, {
"time": "2014-03-04T15:00:00Z",
"temp": "39.40"
}, {
"time": "2014-03-04T17:00:00Z",
"temp": "40.39"
}, {
"time": "2014-03-04T19:00:00Z",
"temp": "39.61"
}, {
"time": "2014-03-04T21:00:00Z",
"temp": "38.94"
}, {
"time": "2014-03-04T23:00:00Z",
"temp": "40.43"
}, {
"time": "2014-03-05T01:00:00Z",
"temp": "40.17"
}, {
"time": "2014-03-05T03:00:00Z",
"temp": "39.81"
}, {
"time": "2014-03-05T05:00:00Z",
"temp": "40.68"
}, {
"time": "2014-03-05T07:00:00Z",
"temp": "39.80"
}, {
"time": "2014-03-05T09:00:00Z",
"temp": "40.38"
}, {
"time": "2014-03-05T11:00:00Z",
"temp": "39.05"
}, {
"time": "2014-03-05T13:00:00Z",
"temp": "37.91"
}, {
"time": "2014-03-05T15:00:00Z",
"temp": "39.28"
}, {
"time": "2014-03-05T17:00:00Z",
"temp": "39.72"
}, {
"time": "2014-03-05T19:00:00Z",
"temp": "38.84"
}, {
"time": "2014-03-05T21:00:00Z",
"temp": "39.74"
}, {
"time": "2014-03-05T23:00:00Z",
"temp": "40.63"
}, {
"time": "2014-03-06T01:00:00Z",
"temp": "39.66"
}, {
"time": "2014-03-06T03:00:00Z",
"temp": "40.71"
}, {
"time": "2014-03-06T05:00:00Z",
"temp": "40.67"
}, {
"time": "2014-03-06T07:00:00Z",
"temp": "40.93"
}, {
"time": "2014-03-06T09:00:00Z",
"temp": "40.48"
}, {
"time": "2014-03-06T11:00:00Z",
"temp": "39.54"
}, {
"time": "2014-03-06T13:00:00Z",
"temp": "40.54"
}, {
"time": "2014-03-06T15:00:00Z",
"temp": "39.90"
}, {
"time": "2014-03-06T17:00:00Z",
"temp": "39.85"
}, {
"time": "2014-03-06T19:00:00Z",
"temp": "39.37"
}, {
"time": "2014-03-06T21:00:00Z",
"temp": "40.58"
}, {
"time": "2014-03-06T23:00:00Z",
"temp": "39.72"
}, {
"time": "2014-03-07T01:00:00Z",
"temp": "40.40"
}, {
"time": "2014-03-07T03:00:00Z",
"temp": "40.68"
}, {
"time": "2014-03-07T05:00:00Z",
"temp": "40.72"
}, {
"time": "2014-03-07T07:00:00Z",
"temp": "41.08"
}, {
"time": "2014-03-07T09:00:00Z",
"temp": "38.06"
}, {
"time": "2014-03-07T11:00:00Z",
"temp": "39.39"
}, {
"time": "2014-03-07T13:00:00Z",
"temp": "39.83"
}, {
"time": "2014-03-07T15:00:00Z",
"temp": "40.51"
}, {
"time": "2014-03-07T17:00:00Z",
"temp": "40.21"
}, {
"time": "2014-03-07T19:00:00Z",
"temp": "38.25"
}, {
"time": "2014-03-07T21:00:00Z",
"temp": "40.39"
}, {
"time": "2014-03-07T23:00:00Z",
"temp": "40.54"
}, {
"time": "2014-03-08T01:00:00Z",
"temp": "39.31"
}, {
"time": "2014-03-08T03:00:00Z",
"temp": "40.29"
}, {
"time": "2014-03-08T05:00:00Z",
"temp": "40.94"
}, {
"time": "2014-03-08T07:00:00Z",
"temp": "41.05"
}, {
"time": "2014-03-08T09:00:00Z",
"temp": "39.82"
}, {
"time": "2014-03-08T11:00:00Z",
"temp": "39.14"
}, {
"time": "2014-03-08T13:00:00Z",
"temp": "36.90"
}, {
"time": "2014-03-08T15:00:00Z",
"temp": "39.69"
}, {
"time": "2014-03-08T17:00:00Z",
"temp": "39.61"
}, {
"time": "2014-03-08T19:00:00Z",
"temp": "38.97"
}, {
"time": "2014-03-08T21:00:00Z",
"temp": "39.58"
}, {
"time": "2014-03-08T23:00:00Z",
"temp": "40.39"
}, {
"time": "2014-03-09T01:00:00Z",
"temp": "40.85"
}, {
"time": "2014-03-09T03:00:00Z",
"temp": "40.66"
}, {
"time": "2014-03-09T05:00:00Z",
"temp": "40.91"
}, {
"time": "2014-03-09T07:00:00Z",
"temp": "40.83"
}, {
"time": "2014-03-09T09:00:00Z",
"temp": "37.44"
}, {
"time": "2014-03-09T11:00:00Z",
"temp": "39.01"
}, {
"time": "2014-03-09T13:00:00Z",
"temp": "37.28"
}, {
"time": "2014-03-09T15:00:00Z",
"temp": "38.47"
}, {
"time": "2014-03-09T17:00:00Z",
"temp": "39.60"
}, {
"time": "2014-03-09T19:00:00Z",
"temp": "39.15"
}, {
"time": "2014-03-09T21:00:00Z",
"temp": "40.64"
}, {
"time": "2014-03-09T23:00:00Z",
"temp": "37.76"
}];
var parseDate = d3.time.format("%Y-%m-%dT%H:%M:%SZ").parse;
data.forEach(function (d) { d.time = parseDate(d.time); });
var chart = d3.select("#chart");
var padding = 40,
width = 950,
height = 300,
xTicks = 10,
yTicks = 8;
var svg = chart.append("svg")
.attr("width", width + padding * 2)
.attr("height", height + padding * 2)
.append("g")
.attr("transform", "translate(" + padding + "," + padding + ")");
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
var xAxis = d3.svg.axis().scale(x).orient("bottom").ticks(xTicks);
var yAxis = d3.svg.axis().scale(y).orient("left").ticks(yTicks);
var valueLine = d3.svg.line()
.interpolate("basis")
.x(function (d) {
return x(d.time);
})
.y(function (d) {
return y(d.temp);
});
x.domain(d3.extent(data, function (d) {
return d.time;
}));
y.domain([33, 43]);
var mainLine = svg.append("path").attr({
"class": "line",
stroke: "steelblue",
d: valueLine(data)
});
var threshold = 40.5;
svg.append("line").attr("stroke", "#F00").attr("x1", 0).attr("y1", y(threshold)).attr("x2", width).attr("y2", y(threshold)).attr("class", "line");
答案 0 :(得分:0)
这个修正后的Fiddle在JS中进行了线性插值,并说明了为什么基础插值可能没有达到预期效果。我已经将一些样式移动到CSS中,并且还添加了圈子以便使用鼠标悬停文本进行观察,以便我们可以看到每个观察的详细信息。
使用第475行运行此操作,两者都已注释掉而不是:
// .interpolate("basis")
在数据集的末尾,截至05年3月5日和23:00的观察结果均大幅上升然后急剧下降。基础插值线不超过阈值,但观察结果如此。如果求解插值线,则无法识别这些交点。这可能是你想要的,但你的问题并不清楚。
末尾的交叉数组是我们得到交叉时间的地方。它遍历每个数据对,检查它们是否位于阈值的不同侧。如果它们是,那么就会有一个简单的线性插值计算来确定它穿过的时间,假设温度在观测值之间线性上升。
答案 1 :(得分:0)
安格斯的答案比我的好,但我发布这个以防有人发现它有用。另外,感谢Pablo的有用建议。
将此代码添加到最后:
var yLine = y(threshold);
console.log(yLine);
var node = mainLine.node();
var pathLength = node.getTotalLength();
for (var i = 0; i < pathLength; i++) {
var point = node.getPointAtLength(i);
console.log(point);
if(Math.floor(point.y) == yLine) {
svg.append("circle").attr({cx:point.x, cy:point.y, r:2});
}
}
这就是CSS:
circle {
fill: green;
}
或者打开此修订后的Fiddle