代码之家  ›  专栏  ›  技术社区  ›  Raviteja

如何在d3js中制作分组堆积条形图?

  •  3
  • Raviteja  · 技术社区  · 6 年前

    d3.stack() . 有没有更好的方法可以让我知道吗?

    var data = [
      {
        Category: "cat1",
        type1: 300,
        type2: 450,
        type3: 120
      },
      {
        Category: "cat2",
        type1: 400,
        type2: 100,
        type3: 200
      },
      {
        Category: "cat3",
        type1: 400,
        type2: 100,
        type3: 200
      },
      {
        Category: "cat4",
        type1: 400,
        type2: 100,
        type3: 200
      }
    ];
    
    var margin = { top: 20, right: 20, bottom: 30, left: 40 },
      width = 500 - margin.left - margin.right,
      height = 500 - margin.top - margin.bottom;
    var barWidth = 40;
    var x0 = d3.scaleBand().range([0, width]);
    
    var x1 = d3.scaleBand();
    
    var y = d3.scaleLinear().range([height, 0]);
    
    var xAxis = d3.axisBottom(x0);
    
    var yAxis = d3.axisLeft(y).tickFormat(d3.format(".2s"));
    
    var color = d3.scaleOrdinal().range(["#98abc5", "#8a89a6", "#7b6888"]);
    
    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 yBegin;
    
    var innerColumns = {
      column1: ["type1", "type2"],
      column2: ["type3"]
    };
    var columnHeaders = d3.keys(data[0]).filter(function(key) {
      return key !== "Category";
    });
    color.domain(
      d3.keys(data[0]).filter(function(key) {
        return key !== "Category";
      })
    );
    var groupData = data.forEach(function(d) {
      var yColumn = new Array();
      d.columnDetails = columnHeaders.map(function(name) {
        for (ic in innerColumns) {
          if (innerColumns[ic].indexOf(name) >= 0) {
            if (!yColumn[ic]) {
              yColumn[ic] = 0;
            }
            yBegin = yColumn[ic];
            yColumn[ic] += +d[name];
            return {
              name: name,
              column: ic,
              yBegin: yBegin,
              yEnd: +d[name] + yBegin
            };
          }
        }
      });
      d.total = d3.max(d.columnDetails, function(d) {
        return d.yEnd;
      });
    });
    
    //console.log(data);
    x0.domain(
      data.map(function(d) {
        return d.Category;
      })
    );
    x1.domain(d3.keys(innerColumns)).range([0, x0.bandwidth()]);
    
    y.domain([
      0,
      1.15 *
        d3.max(data, function(d) {
          return d.total;
        })
    ]);
    
    svg
      .append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis);
    
    svg
      .append("g")
      .attr("class", "y axis")
      .call(yAxis);
    
    var stackedbar = svg
      .selectAll(".stackedbar")
      .data(data)
      .enter()
      .append("g")
      .attr("class", "g")
      .attr("transform", function(d) {
        return "translate(" + x0(d.Category) + ",0)";
      });
    
    stackedbar
      .selectAll("rect")
      .data(function(d) {
        return d.columnDetails;
      })
      .enter()
      .append("rect")
      .attr("width", barWidth)
      .attr("x", function(d) {
        return x1(d.column) + (x1.bandwidth() - barWidth) / 2;
      })
      .attr("y", function(d) {
        return y(d.yEnd);
      })
      .attr("height", function(d) {
        return y(d.yBegin) - y(d.yEnd);
      })
      .style("fill", function(d) {
        return color(d.name);
      });
    body {
      font: 10px sans-serif;
    }
     
    .axis path,
    .axis line {
      fill: none;
      stroke: #000;
      shape-rendering: crispEdges;
    }
     
    .bar {
      fill: steelblue;
    }
    
     
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.6.0/d3.min.js"></script>
    2 回复  |  直到 6 年前
        1
  •  0
  •   Kyros Koh    6 年前

    你可能需要。。。在循环中按如下方式在innerColumns中构建该对象:

    itemLookup= data[0],
    category = d3.keys(itemLookup.category),
    items = d3.keys(itemLookup.category[type1[0]]),
    columnHeaders = [],
    innerColumns = (function(){
      var result = {};
      for(var i = 0, ii = category.length; i<ii; i++){
        var holder = [];
        for(var j = 0, jj = items.length; j<jj; j++){
          columnHeaders.push(items[j]+'-'+category[i]);
          holder.push(items[j]+'-'+category[i]);
          result[category[i]] = holder;
        }
      }
      return result;
    })()...
    

    https://jsfiddle.net/kyroskoh/tmec32z0/

        2
  •  0
  •   AB9KT    6 年前

    . 以下是我的解决方案的两个重要部分:

    var datasets=[d3.stack().keys(['type1','type3'])(data),
                  d3.stack().keys(['type2'])(data)];
    
    var num_groups=datasets.length;
    

    这里我使用d3.stack的.keys()方法为每个组创建数据集。在此之后,我们可以使用代码创建堆积条形图,如下所示:

    d3.range(num_groups).forEach(function(gnum) {
            svg.selectAll('g.group'+gnum)
                .data(datasets[gnum])
                .enter()
                .append('g')
                    .attr('fill',accent)
                    .attr('class', 'group'+gnum)
                .selectAll('rect')
                .data(d=>d)
                .enter()
                .append('rect')
                    .attr('x',(d,i)=>xscale(xlabels[i])+(xscale.bandwidth()/num_groups)*gnum)
                    .attr('y',d=>yscale(d[1]))
                    .attr('width',xscale.bandwidth()/num_groups)
                    .attr('height',d=>yscale(d[0])-yscale(d[1]));
                });
    

    https://jsfiddle.net/Abhi9kt/28wzdrfk/4/