使用d3遮住两条线之间的区域 [英] Using d3 to shade area between two lines

查看:164
本文介绍了使用d3遮住两条线之间的区域的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我有一个图表,描绘了流量与日期和比率与日期。我试图遮蔽两条线之间的区域。然而,我想遮蔽它不同的颜色,取决于哪一行更高。以下工作没有最后的要求:

  var area = d3.svg.area()
.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 clipPaths 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 assuming 0 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆