我正在尝试在D3js中构建堆积条形图。我无法正确设置y
和y0
属性并在正确位置绘制条形图。可能我有一个计算错误,但我找不到它。这是示例代码FIDDLE的链接
场景是:
我使用带有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的初学者,我找不到解决方案。有人可以帮帮我吗?
答案 0 :(得分:0)
我可以看到一些事情:
nest
。你应该只需要嵌套一个级别。g
)似乎被分组为"错误"办法。您通常希望将相同的" bit"每个堆栈。也就是说,您希望每个堆栈的第一个rect
与其他第一个rect
在同一个组中。然后,每个堆栈中的第二个将与其他第二个rect
组合,依此类推。这可能是由于第一点的嵌套错误。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>
&#13;
上述代码段的一些注释(符合我的评论):
一个更简单的巢:
var nest = d3.nest()
.key(function(d) { return d["type"];});
这比前一个简单得多,并且不需要执行汇总功能。当您想要汇总数据时通常需要汇总,在这种情况下您不需要汇总,这应该是您的嵌套过于复杂的赠品。
y轴最大值的计算:
var yMax = d3.max(dataByType, function(type) { return d3.max(type.values, function(d) { return d.amount + d.valueOffset; }); });
这将计算你的轴需要采取的最大值,使一切都很合适。
如果您查看生成的SVG,您将看到我对每个堆栈中rect
的分组的含义。我通常发现以这种方式分组更容易。我想那里没有&#34;对&#34;方式,但这通常最适合我。
计算valueOffset
中的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;
});
计算出的valueOffset
用于&#34;移动&#34;堆栈中的每个rect
相对于其他rect
的位置。您会看到它使用了几次,计算每个y
的最大y
值,rect
attr以及每个height
的{{1}} }。
我还没有解释我所做的每一项更改,但希望通过上述内容和代码片段,您将能够解决这些差异并将其应用于您的确切用例。