简体   繁体   中英

Value above each bar stacked bar chart D3.js

So I want to display the total value for each bar above the bar chart. Unfortunately I can't seem to get it to be positioned directly above a bar. I've tried several things, but the value seems to stay static right above the bar. Can someone help me out? I'd appreciate it very much. I've omitted some of the code, because it was too long.

This is how it looks right now:

堆叠条

var x = d3.scaleBand()
    .rangeRound([0, width])
    .paddingInner(0.2);

var y = d3.scaleLinear()
    .rangeRound([height, 0]);

var color = d3.scaleOrdinal()
    .range(d3.schemeGreys[7]);

var xAxis = d3.axisBottom(x);

var yAxis = d3.axisLeft(y)
    .tickFormat(d3.format(".2s"));

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 update = function(data) {

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

  data.forEach(function(d) {
    var y0 = 0;
    d.stores = color.domain().map(function(name) { return {name: name, y0: y0, y1: y0 += +d[name]}; });
    d.total = d.stores[d.stores.length - 1].y1;
  });

  data.sort(function(a, b) { return b.total - a.total; });

  x.domain(data.map(function(d) { return d.Categories; }));
  y.domain([0, d3.max(data, function(d) { return d.total; })]);

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

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

    categories.selectAll("rect")
      .data(function(d) { return d.stores; })
    .enter().append("rect")
      .attr("width", x.bandwidth())
      .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.name); });

    categories.selectAll("text")
      .data(function(d) { return d.stores; })
    .enter().append("text")
      .attr("y", function(d) { return y((d.y0 + d.y1) / 2); })
      .attr("x", x.bandwidth()/2)
      .attr("text-anchor","middle")
      .attr("alighnment-baseline", "middle")
      .style("fill",'#fff')
      .text(function(d) { return d.y1 - d.y0; });

    categories.append("text")
        .attr("text-anchor", "middle")
        .attr("x", x.bandwidth()/2)
        .attr("y", function(d) { return y((d.y0)); }) 
        .style("fill", "black")
        .text(function(d) { return d.total; });
var Data = [
    {
        "Categories": "Lissabon",
        "1": "34",
        "2": "76",
        "3": "87",
        "4": "54",
        "5": "66",
        "6": "72"
    },

You can use your existing y scale to calculate the position of the total in the same way that you've done with the top and bottom edges of the rectangles and the text on each. Rather than using d.y0 or d.y1 , you need to use d.total :

categories.append("text")
  .attr("text-anchor", "middle")
  .attr("x", x.bandwidth()/2)
  .attr("y", function(d) { return y(d.total); }) // d.total!
  .style("fill", "black")
  .text(function(d) { return d.total; });

This will position the text right on top of the top rectangle, so it's a good idea to add a bit of an offset to this:

categories.append("text")
  .attr("text-anchor", "middle")
  .attr("x", x.bandwidth()/2)
  .attr("y", function(d) { return y(d.total); })
  .attr('dy', '-0.5em') // add 0.5em offset
  .style("fill", "black")
  .text(function(d) { return d.total; });

Here is a working example:

 var Data = [ { "Categories": "Lissabon", "1": "34", "2": "76", "3": "87", "4": "54", "5": "66", "6": "72" }, { Categories: "This", 1: 239, 2: 254, 3: 225, 4: 152, 5: 362, 6: 98 }, { Categories: "That", 1: 457, 2: 234, 3: 83, 4: 327, 5: 88, 6: 99 }, { Categories: "The Other", 1: 132, 2: 286, 3: 222, 4: 150, 5: 363, 6: 95 } ] var height = 600, width = 600, margin = { left: 10, right: 10, top: 20, bottom: 20 } var x = d3.scaleBand() .rangeRound([0, width]) .paddingInner(0.2); var y = d3.scaleLinear() .rangeRound([height, 0]); var color = d3.scaleOrdinal() .range(d3.schemeGreys[7]); var xAxis = d3.axisBottom(x); var yAxis = d3.axisLeft(y) .tickFormat(d3.format(".2s")); 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 update = function(data) { color.domain(d3.keys(data[0]).filter(function(key) { return key !== "Categories"; })); data.forEach(function(d) { var y0 = 0; d.stores = color.domain().map(function(name) { return {name: name, y0: y0, y1: y0 += +d[name]}; }); d.total = d.stores[d.stores.length - 1].y1; }); data.sort(function(a, b) { return b.total - a.total; }); x.domain(data.map(function(d) { return d.Categories; })); y.domain([0, d3.max(data, function(d) { return d.total; })]); svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call((xAxis) .tickSize(0) .tickPadding(6)); var categories = svg.selectAll(".categories") .data(data) .enter().append("g") .attr("class", "g") .attr("transform", function(d) { return "translate(" + x(d.Categories) + ",0)"; }); categories.selectAll("rect") .data(function(d) { return d.stores; }) .enter().append("rect") .attr("width", x.bandwidth()) .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.name); }); categories.selectAll("text") .data(function(d) { return d.stores; }) .enter().append("text") .attr("y", function(d) { return y((d.y0 + d.y1) / 2); }) .attr("x", x.bandwidth()/2) .attr('dy', '0.35em') .attr("text-anchor","middle") .attr("alighnment-baseline", "middle") .style("fill",'#fff') .text(function(d) { return d.y1 - d.y0; }); categories.append("text") .attr("text-anchor", "middle") .attr("x", x.bandwidth()/2) .attr("y", function(d) { return y(d.total); }) .attr('dy', '-0.5em') .style("fill", "black") .text(function(d) { return d.total; }); } update(Data)
 <script type="text/javascript" src="http://d3js.org/d3.v5.js"></script>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM