javascript - Using d3 to shade area between two lines -
so have chart plotting traffic vs. date , rate vs. date. i'm trying shade area between 2 lines. however, want shade different color depending on line higher. following works without 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 last requirement, tried use defined():
.defined(function(d){ return parseint(d.original.traffic) >= parseint(d.original.rate); })
now works, except when lines cross. how shade area under 1 line between points? it's shading based on points , want shade based on line. if don't have 2 consecutive points on 1 side of line, don't shading @ all.
since don't have datapoints @ intersections, simplest solution areas above , below each line , use clippath
s crop difference.
i'll assume you're using d3.svg.line
draw lines areas based on. way we'll able re-use .x()
, .y()
accessor functions on 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 traffic line's x .y(function(d) { return y(parseint(d.original.rate)); })
you can create separate area functions calculating areas both above , below 2 lines. area below each line used drawing actual path, , area above used clipping path. can re-use accessors 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
height of chart, , assuming 0
y-coordinate of top of chart, otherwise adjust values accordingly.
now can use area-above functions create clipping paths 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 necessary because need refer definitions when clipping paths.
finally, use area-below functions draw paths svg. important thing remember here each area-below, need clip opposite area-above, rate area clipped based on #clip-traffic
, vice versa:
// traffic above rate svg.append('path') .datum(your_dataset) .attr('d', areabelowtrafficline) .attr('clip-path', 'url(#clip-rate)') // rate above traffic svg.append('path') .datum(your_dataset) .attr('d', areabelowrateline) .attr('clip-path', 'url(#clip-traffic)')
after you'll need give 2 regions different fill colors or whatever want distinguish them 1 another. hope helps!
Comments
Post a Comment