質問

I am trying to get a stacked bar chart to transition in the same way as this bar chart - http://www.animatedcreations.net/d3/animatedBarChart_Slide.html I have been following Mike Bostock's "A bar chart, part 2" example, and things are OK up to transitioning the stacked bars in and out.
My broken example is here - http://www.animatedcreations.net/d3/stackedBarChart7.html I am reasonably sure the problem is with how I set up the data, as shown below. I am even wondering if the data needs to be transformed to be in columns rather than layers? Insight much appreciated :) Thanks.

From redraw():

// stack the new data
var stacked = d3.layout.stack()(["act1", "act2","act3","other"].map(function(activity){
    return stats.map(function(d) {
        return {x:(d.hour), y: +d[activity]};
    });
}));

// update x axis 
x.domain(stacked[0].map(function(d) { return d.x; })); 

var valgroup = graph.selectAll("g.valgroup").data(stacked);

// want the data in d.  var rect contains the data AND functions. 
// I am guessing this is where it all breaks??
var rect = valgroup.selectAll("rect")
    .data((function(d) { return d; }), (function(d) { return d.x; }));   
         // new data set.  slide by hour on x axis.
役に立ちましたか?

解決

In this problem, the transitions are clearly the trickiest part, so I prefered to go from the simple bar example you provided and go to the stacked bar chart using Mike Bostock's example.

The principal problem with the stacked implementation you provide is that the information is "reversed" as you would want each bar to be in a different element of the data array, this way you can identify your data by its time stamp.

So, first, let's define some data with an array of values for each element:

function next () {
    return {
        time: ++t,
        value: d3.range(3).map(getRand)
    };
}

Then, inside of the redraw() function:

  • First format the data for the bar stacks:

    customData = data.map(function(d){
        y0=0
        return {value:d.value.map(function(d){return {y0:y0, y1: y0+=d}}), time:d.time}
    })
    
  • Then create the group for each stack of bar

    var state = graph.selectAll(".g")
        .data(customData, function(d) { return d.time; });
    var stateEnter = state.enter().append("g")
        .attr("class", "g")
        .attr("transform", function(d) { return "translate(" + x(d.time+1) + ",0)"; });
    
  • Then, add the stack of bars of the group:

    stateEnter.selectAll("rect")
        .data(function(d) { return d.value; })
        .enter().append("rect")
        .attr("width", barWidth)
        .attr("y", function(d) {return y(d.y1); })
        .attr("height", function(d) { return y(d.y0) - y(d.y1); })
        .attr("class", "bar")
        .style("fill", function(d,i) { return color(i); });
    
  • Move every bar group to update the x values:

    state.transition().duration(1000)
        .attr("transform", function(d) {console.log(d); return "translate(" + x(d.time) + ",0)"; });
    
  • Remove old values

    state.exit()
        .attr("transform", function(d) {return "translate(" + x(d.time) + ",0)";})
        .remove()
    

Here is a working example.

PS: Next time, please provide jsFiddles so we don't have to go to the source code of your page to provide a solution. Also, try to minimize as much as possible the code of your example (remove axis, useless parsing etc) so we can concentrate on what is wrong. Also, in the process you will often find the problem by yourself as you isolate it.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top