我有D3.js条形图,我想在其上显示数组中的数字。每个栏都有自己的数组,例如[12, 34, 65]
。我能够在每个条形图的顶部只显示数组作为文本,但我想分割每个数组并从上到下显示每个数字,因此对于[12, 34, 65]
条,底部为12
,然后34
位于中间,65
位于顶部。这该怎么做?到目前为止,我有这样的代码,它只显示每个栏顶部的数组:
g.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text(function(d) {
return d;
})
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "white")
.attr("text-anchor", "middle")
.attr("x", function(d, i) {
return ...;
})
.attr("y", function(d) {
return ...;
});
其中dataset
是一个数组数组。 d
将对应[12, 34, 65]
。我需要一种方法将其拆分为单个数字,并为每个数字指定y
。同时x
显然应该对每个栏保持不变。还希望通过改变与数字对应的每个片段的颜色,将每个条形分割成与每个数字对应的部分,或者通过绘制黑白数字或更好的数字。
答案 0 :(得分:2)
好的我有一个数据集,其中我有一个数组形式的标签,你说每个栏都有自己的数字数组,比如[12, 34, 65]
{
"letter": "B",
"frequency": 0.03492,
label: [10, 20, 30]//this is the array which will be displayed on bar's top middle bottom
}
要在条形图上附加标签,请执行以下操作
var rects = svg.selectAll(".bar")
.data(data)
.enter().append("g");
//make the bars
rects.append("rect")
.attr("class", "bar")
.attr("x", function (d) {
return x(d.letter);
})
.attr("width", x.rangeBand())
.attr("y", function (d) {
return y(d.frequency);
})
.attr("height", function (d) {
return height - y(d.frequency);
});
//text @ the top
rects.append("text")
.attr("x", function (d) {
return x(d.letter) + x.rangeBand() / 2;
})
.attr("y", function (d) {
return y(d.frequency) + 10;
}).attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "white")
.attr("text-anchor", "middle")
.attr("dy", ".35em")
.text(function (d) {
return d.label[0];
});
//text @ the middle
rects.append("text")
.attr("x", function (d) {
return x(d.letter) + x.rangeBand() / 2;
})
.attr("y", function (d) {
return (height + y(d.frequency))/2;
}).attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "white")
.attr("text-anchor", "middle")
.attr("dy", ".35em")
.text(function (d) {
return d.label[1];
});
//text @ the bottom
rects.append("text")
.attr("x", function (d) {
return x(d.letter) + x.rangeBand() / 2;
})
.attr("y", function (d) {
return height - 10;
}).attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "white")
.attr("text-anchor", "middle")
.attr("dy", ".35em")
.text(function (d) {
return d.label[2];
});
工作代码here
希望这有帮助!
答案 1 :(得分:1)
要解决您的问题,您需要处理nested data with d3,即您需要先为每个堆叠条创建一个组:
var stacks = root.selectAll("g.stack")
.data(dataset)
.enter()
.append("g").attr("class","stack")
然后,对于每个堆栈,通过使用从父数据中提取嵌套数组的新data
函数,创建一个新的选择,将嵌套数组作为数据。
var bars = stacks.selectAll("g.bar")
.data(function(d, i) { return d; })
.enter().append(...)
对于堆叠中的每个条形,您可以使用不同的颜色,例如,使用d3.scale.category10
。
这是完整的例子:
var root = d3.selectAll("svg>g#root")
var dataset = [[10,20,50],[70,40,10],[20,40,10]]
var color = d3.scale.category10()
dataset.forEach( function(d) {
d.sort( function(a,b) { return b-a; } )
})
var stacks = root.selectAll("g.stack")
.data(dataset)
.enter()
.append("g").attr("class","stack")
.attr("transform", function(d,i) {
return "translate(0,"+ (i * 30) +")"
})
var bars = stacks.selectAll("g.bar")
.data(function(d, i) { return d; })
.enter()
.append("g").attr("class","bar")
var barWidth = function(d,i) { return d * 2 }
var barColor = function(d,i) { return color(i) }
bars.append("rect")
.attr("height", "20")
.attr("x", "0")
.attr("y", "0")
.attr("width", barWidth )
.style("fill", barColor )
bars.append("text")
.text( function(d) { return d } )
.attr("x", barWidth )
.attr("y", 9)
.attr("transform", "translate(-10,0)" )
svg { border: solid 1px gray }
svg text {
font-family: sans-serif;
font-size: 11px;
fill: white;
text-anchor: middle;
}
svg rect {
fill: gray;
stroke: black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<svg width=200 height=100 id="container"
style="border: solid 1px gray">
<g id="root" transform="translate(10,10)"></g>
</svg>
请注意,为简洁起见,该示例不使用任何d3.scale
将数据空间转换为几何空间。有关详细信息,请参阅d3 wiki。
该示例当前假设数组中的值是绝对值,即所有条形均以x="0"
开始。如果您需要实际堆叠相对值,我建议首先为每个条形预先计算x
的相应值,方法是将已排序的嵌套数组的先前值相加:
var sum = function(a,b) { return a+b }
var derivedData = dataset.map( function(d,i) {
d.sort( function(a,b) { return b-a; } )
return d.map( function(v,i) {
// `value` determines the width or height of a bar
// `sum` determines the position of the bar
return { value: v, sum: d.slice(0,i+1).reduce(sum) }
})
})