Search code examples
javascriptangularjsd3.jsstacked-area-chart

The fill in stacked area chart gets reversed d3


I have no idea why the fill of my stacked area chart is getting reversed. I was somehow able copy it from the site and create a pen. There are quite a lot of data (sorry about that). Please check this pen link. Help appreciated. Snippets from my code below:

                function plotStackedArea(data) {

                    clearChart();
                    appendResponsiveSvg();
                    checkLength(sgChartData);

                // getting min and max values to pass in domain
                var minX = d3.min(data, function (kv) {
                    return d3.min(kv.values, function (d) {
                        return d.x;
                    }) });
                var maxX = d3.max(data, function (kv) {
                    return d3.max(kv.values, function (d) {
                        return d.x;
                    }) });
                var minY = d3.min(data, function (kv) {
                    return d3.min(kv.values, function (d) {
                        return d.y;
                    }) });
                var maxY = d3.max(data, function (kv) {
                    return d3.max(kv.values, function (d) {
                        return d.y;
                    }) });

                // we exclude x axis label from here
                var getKeysArr = d3.keys(stackedDataToPlot[0]).filter(function(key) { return key !== xaxisData[0].columnID; });

                // Color range - add your favorites here
                var color = d3.scale.ordinal()
                    .range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);


                function xAxisScale() {

                    if ((xaxisData[0].hasOwnProperty("dataType")) && (xaxisData[0].dataType === "String")) {
                        // this is for ordinal data
                        var ordinal = d3.scale.ordinal().rangePoints([MARGINS.left, WIDTH - MARGINS.right], 0).domain(sgChartData.map(function(d) {
                            return d.x;
                        }));
                        return ordinal;
                    } else {
                        // this is for numbers
                        var linear = d3.scale.linear().range([MARGINS.left, WIDTH - MARGINS.right]).domain([minX, maxX]);
                        return linear;
                    }
                }


                var xScale = xAxisScale(),

                      yScale = d3.scale.linear()
                      .range([HEIGHT - MARGINS.top, MARGINS.bottom])
                      .domain([0, maxY]),

                      xAxis = d3.svg.axis()
                      .scale(xScale)
                      .tickValues(_arr.map(function(d) {
                            return d.x;
                        })),

                      yAxis = d3.svg.axis()
                      .scale(yScale);

                    yAxis = d3.svg.axis()
                      .scale(yScale)
                      .orient("left");

                    // for stacked area
                    d3.layout.stack(data);

                    var area = d3.svg.area()
                      .x(function(d) {
                        return xScale(d.x);
                      })
                      .y0(function(d) {
                        return yScale(HEIGHT - MARGINS.top, MARGINS.bottom);
                      })
                      .y1(function(d) {
                        return yScale(d.y);
                      })
                      .interpolate("cardinal");

                    data.forEach(function(d, i) {
                      svg.append('svg:path')
                        .attr('d', area(d.values))
                        .attr('id', 'line_' + d.key)
                        .attr('fill', function(d, j) {
                          return color(i);
                        });
                    });

                    svg.append("svg:g")
                      .attr("class", "axis")
                      .attr("transform", "translate(0," + (HEIGHT - MARGINS.bottom) + ")")
                      .call(xAxis);

                    svg.append("svg:g")
                      .attr("class", "axis")
                      .attr("transform", "translate(" + (MARGINS.left) + ",0)")
                      .call(yAxis);

                   var legend = svg.selectAll(".legend")
                      .data(getKeysArr.slice().reverse())
                    .enter().append("g")
                      .attr("class", "legend")
                      .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });

                    legend.append("rect")
                          .attr("x", WIDTH - 18)
                          .attr("width", 18)
                          .attr("height", 18)
                          .style("fill", function(d, j) {
                          return color(j);
                        });

                      legend.append("text")
                          .attr("x", WIDTH - 24)
                          .attr("y", 9)
                          .attr("dy", ".35em")
                          .style("text-anchor", "end")
                          .text(function(d) { return d; });
                }
                plotStackedArea(multiLineData);  

Pen link with solution: Stacked area d3


Solution

  • You don't need to scale your initial y0 values. You want them to match the y value of your x axis positioning (given that you want the bottom of the chart to sit on the x axis):

    .y0(function(d) {
      return HEIGHT - MARGINS.bottom;
    })