如何在d3中对堆积条进行排序?

时间:2016-01-15 06:58:42

标签: javascript sorting d3.js stacked-chart

我试图在d3中对水平堆积条形图进行排序,但不断提出未定义的值,这会弄乱我的排序。我正在引用Cyril's code,但我一直在" a.total = undefined"。 (它来自代码的后半部分,我已经为你们评论过了。)

除了确保此代码正确排序外,我的问题是:

  1. 为什么不定义?我是否错误地引用了不同数据集的属性?
  2. 如果是这样,如何访问各自数据集的属性而不局限于函数内?
  3. 我对d3和javascript全新,所以任何评论都会有很大帮助,我感谢任何帮助! :)

    
    
    //the stacks
    var headers = ["AR_Score_2015", "ER_Score_2015", "FS_Score_2015", "CF_Score_2015", "IF_Score_2015", "IS_Score_2015"];
    
    var margin = {
        top: 20,
        right: 50,
        bottom: 30,
        left: 20
      },
      width = 800 - margin.left - margin.right,
      height = 500 - margin.top - margin.bottom;
    
    var x = d3.scale.linear()
      .rangeRound([0, width]);
    
    var y = d3.scale.ordinal()
      .rangeRoundBands([0, height], .2);
    
    var z = d3.scale.category10();
    
    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");
    
    //***Canvas setup***/
    var svg = d3.select("body").append("svg")
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom)
      .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
    
    var csv = "Uni,AR_Score_2015,ER_Score_2015,FS_Score_2015,CF_Score_2015,IF_Score_2015,IS_Score_2015\n\
    A,400,400,400,400,400,382\n\
    B,400,400,394.4,400,399.6,304\n\
    C,400,400,400,374.8,384.8,386.4\n\
    D,400,400,398,399.6,390.4,291.2\n\
    E,399.2,358.4,400,400,360.8,340.8\n\
    F,400,400,400,355.6,391.2,386.4\n\
    G,399.6,399.2,394.4,352,382,399.6\n\
    H,399.6,400,399.6,318.4,400,400\n\
    I,399.6,396,314.4,395.2,400,392\n\
    J,399.6,385.2,375.2,366,293.6,326.4\n\
    K,400,394,371.6,400,188.8,272.8\n\
    L,400,400,371.6,315.6,400,370\n\
    M,381.2,390,376.8,346,400,376\n\
    N,400,400,400,285.2,359.6,262\n\
    O,388.8,296,400,339.6,386.4,284.8\n\
    P,399.6,386.8,295.6,388.4,360.8,264\n\
    Q,395.2,389.6,400,322,211.6,266.4\n\
    R,380.8,383.6,359.6,310,381.6,392.8\n\
    S,398.8,392,341.2,286,372.4,391.6\n\
    T,400,397.6,400,268,132,359.2\n\
    U,396.4,378.8,323.2,281.6,353.2,369.2\n\
    V,398.4,398,350,336.8,191.2,144.4\n\
    W,400,399.6,187.6,399.6,387.2,317.2\n\
    X,400,398.8,296.8,358.4,229.6,196\n\
    Y,377.2,367.2,263.2,357.6,400,388\n\
    Z,385.6,338.4,399.2,341.6,60.8,229.6";
    var csvBase64 = btoa(csv);
    //***CSV START***/
    d3.csv("data:text/plain;base64," + csvBase64, type, function(error, scores) {
      if (error) throw error;
    
      scores.forEach(function(d) {
        d.Overall_Score_2015 = +d.Overall_Score_2015;
        d.AR_Score_2015 = +d.AR_Score_2015;
        d.ER_Score_2015 = +d.ER_Score_2015;
        d.FS_Score_2015 = +d.FS_Score_2015;
        d.CF_Score_2015 = +d.CF_Score_2015;
        d.IF_Score_2015 = +d.IF_Score_2015;
        d.IS_Score_2015 = +d.IS_Score_2015;
      });
    
    
      //***Stacking***/
    
      var layers = d3.layout.stack()(headers.map(function(c) {
        return scores.map(function(d) {
          return {
            x: d.Uni,
            y: d[c]
          };
        });
      }));
      var count = 0;
      var i = 0;
    
      var layers2 = layers.map(function(scores) {
    
        return scores.map(function(d) {
          d.width = 0;
          var l = scores.length;
          if (count == l * 5 + i) {
            d.total = d.y0;
            i++;
          }
          count++;
          return {
            x: d.y,
            y: d.x,
            x0: d.y0,
            parent: d
          };
        });
      });
    
    
      //***Drawing***/
    
      y.domain(layers2[0].map(function(d) {
        return d.y;
      }));
      x.domain([0, d3.max(layers2[layers2.length - 1], function(d) {
          return d.x / 4 + d.x0 / 4;
        })])
        .nice();
    
      color.domain(d3.keys(scores[0]).filter(function(key) {
        return key !== "Uni";
      }));
    
      var layer = svg.selectAll(".layer")
        .data(layers2)
        .enter().append("g")
        .attr("class", "layer")
        .attr("transform", function(d) {
          return "translate(0," + 0 + ")";
        })
        .style("fill", function(d, i) {
          return z(i);
        })
        .attr("class", "stack");
    
      layer.selectAll("rect")
        .data(function(d) {
          return d;
        })
        .enter().append("rect")
        .attr("y", function(d) {
          return y(d.y);
        })
        .attr("x", function(d) {
          return x(d.x0 / 4);
        })
        .attr("height", y.rangeBand())
        .attr("width", function(d) {
          d.parent.width += x(d.x) - x(d.x0);
          return -(x(d.x0 / 4) - x(d.x / 4 + d.x0 / 4));
        })
        .on("click", function() {
          sortBars();
        });
    
      svg.append("g")
        .attr("class", "axis axis--x")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis);
    
      svg.append("g")
        .attr("class", "axis axis--y")
        .attr("transform", "translate(0,0)")
        .call(yAxis);
    
    
      //***Sorting***/
    
      function sortBars() {
    
        //***Problem here***//
        var z = y.domain(layers2.sort(function(a, b) {
              console.log("a.total = " + a.total, a, b);
              return b.total - a.total;
            })
            .map(function(d) {
              return d.layers2;
            }))
          .copy();
    
        //*** This is the code I was referencing from ***/
        var y0 = y.domain(layers2.sort(this.id == "test" ?
              function(a, b) {
                return b.total - a.total;
              } :
              function(a, b) {
                return d3.ascending(a.total, b.total);
              })
            .map(function(d) {
              return d.layers2;
            }))
          .copy();
        console.log(y0);
    
        svg.selectAll(".stack")
          .sort(function(a, b) {
            console.log("y0(a.total) = " + z(a.total));
            console.log("y0(b.total) = " + z(b.total));
            return z(a.total) - z(b.total);
          });
    
        var transition = svg.transition().duration(750),
          delay = function(d, i) {
            return i * 50;
          };
    
        transition.selectAll(".stack")
          .delay(delay)
          .attr("transform", function(d) {
            return "translate(0," + z(d.total) + ")";
          });
    
        transition.select(".y.axis")
          .call(yAxis)
          .selectAll("g")
          .delay(delay);
      }
    });
    
    function type(d) {
      headers.forEach(function(c) {
        d[c] = +d[c];
      });
      return d;
    }
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
    &#13;
    &#13;
    &#13;

1 个答案:

答案 0 :(得分:0)

关于undefined的mdn文档说:

  

自动分配给具有just的变量的原始值   被宣布或正式的论据,没有实际的   参数。

但是,如果它不能帮助你检查this answer out

你得到a.total = undefined因为这个表达:

if (count == l * 5 + i) {
  d.total = d.y0;
  i++;
}

如果条件为total,则仅设置true属性。