使用d3遮住两条线之间的区域 [英] Using d3 to shade area between two lines
问题描述
所以我有一个图表,描绘了流量与日期和比率与日期。我试图遮蔽两条线之间的区域。然而,我想遮蔽它不同的颜色,取决于哪一行更高。以下工作没有最后的要求:
var area = d3.svg.area()
$然而,除了最后一个要求,我试图使用defined():
.x0 (d){return x(d3.time.format(%m /%d /%Y)。parse(d.original.date));})
.x1(function(d){return x(d3.time.format(%m /%d /%Y)。parse(d.original.date));})
.y0(function(d){return y(parseInt .original.traffic));})
.y1(function(d){return y(parseInt(d.original.rate));})
<$> c $ c> .defined(function(d){return parseInt(d.original.traffic)> = parseInt(d.original.rate);})
现在这个工作大部分工作,除非当线交叉。我如何阴影区域下一条线下BETWEEN点?它的阴影基于点,我想它的阴影基于线。
解决方案
如果我没有两个连续的点在一行,我没有得到任何阴影。 >由于在交点处没有数据点,最简单的解决方案可能是获取每行上方和下方的区域,并使用
clipPath
s裁剪差异。 p>
我假设你使用
d3.svg.line
来绘制区域所基于的线。这样我们就可以重用.x()
和.y()
var trafficLine = d3.svg.line()
.x(function(d){ return x(d3.time.format(%m /%d /%Y)。parse(d.original.date));})
.y(function(d){return y(parseInt d.original.traffic));});
var rateLine = d3.svg.line()
.x(trafficLine.x())//重用流量线的x
.y(function(d){ return y(parseInt(d.original.rate));})
用于计算两条线上方和下方的区域。每行下面的区域将用于绘制实际路径,上面的区域将用作剪切路径。现在我们可以从以下行中重用访问器:
var areaAboveTrafficLine = d3.svg.area()
.x(trafficLine.x())
.y0(trafficLine.y())
.y1(0);
var areaBelowTrafficLine = d3.svg.area()
.x(trafficLine.x())
.y0(trafficLine.y())
。
var areaAboveRateLine = d3.svg.area()
.x(rateLine.x())
.y0(rateLine.y())
.y1(0);
var areaBelowRateLine = d3.svg.area()
.x(rateLine.x())
.y0(rateLine.y())
。
...其中
height
,并假设0
是图表顶部的y坐标,否则相应地调整这些值。
现在,您可以使用区域以上的函数来创建如下的剪切路径:
var defs = svg.append 'defs');
defs.append('clipPath')
.attr('id','clip-traffic')
.append('path')
.datum (YOUR_DATASET)
.attr('d',areaAboveTrafficLine);
defs.append('clipPath')
.attr('id','clip-rate')
.append('path')
.datum (YOUR_DATASET)
.attr('d',areaAboveRateLine);
id
属性是必要的,因为我们需要在实际剪切路径时引用这些定义。
最后,使用area-below函数绘制svg的路径。这里要记住的重要的事情是,对于每个区域,下面,我们需要剪辑到上面的区域,所以速率区域将根据
#clip-交通
,反之亦然:// TRAFFIC IS ABOVE RATE
svg.append 'path')
.datum(YOUR_DATASET)
.attr('d',areaBelowTrafficLine)
.attr('clip-path','url(#clip-rate)')
//速度是上面的交通
svg.append('path')
.datum(YOUR_DATASET)
.attr('d',areaBelowRateLine)
.attr('clip-path','url(#clip-traffic)')
你只需要给这两个区域不同的填充颜色或任何你想做的,以区分彼此。希望有所帮助!
So I have a chart plotting traffic vs. date and rate vs. date. I'm trying to shade the area between the two lines. However, I want to shade it a different color depending on which line is higher. The following works without that last requirement:
var area = d3.svg.area() .x0(function(d) { return x(d3.time.format("%m/%d/%Y").parse(d.original.date)); }) .x1(function(d) { return x(d3.time.format("%m/%d/%Y").parse(d.original.date)); }) .y0(function(d) { return y(parseInt(d.original.traffic)); }) .y1(function(d) { return y(parseInt(d.original.rate)); })
However, adding that last requirement, I tried to use defined():
.defined(function(d){ return parseInt(d.original.traffic) >= parseInt(d.original.rate); })
Now this mostly works, except when lines cross. How do I shade the area under one line BETWEEN points? It's shading based on the points and I want it to shade based on the line. If I don't have two consecutive points on one side of the line, I don't get any shading at all.
解决方案Since you don't have datapoints at the intersections, the simplest solution is probably to get the areas above and below each line and use
clipPath
s to crop the difference.I'll assume you're using
d3.svg.line
to draw the lines that the areas are based on. This way we'll be able to re-use the.x()
and.y()
accessor functions on the areas later:var trafficLine = d3.svg.line() .x(function(d) { return x(d3.time.format("%m/%d/%Y").parse(d.original.date)); }) .y(function(d) { return y(parseInt(d.original.traffic)); }); var rateLine = d3.svg.line() .x(trafficLine.x()) // reuse the traffic line's x .y(function(d) { return y(parseInt(d.original.rate)); })
You can create separate area functions for calculating the areas both above and below your two lines. The area below each line will be used for drawing the actual path, and the area above will be used as a clipping path. Now we can re-use the accessors from the lines:
var areaAboveTrafficLine = d3.svg.area() .x(trafficLine.x()) .y0(trafficLine.y()) .y1(0); var areaBelowTrafficLine = d3.svg.area() .x(trafficLine.x()) .y0(trafficLine.y()) .y1(height); var areaAboveRateLine = d3.svg.area() .x(rateLine.x()) .y0(rateLine.y()) .y1(0); var areaBelowRateLine = d3.svg.area() .x(rateLine.x()) .y0(rateLine.y()) .y1(height);
...where
height
is the height of your chart, and assuming0
is the y-coordinate of the top of the chart, otherwise adjust those values accordingly.Now you can use the area-above functions to create clipping paths like this:
var defs = svg.append('defs'); defs.append('clipPath') .attr('id', 'clip-traffic') .append('path') .datum(YOUR_DATASET) .attr('d', areaAboveTrafficLine); defs.append('clipPath') .attr('id', 'clip-rate') .append('path') .datum(YOUR_DATASET) .attr('d', areaAboveRateLine);
The
id
attributes are necessary because we need to refer to those definitions when actually clipping the paths.Finally, use the area-below functions to draw paths to the svg. The important thing to remember here is that for each area-below, we need to clip to the opposite area-above, so the Rate area will be clipped based on
#clip-traffic
and vice versa:// TRAFFIC IS ABOVE RATE svg.append('path') .datum(YOUR_DATASET) .attr('d', areaBelowTrafficLine) .attr('clip-path', 'url(#clip-rate)') // RATE IS ABOVE TRAFFIC svg.append('path') .datum(YOUR_DATASET) .attr('d', areaBelowRateLine) .attr('clip-path', 'url(#clip-traffic)')
After that you'll just need to give the two regions different fill colors or whatever you want to do to distinguish them from one another. Hope that helps!
这篇关于使用d3遮住两条线之间的区域的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!