繁体   English   中英

D3js中堆积的条形图-条形不在正确的位置

[英]Stacked bar chart in D3js - bars are not on the correct places

我正在尝试在D3js中构建堆积的条形图。 我在正确设置yy0属性并在其正确位置绘制条形时遇到问题。 可能我有一个计算错误,但找不到。 这是示例代码FIDDLE的链接方案是:

  1. 我先按“期间”对数据进行分组,然后在xAxis上显示周期
  2. 然后我按“类型”分组-MONTH和ENTRY,应将其堆叠成不同颜色的条。
  3. 每种类型在每个周期的总和“金额”显示在yAxis上。

我使用带有2个键的嵌套函数来构造数据。 当我在实际堆积的条形图中绘制条形时出现问题。 我不确定问题出在我访问数据(键和值)的方式还是在设置属性“ y”和“ height”的方式。

selection.selectAll("rect")
    .data(function (d) { return d.values; })
    .enter().append("rect")
    .attr("width", x.rangeBand())
    .attr("y", function (d) { return y(d.values); })
    .attr("height", function (d) { return y(d.y0) + y(d.values); })
    //.attr("height", function (d) { return y(d.y0) - y(d.values); })
    .style("fill", function (d) { return color(d.key); })

明显的错误是其中一个条形图隐藏在另一个条形图的后面。 第二条位于xAxis下。

我是d3js的初学者,找不到解决方案。 有人可以帮我吗?

我可以看到几件事:

  1. 看来您使nest复杂化了。 您只需要嵌套一个级别。
  2. 当您实际上希望最大值是堆栈的总数时,您要计算的最大值将永远只是堆栈中单个元素的最大值。
  3. 您正在创建的分组元素( g )似乎以“错误”的方式分组。 通常,您希望将每个堆栈的相同“位”分组。 也就是说,您希望每个堆栈的第一个rect与其他第一个rect处于同一组中。 然后,每个堆栈中的第二个将与其他第二个rect分组,依此类推。 这可能是由于第一点的嵌套错误。
  4. 实际上,您需要计算小提琴中的valueOffset ,但已将其注释掉。 此值用于在构造堆栈时设置相对位置。

为了帮助您,我根据您所写的内容整理了看起来正确的内容。 查看下面的代码段。

  var margin = {top: 20, right: 20, bottom: 30, left: 40}, width = 400 - margin.left - margin.right, height = 400 - margin.top - margin.bottom; var color = d3.scale.category10(); var data = [ { "period":201409, "type":"MONTH", "amount":85.0 }, { "period":201409, "type":"ENTRY", "amount":111.0 }, { "period":201410, "type":"MONTH", "amount":85.0 }, { "period":201410, "type":"ENTRY", "amount":55.0 } ]; var x = d3.scale.ordinal().rangeRoundBands([0, width], .1, 0); var y = d3.scale.linear().range([height, 0]); var xAxis = d3.svg.axis() .scale(x) .orient("bottom"); var yAxis = d3.svg.axis() .scale(y) .orient("left").ticks(10); var svg = d3.select("#chart") .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.forEach(function(d) { d["period"] = d["period"]; d["amount"] = +d["amount"]; d["type"] = d["type"]; }); var nest = d3.nest() .key(function(d) { return d["type"];}); var dataByType = nest.entries(data); //var max = d3.max(dataByGroup, function(d) { return d3.sum(d.values, function(e) { return e.values; }); }) //console.log("dataByGroup", dataByGroup); var stack = d3.layout.stack() .values(function(d) { return d.values; }) .x(function(d) { return d.period; }) .y(function(d) { return d.amount; }) .out(function(d, y0) { d.valueOffset = y0; }); //data: key: group element, values: values in each group stack(dataByType); var yMax = d3.max(dataByType, function(type) { return d3.max(type.values, function(d) { return d.amount + d.valueOffset; }); }); color.domain(dataByType[0].values.map(function(d) { return d.type; })); x.domain(dataByType[0].values.map(function(d) { return d.period; })); y.domain([0, yMax]); svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis); svg.append("g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("transform", "rotate(-90)") .attr("y", 3) .attr("dy", ".71em") .style("text-anchor", "end"); var selection = svg.selectAll(".group") .data(dataByType) .enter().append("g") .attr("class", "group"); //.attr("transform", function(d) { return "translate(0," + y0(y0.domain()[0]) + ")"; }); selection.selectAll("rect") .data(function (d) { return d.values; }) .enter().append("rect") .attr("width", x.rangeBand()) .attr("x", function(d) { return x(d.period); }) .attr("y", function (d) { return y(d.amount + d.valueOffset); }) .attr("height", function (d) { return y(d.valueOffset) - y(d.valueOffset + d.amount); }) .style("fill", function (d) { return color(d.type); }) .style("stroke", "grey"); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> <div id="chart"></div> 

以上代码段的一些注释(与我的评论相符):

  1. 一个简单得多的嵌套:

     var nest = d3.nest() .key(function(d) { return d["type"];}); 

    这比上一个简单得多,并且不需要执行汇总功能。 当您想要聚合数据时,通常不需要汇总,在这种情况下,您不需要汇总数据,这应该说明嵌套太复杂了。

  2. y轴的最大值的计算:

     var yMax = d3.max(dataByType, function(type) { return d3.max(type.values, function(d) { return d.amount + d.valueOffset; }); }); 

    这将计算您的轴需要采用的最大值,从而使所有组件都非常合适。

  3. 如果查看生成的SVG,您将了解我对每个堆栈中rect的分组的含义。 通常,我发现以这种方式进行分组比较容易。 我猜没有“正确”的方法,但这通常对我最有效。

  4. stack valueOffset的计算:

     d3.layout.stack() .values(function(d) { return d.values; }) .x(function(d) { return d.period; }) .y(function(d) { return d.amount; }) .out(function(d, y0) { d.valueOffset = y0; }); 

    计算出的valueOffset用于将堆栈中的每个rect “移动”到相对于其他rect的位置。 你会看到它使用了几次,计算最大y值时, y每个ATTR rectheight各的rect

我还没有解释我所做的每一个更改,但是希望借助上面的内容和摘录,您将能够解决这些差异并将其应用于您的确切用例。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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