In D3:
I have created histograms with a multi column array, "age" and "gender", using the "age" column. My histogram is made with just the "age" data. But I want to be able to also have the corresponding "gender" data stored with or in the bins for the histogram. That way I could calculate something about dealing with "gender" data for a bin when I mouseover that bin - and, again, that bin (and the whole histogram) is built on the "age" data.
Sample data:
{
"age":[22,21,30,26,28,26,23,32,30,26,34,23,33,23,34,28,34,35,31,15,26,34,32,21,35,28,27,26,24,19,21,32,23,23,23,23,28,32,22,26,32,21,25,30,23,30,21,20,28,28,26,26,31,39,25,30,36,23,38,30,30,31,23,22,28,26,23,32,26,34,28,30,24,27,26,38,24,30,34,25,28,35,22,27,26,25,29,32,26,30,33,33,31,31,37,28,27,28,29,16],
"gender":["1","0","0","0","1","1","1","1","1","1","0","1","0","0","1","0","0","0","1","1","1","1","0","0","1","0","1","0","0","1","0","0","1","0","0","1","1","0","1","1","0","1","0","0","1","1","0","0","1","0","1","1","1","0","1","1","1","0","1","1","0","1","0","1","1","1","1","1","0","1","1","0","1","0","1","1","1","1","0","0","1","0","1","1","0","0","1","1","0","1","1","1","0","1","1","0","0","1","1","0"]
}
Here is some of the code. I think it is all that corresponds directly to this issue but let me know if more is needed:
var histogram = d3.layout.histogram()
.frequency(false)
.bins(x.ticks(10));
var canvas = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
d3.json("100sample.json", function(error, data) {
//var allData = histogram(allAge.age);
var allAge = histogram(data.age);
var allBars = canvas.selectAll(".allBar")
.data(allAge)
.enter().insert("rect", ".axis")
.attr("class", "allBar")
.attr("x", function(d) { return x(d.x) + 1; })
.attr("y", function(d) { return y(d.y); })
.attr("width", x(allAge[0].dx + allAge[0].x) - x(allAge[0].x) - 1)
.attr("height", function(d) { return height - y(d.y); })
.on('mouseover', allTip.show)
.on('mouseout', allTip.hide);
I have everything working with "mouseover" and building the histogram, etc. Every age value has a corresponding gender value, but the gender value does not change the bins / histogram. I was thinking there is something at play with adding the gender values to
.data()
but somehow not calling them on the histogram layout?
How do I incorporate this extra data that corresponds to the data being used for the histogram?
--- Update ----
I understand it is necessary to bind the entire dataset to the svg / canvas allBars variable so that I can access allAge for the histogram and gender for the metadata I am trying to calculate on mouseover.
I have:
var total = [allAge, data.gender];
after creating the allAge histogram from data.age. This may not be the best way to bring in all data at once...
Now, instead of:
.data(allAge)
I have:
.data(total)
So I need to index total[0] on the histogram construction and total[1] on the metadata that will be associated with mouseover. How do I go about indexing within the allbars var - specifically within the .attr to build the histogram?
You're really close!
What you want is to call .data(data) to bind all your data, not just the ages. This will make the data available to the callbacks bound with .on at the end. So why are you passing in allAge? Well, because that's what you're getting back from the histogram function. The docs state that
The return value is an array of arrays: each element in the outer array represents a bin, and each bin contains the associated elements from the input values.
Good - so you don't lose the data by running it through the histogram function. But won't it get confused by having two arrays in a object? That's where the accessor function comes in. Chain it to where you define histogram. You might get away with function(d){return d.age} for the callback, or you may need to use an array length 2 and go by index. You can also try zipping your arrays.
I don't think you'll need to modify your .attr calls, since they operate on the bins, not the data inside them. I also recommend taking another look at how you set the width - again, you'll have to fiddle with it, but perhaps function(d){return x(d.dx) -1} would work better. It's a bit of a red flag to access the data directly in these, even if dx should be the same.
Hope that's helpful. Let me know if I'm totally off base (since I didn't write your code for you).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With