d3.js在每个柱的末尾堆叠条形图值

时间:2017-08-11 10:51:31

标签: javascript html css d3.js sapui5

我正在关注Horizontal stack bar

用于填充数据。如何在每个条形的末尾添加每个条形图的值。例如

enter image description here

以上屏幕截图适用于普通水平条形图。但我期待堆叠条形图。让我知道在哪里我可以修改代码,在上面链接给出的代码中每个堆叠水平条的末尾都有这个值

由于 普拉萨德

2 个答案:

答案 0 :(得分:0)

你的意思是这样的吗?

Stackchart

参见示例 - fiddle



var data = [
       {
            "interest_rate":"< 4%",
            "Default":60,
            "Charge-off":20,
            "Current":456,
            "30 days":367.22,
            "60 days":222,
            "90 days":198,
            "Default":60
            
         },
         {
            "interest_rate":"4-7.99%",
            "Charge-off":2,
            "Default":30,
            "Current":271,
            "30 days":125,
            "60 days":78,
            "90 days":72
            
           
         }
];

	var margin = {
				top: 20,
				right: 20,
				bottom: 40,
				left: 60
			},
				width = 450 - margin.left - margin.right,
				height = 315 - margin.top - margin.bottom,
				that = this;


			var x = d3.scale.ordinal().rangeRoundBands([0, width], .3);

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

			var color = d3.scale.category20();

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

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

			var svg = d3.select(".viz-portfolio-delinquent-status").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 + ")");

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


			data.forEach(function (d) {
				var y0 = 0;

				d.rates = color.domain().map(function (name) {
					console.log();;
					return {
						name: name,
						y0: y0,
						y1: y0 += +d[name],
						amount: d[name]
					};
				});
				d.rates.forEach(function (d) {
					d.y0 /= y0;
					d.y1 /= y0;
				});

				console.log(data);
			});

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

			x.domain(data.map(function (d) {
				return d.interest_rate;
			}));

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

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

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

			interest_rate.selectAll("rect").data(function (d) {
				return d.rates;
			}).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.name);
			}).on('mouseover', function (d) {
				var total_amt;
				total_amt = d.amount;



				console.log('----');
				d3.select(".chart-tip").style('opacity', '1').html('Amount: <strong>$' + that.numberWithCommas(total_amt.toFixed(2)) + '</strong>');

			}).on('mouseout', function () {
				d3.select(".chart-tip").style('opacity', '0');
			});

			var legend = svg.selectAll(".legend").data(color.domain().slice().reverse()).enter().append("g").attr("class", "legend").attr("transform", function (d, i) {
				return "translate(" + i * -70 + ",283)";
			});


			legend.append("rect").attr("x", width + -53).attr("width", 10).attr("height", 10).style("fill", color);

			legend.append("text").attr("x", width - 40).attr("y", 5).attr("width", 40).attr("dy", ".35em").style("text-anchor", "start").text(function (d) {
				return d;
			});
&#13;
h1 { 
  font-family: helvetica, arial, sans-serif; 
  text-align:center; 
  margin-top: 80px;
}


.viz-portfolio-delinquent-status {
  font-family: helvetica, arial, sans-serif; 
  margin: 0 auto;
  font-size: 10px;
  width: 450px;
  height: 300px
}


	path { fill: #83B0EA;}	
.domain { 
		fill: none; 
		stroke: #000; 
		stroke-width: 1px; 
	} 
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<h1>D3 Stacked Bar Chart Example</h1>
<div class="viz-portfolio-delinquent-status"></div>
&#13;
&#13;
&#13;

答案 1 :(得分:0)

为了生成每个柱的总计数,您需要执行两个步骤:

  1. 转换数据,以便获得包含date和总和的对象数组。引用您已链接的d3示例,我们需要对diseasewoundsother的键中的整数求和。
  2. 我们将此转换后的数据传递给您的SVG插入<text>元素,并使用预先存在的比例正确定位它们。
  3. 第1步:数据转换

    您可以将我们转换的数据存储在名为totals的变量中:

    var totals = d3.nest()
      .key(function(d) {
        return d.date;
      })
      .rollup(function(d) {
        return d3.sum(d, function(g) {
          return g.disease + g.wounds + g.other;
        });
      })
      .entries(data);
    

    上面代码的解释:我们基本上想要根据日期执行摘要,在这种情况下,我们可以使用d3.nest()函数。密钥将是日期,我们使用d3.nest().rollup()来执行diseasewoundsother密钥中值的总和。

    这将按以下格式创建一个对象数组:totals = [{key: <date>, value: <total>}, {...}]。请注意,日期现在存储在keyvalue中的总计中。

    第2步:创建标签

    我们将totals绑定到新创建的对象,并从中创建新的<text>元素:

    var totalLabels = svg.append('g').attr('class', 'totals');
    totalLabels.selectAll('.total')
      .data(totals)
      .enter().append('text')
      .attr('class', 'total')
      .attr("y", function(d) {
        // Retrieve the correct vertical coordinates based on the date (stored as d.key)
        // Plus some pixel offset so that the text is centered vertically relative to bar
        return yScale(parseDate(d.key)) + yScale.bandwidth() - 2;
      })
      .attr("x", function(d) {
        // Retrieve the horizontal coordinates based on total (stored as d.value)
        // Add 5px offset so the label does not 'stick' to end of stacked bar
        return xScale(d.value) + 5;
      })
      .text(function(d) {
        // Inject total as text content (stored as d.value)
        return d.value;
      });
    

    对上述代码的解释:

    1. 我们创建了一个<g>包装来存储您的所有文字标签
    2. 我们通过使用totals.data(totals)绑定到文本标签来创建文本标签。我们输入数据,并附加<text>标签
    3. 对于定位,我们只需重复使用已定义的xScaleyScale。您只需将总计传递到xScale,即xScale(d.value),将日期传递到yScale,即yScale(parseDate(d.key))
    4. 使用d3.text()将文字注入元素,并将总计作为文字内容,即d.value
    5. 实施例

      使用以下代码,我们可以创建您已链接的d3.js示例的修改,您可以在其中将总计追加到堆积条形图的末尾:

      请参阅下面的概念验证示例:

      &#13;
      &#13;
      var initStackedBarChart = {
        draw: function(config) {
          me = this,
            domEle = config.element,
            stackKey = config.key,
            data = config.data,
            margin = {
              top: 20,
              right: 20,
              bottom: 30,
              left: 50
            },
            parseDate = d3.timeParse("%m/%Y"),
            width = 960 - margin.left - margin.right,
            height = 500 - margin.top - margin.bottom,
            xScale = d3.scaleLinear().rangeRound([0, width]),
            yScale = d3.scaleBand().rangeRound([height, 0]).padding(0.1),
            color = d3.scaleOrdinal(d3.schemeCategory20),
            xAxis = d3.axisBottom(xScale),
            yAxis = d3.axisLeft(yScale).tickFormat(d3.timeFormat("%b")),
            svg = d3.select("#" + domEle).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 stack = d3.stack()
            .keys(stackKey)
            .offset(d3.stackOffsetNone);
      
          var layers = stack(data);
          data.sort(function(a, b) {
            return b.total - a.total;
          });
          yScale.domain(data.map(function(d) {
            return parseDate(d.date);
          }));
          xScale.domain([0, d3.max(layers[layers.length - 1], function(d) {
            return d[0] + d[1];
          })]).nice();
      
          var layer = svg.selectAll(".layer")
            .data(layers)
            .enter().append("g")
            .attr("class", "layer")
            .style("fill", function(d, i) {
              return color(i);
            });
      
          layer.selectAll("rect")
            .data(function(d) {
              return d;
            })
            .enter().append("rect")
            .attr("y", function(d) {
              return yScale(parseDate(d.data.date));
            })
            .attr("x", function(d) {
              return xScale(d[0]);
            })
            .attr("height", yScale.bandwidth())
            .attr("width", function(d) {
              return xScale(d[1]) - xScale(d[0])
            });
      
          var totals = d3.nest()
            .key(function(d) {
              return d.date;
            })
            .rollup(function(d) {
              return d3.sum(d, function(g) {
                return g.disease + g.wounds + g.other;
              });
            })
            .entries(data);
            
          var totalLabels = svg.append('g').attr('class', 'totals');
          totalLabels.selectAll('.total')
            .data(totals)
            .enter().append('text')
            .attr('class', 'total')
            .attr("y", function(d) {
              // Retrieve the correct vertical coordinates based on the date (stored as d.key)
              // Plus some pixel offset so that the text is centered vertically relative to bar
              return yScale(parseDate(d.key)) + yScale.bandwidth() - 2;
            })
            .attr("x", function(d) {
              // Retrieve the horizontal coordinates based on total (stored as d.value)
              // Add pixel offset so labels don't stick to end of stacked bars
              return xScale(d.value) + 5;
            })
            .text(function(d) {
              // Inject total as text content (stored as d.value)
              return d.value;
            });
      
          svg.append("g")
            .attr("class", "axis axis--x")
            .attr("transform", "translate(0," + (height + 5) + ")")
            .call(xAxis);
      
          svg.append("g")
            .attr("class", "axis axis--y")
            .attr("transform", "translate(0,0)")
            .call(yAxis);
        }
      }
      var data = [{
        "date": "4/1854",
        "total": 8571,
        "disease": 1,
        "wounds": 0,
        "other": 5
      }, {
        "date": "5/1854",
        "total": 23333,
        "disease": 12,
        "wounds": 0,
        "other": 9
      }, {
        "date": "6/1854",
        "total": 28333,
        "disease": 11,
        "wounds": 0,
        "other": 6
      }, {
        "date": "7/1854",
        "total": 28772,
        "disease": 359,
        "wounds": 0,
        "other": 23
      }, {
        "date": "8/1854",
        "total": 30246,
        "disease": 828,
        "wounds": 1,
        "other": 30
      }, {
        "date": "9/1854",
        "total": 30290,
        "disease": 788,
        "wounds": 81,
        "other": 70
      }, {
        "date": "10/1854",
        "total": 30643,
        "disease": 503,
        "wounds": 132,
        "other": 128
      }, {
        "date": "11/1854",
        "total": 29736,
        "disease": 844,
        "wounds": 287,
        "other": 106
      }, {
        "date": "12/1854",
        "total": 32779,
        "disease": 1725,
        "wounds": 114,
        "other": 131
      }, {
        "date": "1/1855",
        "total": 32393,
        "disease": 2761,
        "wounds": 83,
        "other": 324
      }, {
        "date": "2/1855",
        "total": 30919,
        "disease": 2120,
        "wounds": 42,
        "other": 361
      }, {
        "date": "3/1855",
        "total": 30107,
        "disease": 1205,
        "wounds": 32,
        "other": 172
      }, {
        "date": "4/1855",
        "total": 32252,
        "disease": 477,
        "wounds": 48,
        "other": 57
      }, {
        "date": "5/1855",
        "total": 35473,
        "disease": 508,
        "wounds": 49,
        "other": 37
      }, {
        "date": "6/1855",
        "total": 38863,
        "disease": 802,
        "wounds": 209,
        "other": 31
      }, {
        "date": "7/1855",
        "total": 42647,
        "disease": 382,
        "wounds": 134,
        "other": 33
      }, {
        "date": "8/1855",
        "total": 44614,
        "disease": 483,
        "wounds": 164,
        "other": 25
      }, {
        "date": "9/1855",
        "total": 47751,
        "disease": 189,
        "wounds": 276,
        "other": 20
      }, {
        "date": "10/1855",
        "total": 46852,
        "disease": 128,
        "wounds": 53,
        "other": 18
      }, {
        "date": "11/1855",
        "total": 37853,
        "disease": 178,
        "wounds": 33,
        "other": 32
      }, {
        "date": "12/1855",
        "total": 43217,
        "disease": 91,
        "wounds": 18,
        "other": 28
      }, {
        "date": "1/1856",
        "total": 44212,
        "disease": 42,
        "wounds": 2,
        "other": 48
      }, {
        "date": "2/1856",
        "total": 43485,
        "disease": 24,
        "wounds": 0,
        "other": 19
      }, {
        "date": "3/1856",
        "total": 46140,
        "disease": 15,
        "wounds": 0,
        "other": 35
      }];
      var key = ["wounds", "other", "disease"];
      initStackedBarChart.draw({
        data: data,
        key: key,
        element: 'stacked-bar'
      });
      &#13;
      .axis text {
        font: 10px sans-serif;
      }
      
      .axis line,
      .axis path {
        fill: none;
        stroke: #000;
        shape-rendering: crispEdges;
      }
      
      .path-line {
        fill: none;
        stroke: yellow;
        stroke-width: 1.5px;
      }
      
      svg {
        background: #f0f0f0;
      }
      &#13;
      <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
      <h2>Stacked Bar Chart - d3.v4 implementation</h2>
      <div id='stacked-bar'></div>
      &#13;
      &#13;
      &#13;