Is there any way I could iterate through all circle elements that I added to a graph? For example, let's say I created four circles on a graph with specific id values. If I want to find a circle element with a specific id, how should I got about doing that?
You would do something like
svg.selectAll("circle").filter(function(d) { return d.id == myid; });
assuming that you have bound data to the circles that contains an .id attribute.
Related
I have an heatmap that show some data and a sparkline for each line of the heatmap.
If the user click on a row label, then the data are ordered in decreasing order, so each rect is placed in the right position.
Viceversa, if the user click on a column label.
Each react is placed in the right way but I'm not able to place the sparkline.
Here the code.
When the user click on a row label, also the path inside the svg containing the sparkline should be updated.
And then, when the user click on a column label, the svg containing the sparkline should be placed in the correct line.
To place the svg in the right place, I try to use the x and y attributes of svg. They are updated but the svg doesn't change its position. Why?
Here is a piece of code related to that:
var t = svg.transition().duration(1000);
var values = [];
var sorted;
sorted = d3.range(numRegions).sort(function(a, b) {
if(sortOrder) {
return values[b] - values[a];
}
else {
return values[a] - values[b];
}
});
t.selectAll('.rowLabel')
.attr('y', function(d, k) {
return sorted.indexOf(k) * cellSize;
});
Also, I don't know how to change the path of every sparkline svg. I could take the data and order them manually, but this is only good for the row on which the user has clicked and not for all the others.
How can I do?
The vertical and horizontal re-positioning/redrawing of those sparklines require different approaches:
Vertical adjustment
For this solution I'm using selection.sort, which:
Returns a new selection that contains a copy of each group in this selection sorted according to the compare function. After sorting, re-inserts elements to match the resulting order.
So, first, we set our selection:
var sortedSVG = d3.selectAll(".data-svg")
Then, since selection.sort deals with data, we bind the datum, which is the index of the SVG regarding your sorted array:
.datum(function(d){
return sorted.indexOf(+this.dataset.r)
})
Finally, we compare them in ascending order:
.sort(function(a,b){
return d3.ascending(a,b)
});
Have in mind that the change is immediate, not a slow and nice transition. This is because the elements are re-positioned in the DOM, and the new structure is painted immediately. For having a slow transition, you'll have to deal with HTML and CSS inside the container div (which may be worth a new specific question).
Horizontal adjustment
The issue here is getting all the relevant data from the selection:
var sel = d3.selectAll('rect[data-r=\'' + k + '\']')
.each(function() {
arr.push({value:+d3.select(this).attr('data-value'),
pos: +d3.select(this).attr('data-c')});
});
And sorting it according to data-c. After that, we map the result to a simple array:
var result = arr.sort(function(a,b){
return sorted.indexOf(a.pos) - sorted.indexOf(b.pos)
}).map(function(d){
return d.value
});
Conclusion
Here is the updated Plunker: http://next.plnkr.co/edit/85fIXWxmX0l42cHx or http://plnkr.co/edit/85fIXWxmX0l42cHx
PS: You'll need to re-position the circles as well.
For the following Fiddle I'd like to hide the root node. Any help is appreciated, to view the code please view the fiddle.
I imagine I would do something like the following but I'm unsure of how/where to implement it:
if (d.depth > 0) {
...node is drawn
}
Image below:
Not drawing it is not "drawing it with zero opacity" or "hidden display". It's actually not appending the element.
Therefore, the simplest option is removing it from the data array. Just filter out the first node:
nodes = nodes.filter(function(d){
return d.depth != 0;
})
As 0 is falsy, this is the same of:
nodes = nodes.filter(function(d){
return d.depth;
})
And also filter out all links from it:
links = links.filter(function(d){
return d.depth != 1;
})
Here is your updated fiddle: https://jsfiddle.net/wa21csbc/
Also, since those elements are not painted anymore, you can move the dataviz to the left, thus occupying the empty SVG space. That space is there because we're filtering out the first node after d3.tree() calculated the positions.
I am new to d3.js, I am creating a visualization based on surburst. Can somebody let me know how I can get siblings elements external element in d3.js.
The main part of building the hierarchy from your data will be done by d3. Check the spec for partition.nodes(root) on how this information is put into the nodes. Basically, d3 will populate each node with a reference to its parent and its children providing all that is needed to navigate the hierarchy.
As a starting point you may have a look at this sunburst diagram. When hovering over an arc, this arc as well as its ancestors up to the root node are highlighted. The selection of nodes up the hierarchy which are to be highlighted takes place in a single function:
// Given a node in a partition layout, return an array of all of its ancestor
// nodes, highest first, but excluding the root.
function getAncestors(node) {
var path = [];
var current = node;
while (current.parent) {
path.unshift(current);
current = current.parent;
}
return path;
}
An even simpler version of this function will select the node and its siblings instead of the ancestors:
function getAncestors(node) {
return node.parent.children;
}
I adapted the above example to a plunk demonstrating how this may help solve your problem. In this plunk the hovered node and its siblings will get highlighted.
Take this simple grouped column chart. The data values are passed in this format:
{
"Group1": [group1_subvalue1, group1_subvalue2.....],
"Group2": [group2_subvalue1, group2_subvalue2.....],
....
}
I'd like to sort each group individually, i.e.: for each state, order the columns from taller to narrower. But I'm unable to find a way to do it. In the given example, the array for each group must be in the same order (first people under 5 y.o, 5 to 13 after that, and so on), so I don't know how to face the problem.
To show how to sort each group individually, I took Mike Bostock's example to adjusted it accordingly.
You have to do the following things:
You sort the within-group categories (in the example it's the d.ages Array)
d.ages.sort(function(a, b) { return d3.ascending(a.value, b.value); });
x1 is your scale for the within group categories. Instead of mapping the categories to the same relative position, you just map the index of your sorted array to the x position. d3.range() creates an array which is your domain.
x1.domain(d3.range(0, data[0].ages.length)).rangeRoundBands([0, x0.rangeBand()]);
When you draw, you just call the index instead of the category
.attr("x", function(d, i) { return x1(i); })
The full working example is here.
I have also added how to sort the groups.
I've got an existing svg with a bunch of polygons. Each polygon has a unique id, and with each id, I have some associated data.
My question is this: If I do the natural d3 join:
d3.selectAll("polygon").data(array_of_data)
Is there anyway to insure that the data element associated with a polygon is the correct one?
Or do I just need to keep the order of the array_of_data the same as the order of the selected polygons?
D3's data() function takes an optional second argument that is intended to provide just such a correspondence between datum and DOM nodes. Try this:
d3.selectAll('polygon').data(array_of_data, function(d) { return d.id; });
That second argument to data() is a callback function that, when called with a datum, returns the key that binds each DOM node to it's corresponding datum. When you don't provide such a function, D3 is left with no option but to use the index to bind datum to DOM nodes.