vasturiano/force-graph

Nodes pull away from connected node with fx/fy set

Opened this issue · 6 comments

Hi,

I am setting the node.fx and node.fy in order to pin a node to a spot but it seems like nodes try to pull alway from that node drastically. I am not sure how to adjust the forces to make it so they do a normal pinwheel even though the middle node is "pinned".

Glad to see this git is active, any help would be appreciated!

Graph without a pinned node (no .fx .fy):

graph without fxfy

Graph with one pinned node (NE)

graph nodes pull away from fxfy

The further I drag the node the more extreme and if there are multiple pinned nodes, new ones tend to fly away.

graph extreme

@chodanics that has to do with the center force which tries to establish a mass center at coordinates 0,0, and can only do that by moving the non fixed nodes.

I'd recommend switching off that force when bumping into this problem with fixed nodes:

myGraph.d3Force('center', null)

Great! This helped the expected behavior a lot. Is there a way to set the center.strength to something very small? Or set the center force to apply to specific nodes?

Also, we had some nodes that really seemed to want to fly far away from the center majority of the nodes. Does the fixed (fx,fy) location of the nodes have any affect on this, or is it just the amount of nodes in the area?

Thanks again.

@chodanics I recommend reading a bit about the centering force to help understand its behaviour and how you can control it:
https://github.com/d3/d3-force#centering

Thanks for the link @vasturiano. Do you have any examples showing how to implement something from the d3 docs in the force-graph implementation?

The main thing I need to accomplish is to prevent nodes from slowly drifting apart after removing the center force. After several updates (we update on a timeline of events), the nodes drift apart if the nodes have not been placed using fx/fy.

Ideally we would be able to set specific nodes to have a center force on them only but anything that would prevent drift and still allow the simulation to adjust positions would work.

Relevant config:

this.graph.d3AlphaDecay(0.05) // default is .0228
        .d3VelocityDecay(0.43) // default is .4
// set forces
this.graph.d3AlphaDecay(0.05) // default is .0228
        .d3VelocityDecay(0.45); // default is .4
this.graph.d3Force('collide', d3.forceCollide().radius(10));
this.graph.d3Force('center').strength(0.00005);
this.graph.d3Force('charge')
        .strength(-5)
        .distanceMax(1000);

Any help would be greatly appreciated!

@chodanics which specific functionality from the d3 docs are you interested in applying?

As for containing the drift, you could try to maintain the forceCenter active but just keep updating its center coordinates (via .x and .y) to the center of gravity of all the fixed nodes. You could perform this operation whenever a fixed node gets toggle on/off. Hopefully it eases the initial problem that you had and makes it less jarring.

Another approach is to periodically invoke the .zoomToFit() graph method that moves the canvas boundaries to fit all the nodes currently in the scene. But the result is that you'll see fixed nodes moving, as well as zoom levels changing automatically, which may be less ideal depending on your use case.

Thanks for the insight. I think the collision example containing .d3Force('collide', d3.forceCollide().... answered my question about applying d3 code to force-graph.

I think the drift is ok with a forceCenter and a very small strength. Just FYI, the fixed nodes are fine (they stay put!) but other nodes not connected by a link were slightly drifting apart when I tried setting the forceCenter to null.

If I am understanding force_initialize correctly, could I do something like:

this.graph.d3Force('center').strength(0.00005); // everyone favors the middle
this.graph.d3Force('centerImportant', d3.forceCenter());
this.graph.d3Force('centerImportant').strength(1).initialize(keyNodes); // center important nodes```

Reiterating my many thanks for the help and great library!