d3中所有堆叠条形图堆栈的总和

时间:2015-06-29 08:45:30

标签: javascript d3.js graph

我有一个堆积条形图,每个堆栈中都有标签。现在我想在图表的每个条形图的顶部放置另一个标签。我无法在条形图的顶部放置标签,而且我正在获得图表中所有值的总和,其中我想要每个条形图的总和。 这是我的代码,

var groups = svg.selectAll("g.cost")
  .data(dataset.reverse())
  .enter().append("g")
  .attr("class", "cost")
  .style("fill", function (d, i) { return colors[i]; });
var sum = [0];

var svg = d3.select("svg");
var bar = groups.selectAll("g")
   .data(function (d) { return d; })
.enter().append("g")
  .attr("transform", function (d, i) { return "translate(0," + i * y(d.y0) - y(d.y0 + d.y) + ")"; });


bar.append("rect")
 .attr("x", function (d) { return x(d.x); })
 .attr("y", function (d) { return y(d.y0 + d.y); })
 .attr("height", function (d) { return y(d.y0) - y(d.y0 + d.y); })
 .attr("width", x.rangeBand())


bar.append("text")
    .attr("x", function (d) { return x(d.x); })
  .attr("y", function (d) { return y(d.y0 + d.y); })
    .attr("dy", ".35em")
    .attr('style', 'font-size:13px')
    .text(function (d) { if (d.y != 0) { sum += d.y; return "$" + d.y; } })
    .style('fill', 'black');

bar.append("text")
   .attr("x", function (d) { return x(d.x); })
 .attr("y", function (d) { return y(d.y0 + d.y); })
   .attr("dy", ".35em")
   .attr('style', 'font-size:13px')
   .text( sum)
   .style('fill', 'black'); 

jsfiddle:http://fiddle.jshell.net/1fsm8cst/3/

2 个答案:

答案 0 :(得分:1)

垂直汇总对于堆栈布局来说并不自然,因为它在图层中分组,但d3有很多功能可以帮助。在这种情况下,d3.nest,d3.sum和d3.values(关于d3.sum的真正好处是它忽略了NaN值)。通过这些,您可以按月汇总数据,然后您可以使用相同的坐标系并进行缩放以定位汇总元素。



var margin = {top: 20, right: 300, bottom: 35, left: 50};

  var width = 760 - margin.left - margin.right,
    height = 400 - margin.top - margin.bottom;



  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 + ")");



  /* Data in strings like it would be if imported from a csv */

  var data = [
    { month: "Jan", MobileCoupon: "430000", Bonus: "240000", Promotions: "200000", Merchandise: "150000" },
    { month: "Feb", MobileCoupon: "250000", Bonus: "440000", Promotions: "200000", Merchandise: "150000" },
    { month: "Mar", MobileCoupon: "350000", Bonus: "180000", Promotions: "200000", Merchandise: "150000" },
  ];

  var parse = d3.time.format("%b").parse;


  // Transpose the data into layers
  var dataset = d3.layout.stack()(["MobileCoupon", "Bonus", "Promotions", "Merchandise"].map(function(fruit) {
    return data.map(function(d) {
      return {x: parse(d.month), y: +d[fruit]};
    });
  }));

  var months = d3.nest()
    .key(function(d){return parse(d.month)})
    .rollup(function(leaves){
      return d3.sum(leaves, function(d) {return d3.sum(d3.values(d))});
    })
    .entries(data);

  // Set x, y and colors
  var x = d3.scale.ordinal()
    .domain(dataset[0].map(function(d) { return d.x; }))
    .rangeRoundBands([10, width-10], 0.35);

  var y = d3.scale.linear()
    .domain([0, d3.max(dataset, function(d) {  return d3.max(d, function(d) { return d.y0 + d.y; });  })])
    .range([height, 0]);

  var colors = ["#3D0000", "#d25c4d", "#f2b447", "#d9d574"];

  // Define and draw axes
  var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left")

    .ticks(5)
    .tickSize(-width, 0, 0)
    .tickFormat( d3.format("$,s") );

  var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom")
    .tickFormat(d3.time.format("%b"));

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


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

  // Create groups for each series, rects for each segment
  var groups = svg.selectAll("g.cost")
    .data(dataset)
    .enter().append("g")
    .attr("class", "cost")
    .style("fill", function(d, i) { return colors[i]; });

//  var svg = d3.select("svg");
  var bar = groups.selectAll("g")
    .data(function(d) { return d; })
    .enter().append("g")
    .attr("transform", function(d, i) {
      return "translate(" + x(d.x) + ", 0)";
    });

  var sum=0;
  bar.append("rect")
    .attr("y", function(d) { return y(d.y0 + d.y); })
    .attr("height", function(d) { return y(d.y0) - y(d.y0 + d.y); })
    .attr("width", x.rangeBand())

  bar.append("text")
    .attr("x", -6)
    .attr("y", function(d) { return y(d.y0 + d.y); })
    .attr("dy", ".35em")
    .text(function(d) {sum+=d.y; return d3.format("$,s")(d.y); });

  columns = svg.append("g")
    .selectAll("text").data(months)
    .enter().append("text")
    .attr("x", function(d){
      return x(d.key) + x.rangeBand()/2
    })
    .attr("y", function (d) {
      return y(d.values);
    })
    .attr("dy", "1.35em")
    .attr('style', 'font-size:13px')
    .text( function (d){
      return d3.format("$,s")(d.values);
    })
    .style({fill: 'black', "text-anchor": "middle"});

  //  svg.call(tip);

  // Draw legend
  var legend = svg.selectAll(".legend")
    .data(colors)
    .enter().append("g")
    .attr("class", "legend")
    .attr("transform", function(d, m) { return "translate(90," + (m+5) * 20 + ")"; });

  legend.append("rect")
    .attr("x", width - 18)
    .attr("width", 18)
    .attr("height", 18)
    .style("fill", function(d, i) {return colors.slice().reverse()[i];});

  legend.append("text")
    .attr("x", width + 5)
    .attr("y", 9)
    .attr("dy", ".35em")
    .style("text-anchor", "start")
    .text(function(d, i) {
      switch (i) {
        case 0: return "Mobile Coupon";
        case 1: return "Bonus";
        case 2: return "Promotions";
        case 3: return "Merchandise";
      }
    });

svg {
      font: 10px sans-serif;
      shape-rendering: crispEdges;
    }

    .axis path,
    .axis line {
      fill: none;
      stroke: black;
      shape-rendering: crispEdges;
    }

    path.domain {
      stroke: none;
    }

    .y .tick line {
      stroke: #ddd;}


    text {
      font: 10px sans-serif;
      text-anchor: end;
    }



    .d3-tip {
      line-height: 1;
      font-weight: bold;
      padding: 12px;
      background: rgba(0, 0, 0, 0.8);
      color: #fff;
      border-radius: 2px;
    }

    /* Creates a small triangle extender for the tooltip */
    .d3-tip:after {
      box-sizing: border-box;
      display: inline;
      font-size: 10px;
      width: 100%;
      line-height: 1;
      color: rgba(0, 0, 0, 0.8);
      content: "\25BC";
      position: absolute;
      text-align: center;
    }

    /* Style northward tooltips differently */
    .d3-tip.n:after {
      margin: -1px 0 0 0;
      top: 100%;
      left: 0;
    }
    .legend
    {
      position: relative;
      top: -401px;
      left: 380px;
    }

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
&#13;
&#13;
&#13;

答案 1 :(得分:0)

我目前是Javascript和D3的初学者。 希望我的解决方案达到目的: http://jsfiddle.net/sandeepedara/n3ew5sqq/

var margin = {top: 20, right: 300, bottom: 35, left: 50};

var width = 760 - margin.left - margin.right,
    height = 400 - margin.top - margin.bottom;



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 + ")");



/* Data in strings like it would be if imported from a csv */

var data = [
  { month: "Jan", MobileCoupon: "430000", Bonus: "240000", Promotions: "200000", Merchandise: "150000" },
  { month: "Feb", MobileCoupon: "250000", Bonus: "440000", Promotions: "200000", Merchandise: "150000" },
  { month: "Mar", MobileCoupon: "350000", Bonus: "180000", Promotions: "200000", Merchandise: "150000" },
];

for (var key in data) {
var sum=0;
   if (data.hasOwnProperty(key)) {
       var obj = data[key];

        for (var prop in obj) {

          // important check that this is objects own property 
          // not from prototype prop inherited
          if(obj.hasOwnProperty(prop)){ 
                if(prop=="month"){console.log("month");}
                else{         
                 sum = sum + parseInt(obj[prop]);
                 obj.sum = sum;
            }
          }
       }
    }
}

var parse = d3.time.format("%b").parse;


// Transpose the data into layers
var dataset = d3.layout.stack()(["MobileCoupon", "Bonus", "Promotions", "Merchandise","sum"].map(function(fruit) {
  return data.map(function(d) {
    return {x: parse(d.month), y: +d[fruit]};
  });
}));


// Set x, y and colors
var x = d3.scale.ordinal()
  .domain(dataset[0].map(function(d) { return d.x; }))
  .rangeRoundBands([10, width-10], 0.35);

var y = d3.scale.linear()
  .domain([0, d3.max(dataset, function(d) {  return d3.max(d, function(d) { return d.y0 + d.y; });  })])
  .range([height, 0]);

var colors = ["#3D0000", "#d25c4d", "#f2b447", "#d9d574"];

// Define and draw axes
var yAxis = d3.svg.axis()
  .scale(y)
  .orient("left")

  .ticks(5)
 .tickSize(-width, 0, 0)
  .tickFormat( function(d) { return "$" + d } );

var xAxis = d3.svg.axis()
  .scale(x)
  .orient("bottom")
  .tickFormat(d3.time.format("%b"));

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


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


// Create groups for each series, rects for each segment 
var groups = svg.selectAll("g.cost")
  .data(dataset)
  .enter().append("g")
  .attr("class", "cost")
  .style("fill", function(d, i) { return colors[i]; });




  var svg = d3.select("svg");
  var bar = groups.selectAll("g")
     .data(function(d) { return d; })
  .enter().append("g")
    .attr("transform", function(d, i) { return "translate(0," + i * y(d.y0) - y(d.y0 + d.y) + ")"; });


 bar.append("rect")
  .attr("x", function(d) { return x(d.x); })
  .attr("y", function(d) { return y(d.y0 + d.y); })
  .attr("height", function(d) { return y(d.y0) - y(d.y0 + d.y); })
  .attr("width", x.rangeBand())


bar.append("text")
    .attr("x", function(d) { return x(d.x); })
  .attr("y", function(d) { return y(d.y0 + d.y); })
    .attr("dy", ".35em")
    .text(function(d) { return d.y; });

  svg.call(tip);





// Draw legend
var legend = svg.selectAll(".legend")
  .data(colors)
  .enter().append("g")
  .attr("class", "legend")
  .attr("transform", function(d, m) { return "translate(90," + (m+5) * 20 + ")"; });

legend.append("rect")
  .attr("x", width - 18)
  .attr("width", 18)
  .attr("height", 18)
  .style("fill", function(d, i) {return colors.slice().reverse()[i];});

legend.append("text")
  .attr("x", width + 5)
  .attr("y", 9)
  .attr("dy", ".35em")
  .style("text-anchor", "start")
  .text(function(d, i) { 
    switch (i) {
      case 0: return "Mobile Coupon";
      case 1: return "Bonus";
      case 2: return "Promotions";
      case 3: return "Merchandise";
    }
  });