问题
I'm trying to update a grouped bar chart with varying groups along the x axis (depending on the data).
Here is the fiddle: https://jsfiddle.net/mrl513/arjcq9ka/ Use the radio button to see the update.
The issue is that I need to update the x1 domain (range bands), by calling exit on existing rangebands. The original range bands are retained on the first 4 data groups.
1st data set has 4 groups. 2nd data set has 8 groups
You can see on the fiddle that when the second button is selected (it has 8 gps) the first 4 gps retain the original range band.
thanks for any input!
function updategp(data) {
var ageNames = d3.keys(data[0]).filter(function(key) { return key !== "state"; });
data.forEach(function(d) {d.ages = ageNames.map(function(name) { return {name: name, value: +d[name]}; });
});
x0.domain(data.map(function(d) { return d.state; }));
x1.domain(ageNames).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(data, function(d) { return d3.max(d.ages, function(d) { return d.value; }); })]);
//etc.. see fiddle
回答1:
I don't understand your data very well but it seems to me that the data between two views are not related. Therefore, I think you should change the transitions such that no bars are kept and moved to another location when you change the view by pressing the radio button. Keeping and changing elements should only be used if the two states are related (for example, same groups but different years). From Mike Bostocks excellent guide to object constancy:
Above all, animation should be meaningful. While it may be visually impressive for bars to fly around the screen during transitions, animation should only be used when it enhances understanding. Transitions between unrelated datasets or dimensions (e.g., from temperature to stock price) should use a simpler cross-fade or cut rather than gratuitous, nonsensical movement.
So in your case I would exit all the bars by collapsing them to the x-axis and then enter new bars by expanding them from the x-axis. To do that you first need to add a key function to .data()
, which makes sure that new data is not added to the existing elements but instead to new ones (not yet existing elements). One possible key function is as follows:
var state = chart.selectAll(".state")
.data(data, function(d){return JSON.stringify(d)});
Then exit the bars by collapsing them to x-axis:
state.exit().transition().duration(1000).selectAll("rect")
.attr("y", height)
.attr("height", 0)
.remove();
And enter new bars with 1000 ms delay (or 0 ms delay during the initial loading) by growing them up from the x-axis:
bars.enter().append("rect")
.attr("width", x1.rangeBand())
.attr("x", function(d) { return x1(d.name); })
.attr("y", height) //start from x-axis
.attr("height", 0) //with initial length of 0
.style("fill", function(d) { return color2(d.name); });
bars.transition()
.delay(function(){
return state.exit()[0].length > 0 ? 1000 : 0;
})
.duration(1000)
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); })
.style("fill", function(d) { return color2(d.name); });
I updated the fiddle to show these changes in action.
回答2:
I saw the problem and resolved it - during the transition on the sub-groups I wasn't calling the width and x attributes, so they weren't being udpated.
来源:https://stackoverflow.com/questions/38921456/d3-updating-x-axis-groups-on-grouped-bar-chart