Hi, I've been working on a project and noticed some weird behaviors around changes in alpha (namely due to alphaDecay) and the strength of links vs other forces; the lower the alpha, the weaker any linkForce is. I've set up a demo to show what I'm talking about.
In the demo, alpha decays as default and then resets to 1 once it reaches a threshold. This causes a "pulsating" behavior, where the graph expands as the links get weaker and then contracts once alpha is 1 and they're at full effect again. This happens regardless of whether I set my own strength function.
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var svg = d3.select("body").append("svg")
.attr("width", 400)
.attr("height", 400)
;
var simulation = d3.forceSimulation()
.force("x", d3.forceX(200))
.force("y", d3.forceY(200))
.force("many", d3.forceManyBody())
.force("link", d3.forceLink())
;
simulation.force("many").strength(-400);
// It's more extreme with more iterations (and obviously higher strength)
// simulation.force("link").iterations(5);
simulation.force("link").distance(50);
mydata = [Object(1), Object(2), Object(3),
Object(1), Object(2), Object(3),
Object(1), Object(2), Object(3),
Object(1), Object(2), Object(3),
Object(1), Object(2), Object(3),
Object(1), Object(2), Object(3)];
var balls = svg.selectAll("circle")
.data(mydata)
.enter().append("circle")
.attr("r", 5)
;
//Here I just connect every ball to every other ball
links = []
balls.data().forEach( function (ball) {
balls.data().forEach( function (ballbud) {
if (ballbud != ball) {
links.push({source: ball, target: ballbud});
}
});
});
simulation.nodes(balls.data());
simulation.force("link").links(links);
function update(){
// Here's where I mess with the alpha -------------------------------------
if (simulation.alpha() < .02) {
simulation.alpha(1);
}
balls
.attr("cx", function (d) {return d.x; })
.attr("cy", function (d) {return d.y; })
;
}
simulation.on("tick", update);
</script>
I've tested all 3 of these forces (position, manybody, and link) against eachother in pairs and it's clearly the case that only link is affected; the "pulsating" behavior happens when only link and another of the forces are active, but not when the linkforce is disabled. It's also more evident that only link is affected in my actual project, where the graph is a lot more complex and populated. You can also just set alphaDecay to 0 and manually play with alpha, the result is the same.
Strangely the behavior seems different on one of Mike's examples: https://bl.ocks.org/mbostock/4600693
When you hold down the mouse on a node, everything kinda drifts apart (when I'd expect it to contract)
Hopefully this is helpful! I'm pretty new to d3 (huge fan so far) and JS in general (less of a fan so far); let me know if something in this snippet reflects some technical or stylistic misunderstandings. I'll poke around in the source and see if I can figure anything out.