Mysterious forces in d3 force directed layout? - javascript

I'm trying to progressively combine two groups of nodes to simulate a sort of adhoc pie chart using a force layout. To do this, I'm using two groups of nodes connected via links to two fixed, animated, foci nodes, respectively. When they combine with ruffly the same number of nodes, the effect works well.
see: http://bl.ocks.org/vicapow/6191895
however, when there's a large difference in the groups of nodes, (say, 1 / 100 ), there seems to be some mysterious extra force applied to the smaller group of nodes away from the larger group
see: http://bl.ocks.org/vicapow/6191896
Does anyone have any ideas on where this extra force could be coming from?
some of the things I've tried that didn't work:
+ forcing the alpha to stay 1
+ reducing the friction

I believe what you are seeing is the lack of gravity. Without gravity the nodes will not tend towards the center of the screen. I was able to get the desired result for your edge case by setting force.gravity(1) and the charge for the nodes to -100. https://bl.ocks.org/david4096/6264697

Related

Formatting nodes in networkx to be more readable

I have a spring layout for NetworkX (rendered in cytoscape.js) which seems to be working well for small datasets, but when it gets really large, nodes keep getting too close together and makes it unreadable. The further out you go in the graph, nodes end up spreading out evenly enough. But the closer in you go to the enter (blue squares) the more compact everything is even though there's still plenty of space.
Here's the algorithm I'm trying to use:
pos = nx.spring_layout(G, k=5/np.sqrt(G.order()), iterations=150, scale=8000)
print('after',pos)
nx.draw(G, pos,node_size=2)
I tried making k=6, but it just increases the distance from it's parent node, not any nodes that might be in the vicinity.
I'm hoping to find a way to make it more readable and have the nodes be more spread out.

Cytoscape.js orphan nodes position

I am using Cytoscape.js to visualize networks.
I am currently using the cola layout which works a treat when one network (with zero orphan nodes) is generated.
However if I add an additional network on screen that is unaffiliated to the first with zero connections, on visualization the two separate networks a re positioned miles apart.
I have to manually grab one of the networks as a cluster and drag it for ages until it is closer to the other network.
My assumption is there is a way to set the distance between two graphs manually however how can I do this?
As far as I know, Cola does not have a component-packing algorithm. That would conflict with its live-animated, n-body physics simulation. Components are naturally repelled from one another, unless there is a strong gravity force to the screen's centre.
Component packing is typically a separate step for force-directed layouts, so it would give a jittery result when coupled with live animation. You may have better luck with other force-directed layouts with different trade-offs, such as FCOSE.

Cytoscape.js - positioning multiple layouts

I am currently using Cytoscape.js to display a variable amount of nodes using the circle layout. I now want/need to add additional groups of nodes around the original circle, with each group also represented in a circle layout.
The resulting visualization would look something like this:
(where each circle is a circle layout of nodes)
The additional groups don't necessarily need to be directly around the original layout, as the amount of circles also varies. I mostly just need to position the layouts such that they don't overlap each other.
I was able to add the additional groups as individual layouts, but I am unsure how to go about positioning them. I checked the docs and unless I missed something obvious, I didn't see how to accomplish what I need. Any pointers in the right direction would be appreciated!
Specify the boundingBox of each layout to tell it where the bounds of the nodes in the layout should be. Specifying a boundingBox tells the layout to put the nodes within the box. Make sure to specify adequate space and set your overlap-avoidance options appropriately. Overlap avoidance can make a layout need to use more room than it has allotted to it.

Summarise many nodes in Cytoscape.js

I am building a web app where the user can create a sort of bipartite graph like this one:
Sometimes the user would like to build a huge graph, for example a graph in which the topmost layer has 784 nodes, as in the next picture. My application can handle the computation, but the result is ugly and meaningless:
Do you have any idea for rendering a huge layer without just drawing all the nodes but, instead, summarising them with another, prettier representation?
Until now I have thought about putting all the nodes of a "huge" layer in an empty compound node, but of course then it is not possible to draw some edges (so the huge layer would seem as it were disconnected from the graph). Another solution would be to have all layers with more than 100 nodes have exactly 100 nodes, and put them inside a compound node with z-index greater than each node's z-index; but I haven't tried this yet.
If you have some other ideas, or if Cytoscape.js provides a way to summarise large graphs, please let me know.
Thank you.
you could group nodes when the amount in a layer exceeds a certain number (e.g. if you have 100 nodes, you combine them into groups of 25)
I'd do this by iterating over the nodes in the layer, making a new node N for each subgroup (inserting all relevant information needed), and then replacing any mention of the replaced nodes by N in all relevant edges (finding connected edges).
As I personally generate layouts/nodes in python before sending them to cytoscape for visualization, I'll refrain from posting a potentially ineffecient/incorrect javascript/cytoscape example :)

Optimize d3 force directed layout, via charge/gravity properties, based on number of nodes

I've been working on a network topology visualization using the force-directed algorithm built into D3. Everything is working well but having troubles with one important detail... I can't seem to get the graph to layout in an ideal way for graphs with a varying number of nodes. By ideal, i mean the nodes are nicely spaced out from each (no overlap) and nodes cluster wherever it makes sense. I've been trying to do this by adjusting the 'charge' and 'gravity' properties of the force layout, but no matter what i try, it seems to always work for one scenario (ie. large number of nodes), but not for another scenario (ie. small number of nodes). For example, if i have the layout working for a large graph, then when i look at small graph using the same formula for charge/gravity, ill have a few nodes that are way way out of site from the rest of the nodes. Here's an example of a formula i was using based on another SO question post:
var k = Math.sqrt(json.nodes.length / (dim.w * dim.h));
var charge = -10 / k;
var gravity = 100 * k;
This works for a graph with 14 nodes, but if i try the same with a graph of 5 nodes, some of those nodes are completely off the screen. Note that the width/height used in the calculation of 'k' is not changing between these two scenarios. Now maybe i shouldn't have these properties based on the width/height of visible area of graph. To be honest, this is not a requirement. I don't need the graph to render and fit within the viewport of graph. I just need the graph to lay itself out sensibly, so it's fine if some of it may be outside of visible area, especially in a large graph. I've also tried the following with some success, but i still find nodes are being rendered too far away from the rest of the graph for small graphs:
var charge = -1 * Math.pow(json.nodes.length, 3);
var gravity = 1 / json.nodes.length;
Can anyone out there help me out with this ? Would be greatly appreciated as i feel kind of stuck on this atm.
I actually figured this out on my own...
So the values i was using for charge/gravity/etc were not so much the problem. The issue was related to how many times the tick function was being called to adjust the graph. For my larger graphs, the nodes were always laid out fairly well. The main problem i was having was with smaller graphs. I was finding that nodes would frequently be placed outside of the viewport when the graph only had around 5-10 nodes in it.
In my code, im calling the tick function manually, like so:
force.start();
for (var i = tickLimit; i > 0; --i)
force.tick();
force.stop();
Previously, tickLimit was being set as follows:
var tickLimit = Math.pow(json.nodes.length, 2);
After messing around with charge/gravity values etc, I eventually realized that this is not sufficient for small graphs. If i have a graph with 4 nodes, then that means only 16 tick() calls will be made. This is not enough for the graph to adjust itself fully (ie. stabilize). Therefore i just needed to add a check to ensure the graph ticks a minimum number of times (ex. at least 300), and a maximum (ex. no more than 10000).
This may not work for everyone but it solves the issue for me.
In this force based algorithm case I would say that it's almost impossible to set all-cases-fit settings. This layout'd hardly depend on graph density and inner graph semantic.
What is the range of possible number of nodes? What about density? Is it randomly generated graph with predefined density coefficient or it has some semantic behind and has possibility to look good based on this semantic.
You said that nodes flows far away from each other. What higher gravity gives you?
Also the suggestion about linkDistance may help you too. E.g. I'm using d3.forceLayout also for drawing network graphs (but they're mostly small handmade graphs with nodes < 50). And I just copied stats from one of Mike Bostock's force layout example. Here they're:
// graph force layout defaults
var linkDistance = 50,
charge = -200;
// chart properties
var height = 720,
width = 720;
radius = 10;
I don't expect that it'll help you but maybe it'll stimulate the others to discuss.
UPD. All I can suggest you is to experiment. Choose a small set of test graphs and find optimal init settings for every one, then interpolate given numbers. Also if you deal with very big graphs (very big for "nice" visualization I mean) maybe you'll find grouping (colapsing) some parts of it helpfull - it reduces the number of nodes (and maybe the graph complexity).
Also keep in mind you don't need to set constant force layout settings (charge, gravity, linkDistance and etc. are all maintain functions). And you can set radius of nodes a little bit more than visible radius so they won't overlapping each other. Or set non constant function for charge, e.g. smth like this. Or use Mike Bostock advice to spread nodes on each tick manually.

Categories

Resources