Expand IndentedTree to specific element - nvd3.js

Is there a way to programatically expand an nvd3 IndentedTree as in http://nvd3.org/examples/indentedtree.html to a specific element of the tree and add a class "active" to this element?
Thanks!

Found it.
NVD3 uses the "values" property of a tree node to mark expanded elements, and "_values" for collapsed elements.
So, if you want to expand/collapse a tree or part of it, you move the content from _values to values or vice versa. After that, call chart.update() to get a redraw.
In addition, to add a class "active" to the element containing the tree node, I used the "classes" callback of the columns array. The callback runs on the child element of the table data element:
classes: function(d) {
if (d.isSelected) {
d3.select(this.parentNode).attr("class", "active");
}
}
"isSelected" is a property I added to the current node.

Related

how to get silbling elements in sunburst

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.

d3.js How to make all the nodes collapsed in Collapsible indented Tree

I am trying to work on a sample d3 collapsible tree. mbostock’s block #1093025. Initially when the form is loaded, how do i make all the nodes collapsed initially?
The way the nodes are collapsed in this example is by removing the .children member of the data elements such that no children are drawn. You can do this statically to have everything collapsed to start with. The code would look like this.
function moveChildren(node) {
if(node.children) {
node.children.forEach(function(c) { moveChildren(c); });
node._children = node.children;
node.children = null;
}
}
moveChildren(json);
Modified example here.
You have to add a function for that in your json loading.
Check that example : http://mbostock.github.io/d3/talk/20111018/tree.html

Constraining d3 force layout graphs based on node degree

I have a force layout with potentially a very large number of nodes, too large for the graph to render responsively. I was thinking that one way to improve the performance of the system was to prune the graph by eliminating nodes based on in- and out-degree when the number of nodes gets too large.
Recomputing the node and link lists is a bit of a nuisance because links are related to indexes in the node array, and so all the links would need to be re-built.
It seems more elegant to be able to mark individual nodes for exclusion (analogously to the way some nodes are fixed) and have the layout algorithm skip those nodes. This would allow me to dynamically select subsets of the graph to show, while preserving as much state for each node (e.g., position) as practical.
Has anyone implemented something like this?
UPDATE:
I tried to implement the filter suggestion, but ran into an interesting error. It appears that the filter method returns an object that does not implement enter:
qChart apply limit:2
NODES BEF: [Array[218], enter: function, exit: function, select: function, selectAll: function, attr: function…]
NODES AFT: [Array[210], select: function, selectAll: function, attr: function, classed: function, style: function…]
Uncaught TypeError: Object [object Array] has no method 'enter'
The following code is run to get from BEF to AFT:
nodeSubset = nodeSubset.filter(function(n) { return (n.sentCount() <= limit); });
UPDATE 2:
I created a jsfiddle to isolate the problem. This example implements my interpretation of ChrisJamesC's answer. When I tried to implement his suggestion directly (putting the filter after the data), the subsequent call to enter failed because the object returned by filter did not have enter defined.
The goal is to make the layout select only those nodes that have active == true, so in this example, this means that node b should be excluded.
You can use the selection.filter() option combined with the node.weight attribute.
What you would normally do is:
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("circle")
Here you can do:
var node = svg.selectAll(".node")
.data(graph.nodes)
.filter(function(d){return d.weight>3})
.enter();
You might also have to remove from drawing the links going to these nodes using the same method.
EDIT You should just filter the data you provide if you want to mark nodes as active directly in the data array (and do the same for links)
var node = svg.selectAll(".node")
.data(force.nodes().filter(function(d) { return d.active; }));
var link = svg.selectAll(".link")
.data(force.links().filter(function(d) {
var show = d.source.active && d.target.active;
if (show)
console.log("kept", d);
else
console.log("excluded", d);
return show;
}) );
Fiddle
If you want to do this by computing the weight of each node, I would still recommend you to do this before passing the nodes and links to the graph and mark nodes as active or not following a specific criteria, then filter the links according to active nodes. Otherwise you would have to load the whole force directed layout only to get the weight to then filter the data to re-load the force directed graph.

make sure d3 data element matches id?

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.

Sub-selection based on function

I have a selection of elements that I'm trying to filter down based on a particular style value (I want just the ones with opacity=1). I'm looking at the documentation for selection.filter along with selection.select and selection.selectAll as well but I'm confused about the correct usage with a function argument.
"select" indicates that it selects the first matching element (as expected) but then the example in the filter documentation shows it being used with a function to select the "odd" elements while maintaining the index.
"selectAll" indicates that you can return an array of elements, but that the function argument is invoked one-by-one in the usual way for each element in the original selection. I'm having difficulty imagining a use case for this.
I guess what I'm wondering is whether there are any tutorials or examples around that discuss the correct usage of these functions?
Thanks,
scott
If you want to reduce a selection to a subset of selected elements, use filter. If you want to select descendent elements, use select or selectAll.
Most often, filter is used to filter elements based on data or index. However, you can access the selected element as this within the filter function. Thus, if you have some elements selected, and you want to reduce that selection to only those elements with an opacity of 1, you can say:
var opaque = selection.filter(function() {
return this.style.opacity == 1;
});
To be safe, you might prefer to look at the computed style rather than the element's style properties. This way, if the opacity is inherited from a stylesheet, you'll get the correct value; otherwise, when a style is inherited this.style.opacity will be the empty string.
var opaque = selection.filter(function() {
return window.getComputedStyle(this, null).getPropertyValue("opacity") == 1;
});
Or equivalently, select the node and use selection.style:
var opaque = selection.filter(function() {
return d3.select(this).style("opacity") == 1;
});
You might find it easier if you filter by data or by class, instead of by computed style property. For example, if you set a class on your nodes, you can filter a selection by class instead:
var opaque = selection.filter(".opaque");

Resources