Force Network: How to set initial position for select nodes? - d3.js

I have a simple force network graph of four nodes as an example, here:
https://jsfiddle.net/NovasTaylor/o1qesn6k/
I would like to set the initial position of node "A" using its accompanying data so the node is initially fixed at point (265,143). If I were to double-click that node it would return to being d.fixed=FALSE and the usual forces apply.
From my research here on Stackoverflow I know I need to set the inital .x and .y values as per Bostock's suggestion:
[Fix Node Position in D3 Force-Directed Layout
But I do not quite grasp where and how to do this. I have tried the following code, which I may not have placed in the right sequence. It appears to be the same as having .x and .y in the source data...which also did not work.
for (var i=0, tot=dataset.nodes.length; i < tot; i++) {
if (dataset.nodes[i].fix_x > 0) {
dataset.nodes[i].x = dataset.nodes[i].fix_x
dataset.nodes[i].y = dataset.nodes[i].fix_y
}
}
Your advice would be very much appreciated!
Tim

Related

Increasing the connecting link length in d3 when the node is expanded

I am working on collapsible force layout in d3.The problem I am facing is I need to increase the length of the link between the nodes when it is clicked keeping the link distance same among the childs.
How to increase the distance between analytics and flare when analytics is expanded keeping distance to its children small?
Yes you can do this by defining a function for the force.linkDistance
something like this:
var force = d3.layout.force()
.linkDistance(function(d){
if(d.target._children){
return 50;//target is not expanded so link distance is 50
} else {
return 200;//target is expanded so link distance is 200
}
})
Full working code here.

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.

Distribute nodes into two groups on a force diagram layout (left and right)

I have some data that Im trying to plot in a specific way:
all the nodes have a way to identify which group it belongs, let say position:L or position:R.
I would like to take that property into account an order all the "l" (left) nodes to be on the left of a central node and all of the "R" (right) nodes to be on the right hand side of a static central node (something similar like drawn in the picture ).
Previously Ive used this:
tick = function () {
nodes.forEach(function (n) {
if (n.position == "L") {
n.x -= force.alpha() * 80;
}
if (n.position == "R") {
n.x += force.alpha() * 80;
}
});
....
};
This solution was okay for small sets but when nodes reach a certain number, say a 1000+, it becomes a very expensive one.
Ive looked at these two examples:
1st one and 2nd one and I was wondering maybe I could solve may problem with combining couple of forces on the page trying to "tear" the (static) central node apart and pulling different nodes to the sides ?
Any suggestions are welcome, thank You.

D3 circle packing diameter calculation

I am using the pack layout for packing different no of equal sized circles. I have a group of clusters to be visualized. So I am calling pack function for each cluster of circles. In all the d3 examples the diameter is either calculated with the given size or fixed diameter. I would like to calculate it according to the no of circles to be packed. So how do I calculate the packing circle diameter?
is there any formula so that I can pack the circles without wasting the space.
If you truly don't care about relative sizing of the circles, then you could make your JSON file represent only the data you care about(say, names) and feed your packing function a dummy value that the 'value' accessor function is expecting.
For instance:
var circleChildren = [{
"value": 1
}, {
"value": 1
}, {
"value": 1
}, {
"value": 1
}];
would give you a JSON object that you can use as children for your packing function:
var circleInput = Object();
circleInput.children = circleChildren;
You can verify that in your console by running:
bubble.nodes(circleInput)
.filter(function (d) {
return !d.children; //we're flattening the 'parent-child' node structure
})
where bubble is your D3 packing bubble variable.
Here's a fiddle that demonstrates that. It may have some extra things but it implements what you're looking for. In addition, you can play around with the number of circles by adding more dummies in the JSON file, as well as changing the SVG container size in the diameter variable. Hope that helps!
EDIT: The size of your layout(in this case, a misnomer of the 'diameter' variable) directly determines the size and diameter of your circles within. At some point you have to assign the pack.size() or pack.radius() value in order for your circles to display within a layout(documentation ):
If size is specified, sets the available layout size to the specified two-element array of numbers representing x and y. If size is not specified, returns the current size, which defaults to 1×1.
Here you have several options:
If you want your circles to be 'dynamically' sized to your available element's width (that is, if you want them to cover up all the element width available) then I'd recommend you get your element's width beforehand, and then apply in your pack() function. The problem is then you have to think about resizing, etc.
If you want to keep the maximum sizing available, then you have to make your viz responsive. There's a really good question already in SO that deals with that.
I know this isn't the full solution but hopefully that points you in the right direction for what you're trying to do.
FURTHER EDIT:
All of a sudden, another idea came to mind. Kind of an implementation of my previous suggestion, but this would ensure you're using the maximum space available at the time for your circle drawing:
zone = d3.select("#myDiv");
myWidth = zone.style("width").substring(0, zone.style("width").length - 2);

How do I control the bounce entry of a Force Directed Graph in D3?

I've been able to build a Force Directed Graph using a Force Layout. Most features work great but the one big issue I'm having is that, on starting the layout, it bounces all over the page (in and out of the canvas boundary) before settling to its location on the canvas.
I've tried using alpha to control it but it doesn't seem to work:
// Create a force layout and bind Nodes and Links
var force = d3.layout.force()
.charge(-1000)
.nodes(nodeSet)
.links(linkSet)
.size([width/8, height/10])
.linkDistance( function(d) { if (width < height) { return width*1/3; } else { return height*1/3 } } ) // Controls edge length
.on("tick", tick)
.alpha(-5) // <---------------- HERE
.start();
Does anyone know how to properly control the entry of a Force Layout into its SVG canvas?
I wouldn't mind the graph floating in and settling slowly but the insane bounce of the entire graph isn't appealing, at all.
BTW, the Force Directed Graph example can be found at: http://bl.ocks.org/Guerino1/2879486enter link description here
Thanks for any help you can offer!
The nodes are initialized with a random position. From the documentation: "If you do not initialize the positions manually, the force layout will initialize them randomly, resulting in somewhat unpredictable behavior." You can see it in the source code:
// initialize node position based on first neighbor
function position(dimension, size) {
...
return Math.random() * size;
They will be inside the canvas boundary, but they can be pushed outside by the force. You have many solutions:
The nodes can be constrained inside the canvas: http://bl.ocks.org/mbostock/1129492
Try more charge strength and shorter links, or more friction, so the nodes will tend to bounce less
You can run the simulation without animating the nodes, only showing the end result http://bl.ocks.org/mbostock/1667139
You can initialize the nodes position https://github.com/mbostock/d3/wiki/Force-Layout#wiki-nodes (but if you place them all on the center, the repulsion will be huge and the graph will explode still more):
.
var n = nodes.length; nodes.forEach(function(d, i) {
d.x = d.y = width / n * i; });
I have been thinking about this problem too and this is the solution I came up with. I used nodejs to run the force layout tick offline and save the resulting nodes data to a json file.
I used that as the new json file for the layout. I'm not really sure it works better to be honest. I would like hear about any solutions you find.

Resources