Phil Butcher
Phil Butcher

Reputation: 45

Fill area between two lines

Apologies for such a basic question. Is it possibly to fill the area between two lines?

For example, I have historical high/low temperature data. I'd like to create a shaded area between these two timeseries.

I've tried using the area feature of a lineChart like this:

return [
    {
        values: tsData.normal,
        key: 'Historical Normal',
        classed: 'dashed'
    },
    {
        area: true,
        values: tsData.hi,
        key: 'Historical Max',
        color: '#0000ff'
    },
    {
        area: true,
        values: tsData.low,
        key: 'Historical Min',
        color: '#ffffff',
        fillOpacity: 1
    }
];

Which results in this image:

enter image description here

Note that the gridlines below the Historical Min line are hidden by the filled areas. This solution is a bit hacky and ugly. Is there a more direct way to do this?

Upvotes: 4

Views: 1535

Answers (1)

purposek
purposek

Reputation: 101

I achieved a better solution by drawing an area using d3.

First I created an array (I called areaData) that merges tsData.hi and tsData.low. For each data point I push for eg: {x: "The x value", y0:"The y value from tsData.hi", y1:"The y value from tsData.low"}

Then I defined the x and y scale based on the chart's scales:

var x = chart.xScale();
var y = chart.yScale();

Then I added an area definition as

var area = d3.svg.area()
    .x(function (d) { return x(d.x); })
    .y0(function (d) { return y(d.y0); })
    .y1(function (d) { return y(d.y1); });

Next I drew the area using:

d3.select('.nv-linesWrap')
    .append("path")
    .datum(areaData)
    .attr("class", "area")
    .attr("d", area)
    .style("fill", "#AEC7E8")
    .style("opacity", .2);

This achieves a better looking solution. Because nvd3 updates the chart when the window is resized. I wrapped the drawing of the area in a function. So that I can call the function when the window is resized while removing the previously drawn area as follows:

var drawArea = function () {
    d3.select(".area").remove();
    d3.select('.nv-linesWrap')
        .append("path")
        .datum(areaData)
        .attr("class", "forecastArea")
        .attr("d", area)
        .style("fill", "#AEC7E8")
        .style("opacity", .2);
}
drawArea();

nv.utils.windowResize(resize);

function resize() {
    chart.update();

    drawArea();
}

I also disabled switching the series on and off using the legend as I wasn't handling that case:

chart.legend.updateState(false);

The result:

enter image description here

Upvotes: 4

Related Questions