Reputation: 16412
I'm using D3 to achieve a visualization with a partition layout. What I need is the divided sections have equally the same width, like this:
But what I currently have is this:
You can find the current version working here on Codepen, but I copy the code here also:
var w = 960,
h = 500,
x = d3.scale.linear().range([0, w]),
y = d3.scale.linear().range([0, h]),
color = d3.scale.ordinal().range(["rgb(255,247,236)","rgb(254,232,200)","rgb(253,212,158)","rgb(253,187,132)","rgb(252,141,89)","rgb(239,101,72)","rgb(215,48,31)","rgb(179,0,0)","rgb(127,0,0)"]);
var vis = d3.select("#chart").append("svg:svg")
.attr("width", w)
.attr("height", h);
var partition = d3.layout.partition()
.children(function(d) { return isNaN(d.value) ? d3.entries(d.value) : null; })
.value(function(d) { return d.value; });
var data = {
'root': {
'asdf': {
'a': {
'kdjfklsfj': 1,
'kdjfklsfsj': 1
},
'b': 1
},
'bnm': {
'c': 1,
'd': {
'lsdkjfdkljsf': {
'lsdkfj': 1,
'kldsjfdlk': 1
},
'kdjfkjsdfk': 1
}
}
}
};
var rect = vis.selectAll("rect")
.data(partition(d3.entries(data)[0]))
.enter().append("svg:rect")
.attr("x", function(d) { return x(d.x); })
.attr("y", function(d) { return y(d.y); })
.attr("width", function(d) { return x(d.dx); })
.attr("height", function(d) { return y(d.dy); })
.attr("fill", function(d) { return color((d.children ? d : d.parent).data.key); })
.on("click", click);
function click(d) {
x.domain([d.x, d.x + d.dx]);
y.domain([d.y, 1]).range([d.y ? 20 : 0, h]);
rect.transition()
.duration(750)
.attr("x", function(d) { return x(d.x); })
.attr("y", function(d) { return y(d.y); })
.attr("width", function(d) { return x(d.x + d.dx) - x(d.x); })
.attr("height", function(d) { return y(d.y + d.dy) - y(d.y); });
}
What I found is that altering the data values (currently all items are valued "1"), increase the width of the elements naturally, but how can I make it have a equally divided boxes?
Upvotes: 1
Views: 5333
Reputation: 6587
You're telling the partition function to calculate the width of each block as either the value (if it has one), or the sum of its children's values. It sounds like you want to use the number of children as the weight in the latter case, so that e.g. the top node is split into 1/2 and 1/2 instead of 4/7 and 3/7.
Edit: The d3's partition() object is designed to determine the size of a parent elements based on the sum of the sizes of its children, whereas (if I understand your use case) you want the sizes of the children to be apportioned from the size of their parents, based on the number of its siblings.
To get this to work you'll have to manage the leaf node object values to 'trick' d3 into doing what you want. Here's a data
object that gets the first level to have even lengths:
var data = {
'root': {
'asdf': {
'a': {
'kdjfklsfj': 1/6,
'kdjfklsfsj': 1/6
},
'b': 1/6
},
'bnm': {
'c': 1/8,
'd': {
'lsdkjfdkljsf': {
'lsdkfj': 1/8,
'kldsjfdlk': 1/8
},
'kdjfkjsdfk': 1/8
}
}
}
};
In other words, you have to manage the data to fit d3's expectations. It's not d3 manipulation that should do this, it's your data generator.
Upvotes: 1