规范化堆叠条形图绘图问题。无论数据如何,所有矩形均等分

Normalized stacked bar chart plotting issue. All rect are equally divided irrespective of data

您好,我正在使用这个示例 here to construct a normalized stacked bar chart. My data structure is a bit different from what is normally used. I am able to plot the chart, but somewhere the calculation is getting messed up and I am having a hard time figuring it out. I have created a pen。如您所见,条形图被平均分配,我认为这不是应该发生的情况。我猜 y0, y1 计算没有正确发生。感谢解决此问题的任何努力。

代码片段

                    var normalizedStackedData = dataset;
                    var excludedYaxisKey = "sum(quantity)";
                    console.log(normalizedStackedData);
                    checkLength(normalizedStackedData);

                function plotNormalizedStack(data) {


                    var x = d3.scale.ordinal()
                        .rangeRoundBands([0, WIDTH], .1);

                    var y = d3.scale.linear()
                        .rangeRound([HEIGHT, 0]);

                    var color = d3.scale.ordinal()
                        .range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);


                    var xAxis = d3.svg.axis()
                        .scale(x)
                        .orient("bottom")
                        .tickValues(_arr.map(function(d) {
                            return d[excludedYaxisKey];
                        }));

                    var yAxis = d3.svg.axis()
                        .scale(y)
                        .orient("left")
                        .tickFormat(d3.format(".0%"));

                    appendResponsiveSvg();

                    svg.append("g")
                        .attr("transform", "translate(" + MARGINS.left + "," + MARGINS.top + ")");

                    color.domain(d3.keys(data[0]).filter(function(key) { return key !== excludedYaxisKey; }));

                    var nested_data = d3.nest()
                        .key(function(d) { return d["state"]; })
                        .entries(normalizedStackedData);

                    var domain = [excludedYaxisKey]//Object.keys(d);
                    var y0;

                    nested_data.forEach(function(_data) {
                        _data.values.map(function(d, index){
                             y0 = 0;
                            _data.groupedItem = [];
                            for (var i = 0; i < (_data.values).length; i++) {
                                _data.groupedItem.push(domain.map(function(name) { return {label: "quantity"+(i+1) ,name: name, y0: y0, y1: y0 += +d[name]}; })[0]);
                            }
                            _data.groupedItem.forEach(function(d) { 
                                d.y0 /= y0; 
                                d.y1 /= y0; 
                            });
                        });
                    });

                    data = nested_data;

                    data.sort(function(a, b) { return b.groupedItem[0].y1 - a.groupedItem[0].y1; });

                    x.domain(data.map(function(d) { return d["key"]; }));

                    svg.append("g")
                      .attr("class", "x axis")
                      .attr("transform", "translate(0," + HEIGHT + ")")
                      .call(xAxis);

                    svg.append("g")
                      .attr("class", "y axis")
                      .call(yAxis);

                    var state = svg.selectAll(".state")
                      .data(data)
                    .enter().append("g")
                      .attr("class", "state")
                      .attr("transform", function(d) { return "translate(" + x(d["key"]) + ",0)"; });

                    state.selectAll("rect")
                      .data(function(d) { return d.groupedItem; })
                    .enter().append("rect")
                      .attr("width", x.rangeBand())
                      .attr("y", function(d) { 
                        return y(d.y1); 
                        })
                      .attr("height", function(d) { 
                        return y(d.y0) - y(d.y1); 
                        })
                      .style("fill", function(d) { return color(d.label); });

                }
                plotNormalizedStack(normalizedStackedData);

我发现您的堆叠数据操作步骤很难阅读和调试。由于您没有变量 domain(您正在为 运行 .map 创建一个数组),只需将其丢弃并为感兴趣的特定属性编写代码。考虑到这一点,它简化为更具可读性:

nested_data.forEach(function(d0) {
    d0.groupedItem = [];
    var y0 = 0;
    d0.values.forEach(function(d1){
      d0.groupedItem.push({
        y0: y0,
        y1: y0 += +d1["sum(quantity)"],
        label: d1["zip"]
      });
    });
    d0.groupedItem.forEach(function(d1){
      d1.y0 /= y0;
      d1.y1 /= y0;
    });
  });

完整运行宁码:

<!DOCTYPE html>
<html>

<head>
  <script data-require="d3@3.5.3" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script>
  <style>
    body {
      font: 10px sans-serif;
    }
    
    .axis path,
    .axis line {
      fill: none;
      stroke: #000;
      shape-rendering: crispEdges;
    }
    
    .browser text {
      text-anchor: end;
    }
    
    svg {
      width: 100%;
      height: 400px;
    }
  </style>
</head>

<body>
  <svg width="100%" height="100%" preserveAspectRatio="xMinYMin meet" viewBox="-80 -10 1450 600" class="svg-content-responsive"></svg>

  <script>
    function getRes(data) {

      var _len = data.length;
      var offset = 20;
      var _range = Math.round(_len / offset);
      //console.log("myRange : ", _range);
      var _arr = [];
      var _res = [];

      for (var i = 0; i < 20; i++) {
        if (_range * i < data.length)
          _res.push(data[_range * i]);
      }
      //console.log(_res);
      return _res;
    }

    function checkLength(data) {
      if (data.length >= 50) {
        _arr = getRes(data);
      } else {
        _arr = data;
      }
    }

    var WIDTH = 1250,
      HEIGHT = 500,
      MARGINS = {
        top: 20,
        right: 20,
        bottom: 20,
        left: 50
      },
      xoffset = 22,
      svg = [],
      tooltip = [];

    var dataset = [{
      "state": "AK",
      "zip": "99546",
      "sum(quantity)": "623.95"
    }, {
      "state": "AL",
      "zip": "35440",
      "sum(quantity)": "265.40"
    }, {
      "state": "CA",
      "zip": "93510",
      "sum(quantity)": "682.81"
    }, {
      "state": "CA",
      "zip": "95220",
      "sum(quantity)": "367.14"
    }, {
      "state": "GA",
      "zip": "30102",
      "sum(quantity)": "609.85"
    }, {
      "state": "GA",
      "zip": "30103",
      "sum(quantity)": "691.53"
    }, {
      "state": "IA",
      "zip": "50001",
      "sum(quantity)": "597.52"
    }, {
      "state": "IA",
      "zip": "50601",
      "sum(quantity)": "741.38"
    }, {
      "state": "IL",
      "zip": "62214",
      "sum(quantity)": "564.20"
    }, {
      "state": "LA",
      "zip": "70420",
      "sum(quantity)": "576.45"
    }, {
      "state": "LA",
      "zip": "70511",
      "sum(quantity)": "377.81"
    }, {
      "state": "LA",
      "zip": "70710",
      "sum(quantity)": "398.69"
    }, {
      "state": "MD",
      "zip": "20606",
      "sum(quantity)": "423.71"
    }, {
      "state": "MD",
      "zip": "20607",
      "sum(quantity)": "544.17"
    }, {
      "state": "MD",
      "zip": "21005",
      "sum(quantity)": "233.74"
    }, {
      "state": "MD",
      "zip": "21520",
      "sum(quantity)": "601.30"
    }, {
      "state": "ME",
      "zip": "4406",
      "sum(quantity)": "238.58"
    }, {
      "state": "ME",
      "zip": "4606",
      "sum(quantity)": "412.01"
    }, {
      "state": "MS",
      "zip": "39735",
      "sum(quantity)": "486.00"
    }, {
      "state": "MT",
      "zip": "59001",
      "sum(quantity)": "434.12"
    }, {
      "state": "ND",
      "zip": "58001",
      "sum(quantity)": "122.81"
    }, {
      "state": "ND",
      "zip": "58002",
      "sum(quantity)": "883.31"
    }, {
      "state": "NE",
      "zip": "68001",
      "sum(quantity)": "605.27"
    }, {
      "state": "NJ",
      "zip": "8205",
      "sum(quantity)": "630.63"
    }, {
      "state": "NM",
      "zip": "87510",
      "sum(quantity)": "1059.78"
    }, {
      "state": "NY",
      "zip": "12404",
      "sum(quantity)": "573.52"
    }, {
      "state": "NY",
      "zip": "12405",
      "sum(quantity)": "911.70"
    }, {
      "state": "NY",
      "zip": "13606",
      "sum(quantity)": "295.05"
    }, {
      "state": "NY",
      "zip": "14410",
      "sum(quantity)": "91.27"
    }, {
      "state": "OH",
      "zip": "43802",
      "sum(quantity)": "234.60"
    }, {
      "state": "OK",
      "zip": "73520",
      "sum(quantity)": "331.16"
    }, {
      "state": "OK",
      "zip": "74330",
      "sum(quantity)": "679.95"
    }, {
      "state": "OK",
      "zip": "74720",
      "sum(quantity)": "723.63"
    }, {
      "state": "OK",
      "zip": "74821",
      "sum(quantity)": "624.22"
    }, {
      "state": "OR",
      "zip": "97810",
      "sum(quantity)": "229.12"
    }, {
      "state": "PA",
      "zip": "15410",
      "sum(quantity)": "558.51"
    }, {
      "state": "PA",
      "zip": "15520",
      "sum(quantity)": "859.19"
    }, {
      "state": "PA",
      "zip": "15610",
      "sum(quantity)": "656.57"
    }, {
      "state": "PA",
      "zip": "15611",
      "sum(quantity)": "303.19"
    }, {
      "state": "PA",
      "zip": "16820",
      "sum(quantity)": "763.54"
    }, {
      "state": "PA",
      "zip": "17301",
      "sum(quantity)": "314.21"
    }, {
      "state": "PA",
      "zip": "18010",
      "sum(quantity)": "522.25"
    }, {
      "state": "PA",
      "zip": "19001",
      "sum(quantity)": "541.86"
    }, {
      "state": "PA",
      "zip": "19501",
      "sum(quantity)": "314.65"
    }, {
      "state": "SC",
      "zip": "29426",
      "sum(quantity)": "387.74"
    }, {
      "state": "TX",
      "zip": "77326",
      "sum(quantity)": "497.49"
    }, {
      "state": "TX",
      "zip": "79311",
      "sum(quantity)": "619.80"
    }, {
      "state": "TX",
      "zip": "79699",
      "sum(quantity)": "546.51"
    }, {
      "state": "TX",
      "zip": "79713",
      "sum(quantity)": "424.77"
    }, {
      "state": "VA",
      "zip": "23001",
      "sum(quantity)": "340.39"
    }, {
      "state": "VA",
      "zip": "23301",
      "sum(quantity)": "446.56"
    }, {
      "state": "VT",
      "zip": "5640",
      "sum(quantity)": "548.90"
    }, {
      "state": "WA",
      "zip": "98520",
      "sum(quantity)": "223.90"
    }, {
      "state": "WI",
      "zip": "54101",
      "sum(quantity)": "680.80"
    }, {
      "state": "WI",
      "zip": "54405",
      "sum(quantity)": "485.17"
    }, {
      "state": "WV",
      "zip": "25606",
      "sum(quantity)": "404.94"
    }];

    function appendResponsiveSvg() {
      svg = d3.select("svg")
        .attr("width", 100 + "%")
        .attr("height", 100 + "%")
        .attr("preserveAspectRatio", "xMinYMin meet")
        .attr("viewBox", "-80 -10 " + (WIDTH + 200) + " " + (HEIGHT + 100))
        .classed("svg-content-responsive", true);

      return svg;
    }

    var normalizedStackedData = dataset;
    var excludedYaxisKey = "sum(quantity)";
    //console.log(normalizedStackedData);
    checkLength(normalizedStackedData);

    function plotNormalizedStack(data) {


      var x = d3.scale.ordinal()
        .rangeRoundBands([0, WIDTH], .1);

      var y = d3.scale.linear()
        .rangeRound([HEIGHT, 0]);

      var color = d3.scale.ordinal()
        .range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);


      var xAxis = d3.svg.axis()
        .scale(x)
        .orient("bottom");

      var yAxis = d3.svg.axis()
        .scale(y)
        .orient("left")
        .tickFormat(d3.format(".0%"));

      appendResponsiveSvg();

      svg.append("g")
        .attr("transform", "translate(" + MARGINS.left + "," + MARGINS.top + ")");

      color.domain(d3.keys(data[0]).filter(function(key) {
        return key !== excludedYaxisKey;
      }));

      var nested_data = d3.nest()
        .key(function(d) {
          return d["state"];
        })
        .entries(normalizedStackedData);

      var domain = [excludedYaxisKey] //Object.keys(d);
      var y0;
      
      nested_data.forEach(function(d0) {
        d0.groupedItem = [];
        var y0 = 0;
        d0.values.forEach(function(d1){
          d0.groupedItem.push({
            y0: y0,
            y1: y0 += +d1["sum(quantity)"],
            label: d1["zip"]
          });
        });
        d0.groupedItem.forEach(function(d1){
          d1.y0 /= y0;
          d1.y1 /= y0;
        });
      });

      data = nested_data;
      
      data.sort(function(a, b) {
        return b.groupedItem[0].y1 - a.groupedItem[0].y1;
      });

      x.domain(data.map(function(d) {
        return d["key"];
      }));

      svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + HEIGHT + ")")
        .call(xAxis);

      svg.append("g")
        .attr("class", "y axis")
        .call(yAxis);

      var state = svg.selectAll(".state")
        .data(data)
        .enter().append("g")
        .attr("class", "state")
        .attr("transform", function(d) {
          return "translate(" + x(d["key"]) + ",0)";
        });

      state.selectAll("rect")
        .data(function(d) {
          return d.groupedItem;
        })
        .enter().append("rect")
        .attr("width", x.rangeBand())
        .attr("y", function(d) {
          return y(d.y1);
        })
        .attr("height", function(d) {
          return y(d.y0) - y(d.y1);
        })
        .style("fill", function(d) {
          return color(d.label);
        });

    }
    plotNormalizedStack(normalizedStackedData);
  </script>

</body>

</html>