Stack matrix in d3 without remapping in json

The documents for the d3 d3.stack stacking function show an example with an array of objects (each json object representing a collection of points for any x axis is measured). For instance:

 var data = [ {month: new Date(2015, 0, 1), apples: 3840, bananas: 1920, cherries: 960}, {month: new Date(2015, 1, 1), apples: 1600, bananas: 1440, cherries: 720} ] 

I am trying to create a complex histogram with a matrix of data series ( [ [], [], [], etc ] ). It is easy enough to iterate through the lines and get a series of histograms (after setting the x scale and domain in another place):

 for(let i=0; i<data.length; i++){ bins[i] = d3.histogram() .domain(x.domain()) .thresholds(x.ticks(10)) (data[i]); } 

And create groups for each data series inside another loop:

 let bars = this.svg.selectAll(".series" + i) .data(this.bins[i]) .enter().append("g") .classed("series" + i, true) 

But of course, I do it in such a way that I'm stuck here. How can I bars.append("rect") find the correct x, y coordinates for this particular series? In other words, I have a really useful array of bins at the moment, looking something like this:

 [ [[1,2,3,3], [5,8,9], [10], ... etc], //series0 grouping by bins of 5 [[1,3], [7,7,9,9], [11], ... etc], //series1 [[2,3,3], [8,9], [10,12], ... etc], //series2 ...etc ] 

Is there a way to call stack without iterating over all the data in the json key, a pair of values?

+2
source share
1 answer

I looked at the source and no comments + single char = variables I understand that this will not happen without iterating. Therefore, I present my unsuccessful attempt to save someone else for a while:

 /* * Static helper method to transform an array of histogram bins into an array of objects * suitable for feeding into the d3.stack() function. * Args: * bins (array): an array of d3 histogram bins */ static processBins(bins){ let temp = {}; // the keys for temp will be the bin name (ie the bin delimiter value) // now create an object with a key for each bin, and an empty object as a placeholder for the data bins[0].map( (bin) => { temp[bin.x0] = {}}); for(let i=0; i<bins.length; i++){ //traverse each series bins[i].map( bin => { temp[bin.x0]["series"+i] = bin.length; //push the frequency counts for each series }); } /* now we have an object whose top-level keys are the bins: { binName0: { series0: freqCount0, series1: freqCount1, ...}, binName1: {...}, ... } now, finally we're going to make an arrays of objects containing all the series' freqencies for that bin */ let result = []; for(let binName in temp){ // iterate through the bin objects let resultRow = {}; if(temp.hasOwnProperty(binName)){ resultRow["bin"] = binName; //put the bin name key/value pair into the result row for(let seriesName in temp[binName]){ //iterate through the series keys if(temp[binName].hasOwnProperty([seriesName])){ resultRow[seriesName] = temp[binName][seriesName]; } } } result.push(resultRow); } return result; } 

Call:

 let stack = d3.stack().keys( bins.map( (d,i)=>{return "series"+i})); //stack based on series name keys let layers = stack(MyCoolHistogram.processBins(bins)); //and now your layers are ready to enter() into a d3 selection. 

Edit: I note that the third argument to the stack data in anonymous functions seems like an array of elements. That is, this is no longer a stack level index. For example, when grouping bars side by side: http://bl.ocks.org/mbostock/3943967

This breaks up the grouping functions that rely on this index number to calculate the x position:

 rect.attr("x", (d,i,j) => { return x(d.data.bin) + j*barWidth/numberOfSeries}); 

I assume this suggests that Mike gist is still using v3, even though it has been updated since v4 was released.

To get the index of a layer, you must directly use the layer.index attribute. Therefore, when grouping you would translate the entire layer (which, of course, spins the animation "per barrel").

 let layers = d3.stack(yourData); let layer = this.svg.selectAll(".layer") .data(layers) layer.transition() .attr("transform", d => { return "translate(" + d.index*barWidth/numberOfSeries + ",0)"; }); 
+1
source

All Articles