首先对不起,如果我的英语很难理解,我会尽我所能......
我对D3.js很新,我试图使用嵌套数据创建D3分组条形图。我已经看过这里分享的一些解决方案,但它们只显示了一级分组。就我而言,数据将来自具有此数据结构的csv文件:
groups,categories,value 1,value 2,value 3
group 1,A,61.0158803,25.903359,13.08076071
group 1,B,71.27703826,21.0180133,7.70494844
group 1,C,82.70203982,13.52731445,3.770645737
group 2,A,58.85721523,28.25939061,12.88339417
group 2,B,71.39695487,20.66010982,7.942935308
group 2,C,82.22389321,13.68924542,4.08686137
该图表有两个x轴,一个用于组(级别0),另一个用于类别(级别1)。值1到3将显示为每个catergory的分组条形,并且将显示类别在相应的组内。
图表的结构应为:
value 1 | value 2 | value 3 | value 1 | value 2 | value 3 | value 1 | value 2 | value 3 |
| category A | category B | category C |
| group 1 |
和第2组相同,放置连续。
问题在于我正在处理的代码,我得到了正确的轴,但是在每个组区域中显示了对应于两个组的数据,一个在另一个的顶部。我无法将类别上的数据链接到其对应的组中,以便在相应的位置绘制它们。
以下是我到目前为止所获得的代码:
var x0 = d3.scale.ordinal()
.rangeRoundBands([0,width], 0);
var x1 = d3.scale.ordinal()
.rangeRoundBands([0,width]);
var x2 = d3.scale.ordinal();
var y = d3.scale.linear()
.range([height,0]);
var color = d3.scale.category10();
var x0Axis = d3.svg.axis()
.scale(x0)
.orient("bottom");
var x1Axis = d3.svg.axis()
.scale(x1)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var svg = d3.select(".chart")
.append("svg")
.attr("class", "svg")
.attr("viewBox", "" + margin* -1 + " " + margin* -1 + " " + (width + margin*2) + " " + (height + margin *2) + "")
.attr ("preserveAspectRatio", "xMidYMid")
.attr("width", "100%")
.attr("height", "100%")
d3.csv("../data/EQ01.csv", function(error, data){
if (error) throw error;
var seriesNames = d3.keys(data[0]).filter(function(key) { return key !== "categories" && key !== "groups";});
data.forEach(function(d) {
d.values = seriesNames.map(function(name) { return {
xValue: name,
yValue: +d[name]
};
});
});
nested = d3.nest()
.key(function(d) { return d.groups})
.key(function(d) { return d.categories})
.entries(data);
y.domain([0, d3.max(data, function(d) { return d3.max(d.values, function(d) { return d.yValue; }); })]);
x0.domain(nested.map(function(d) {return d.key;}));
x1.domain(data.map(function(d) { return d.categories; })).rangeRoundBands([0, x0.rangeBand() ], 0.1);
x2.domain(seriesNames).rangeRoundBands([0, x1.rangeBand()], 0);
svg.append("g")
.attr("class", "x0 axis")
.attr("transform", "translate(0," + (height+30) + ")")
.call(x0Axis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
var group = svg.selectAll(".group")
.data(nested)
.enter().append("g")
.attr("class", "group")
.attr("transform", function(d) { return "translate(" + x0(d.key) + ",0)"; });
group.append("g")
.attr("class", "x1 axis")
.attr("transform", "translate(0," + height + ")")
.call(x1Axis);
var category = group.selectAll(".category")
.data(data)
.enter().append("g")
.attr("class", "category")
.attr("transform", function(d) { return "translate(" + x1(d.categories) + ",0)"; });
category.selectAll("rect")
.data(function(d) { return d.values; })
.enter().append("rect")
.attr("width", x2.rangeBand())
.attr("x", function(d) { return x2(d.xValue); })
.attr("y", function(d) { return y(d.yValue); })
.attr("height", function(d) { return height - y(d.yValue); })
.style("fill", function(d){return color(d.xValue)})
非常感谢您的帮助!
答案 0 :(得分:5)
问题是您没有正确加入您的数据。
我们需要构建不同的比例才能获得正确的rangeBand
值。
var x_groups = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var x_categories = d3.scale.ordinal();
var x_values = d3.scale.ordinal();
我创建了一个嵌套数据结构,其中包含了我们的分组条形图方法所需的一切。
var nested = d3.nest()
.key(function(d) {
return d.groups;
})
.key(function(d) {
return d.categories;
})
.rollup(function(leaves) {
return [{
key: 'v-a',
value: leaves[0]['value 1']
}, {
key: 'v-b',
value: leaves[0]['value 2']
}, {
key: 'v-c',
value: leaves[0]['value 3']
}];
})
.entries(data);
接下来,让我们使用我们刚刚获得的信息配置我们的比例。
x_groups.domain(nested.map(function(d) {
return d.key;
}));
//var categories = ['A', 'B', 'C'];
var categories = nested[0].values.map(function(d, i) {
return d.key;
});
x_categories.domain(categories).rangeRoundBands([0, x_groups.rangeBand()]);
//var values = ['value 1', 'value 2', 'value 3'];
var values = nested[0].values[0].values.map(function(d, i) {
return d.key;
});
x_values.domain(values).rangeRoundBands([0, x_categories.rangeBand()]);
然后我们终于可以开始我们的数据连接了。您可以看到,当我们输入新的信息级别时,我们需要正确设置data
函数。
var groups_g = svg.selectAll(".group")
.data(nested)
.enter().append("g")
.attr("class", function(d) {
return 'group group-' + d.key;
})
.attr("transform", function(d) {
return "translate(" + x_groups(d.key) + ",0)";
});
var categories_g = groups_g.selectAll(".category")
.data(function(d) {
return d.values;
})
.enter().append("g")
.attr("class", function(d) {
return 'category category-' + d.key;
})
.attr("transform", function(d) {
return "translate(" + x_categories(d.key) + ",0)";
});
var categories_labels = categories_g.selectAll('.category-label')
.data(function(d) {
return [d.key];
})
.enter().append("text")
.attr("class", function(d) {
return 'category-label category-label-' + d;
})
.attr("x", function(d) {
return x_categories.rangeBand() / 2;
})
.attr('y', function(d) {
return height + 25;
})
.attr('text-anchor', 'middle')
.text(function(d) {
return d;
})
var values_g = categories_g.selectAll(".value")
.data(function(d) {
return d.values;
})
.enter().append("g")
.attr("class", function(d) {
return 'value value-' + d.key;
})
.attr("transform", function(d) {
return "translate(" + x_values(d.key) + ",0)";
});
var values_labels = values_g.selectAll('.value-label')
.data(function(d) {
return [d.key];
})
.enter().append("text")
.attr("class", function(d) {
return 'value-label value-label-' + d;
})
.attr("x", function(d) {
return x_values.rangeBand() / 2;
})
.attr('y', function(d) {
return height + 10;
})
.attr('text-anchor', 'middle')
.text(function(d) {
return d;
})
var rects = values_g.selectAll('.rect')
.data(function(d) {
return [d];
})
.enter().append("rect")
.attr("class", "rect")
.attr("width", x_values.rangeBand())
.attr("x", function(d) {
return 0;
})
.attr("y", function(d) {
return y(d.value);
})
.attr("height", function(d) {
return height - y(d.value);
})
.style("fill", function(d) {
return color(d.key);
});
工作plnkr:https://plnkr.co/edit/qGZ1YuyFZnVtp04bqZki?p=preview