Skip to content

Instantly share code, notes, and snippets.

@mbostock
Forked from ZoltanLajosKis/d3jsproblem.html
Last active November 26, 2023 18:48
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 23 You must be signed in to fork a gist
  • Save mbostock/1095795 to your computer and use it in GitHub Desktop.
Save mbostock/1095795 to your computer and use it in GitHub Desktop.
Modifying a Force Layout
license: gpl-3.0
redirect: https://observablehq.com/@d3/modifying-a-force-directed-graph

This example demonstrates how to add and remove nodes and links from a force-directed layout. The graph initially appears with three disconnected nodes A, B and C. After one second, the three are connected in a loop. At two seconds, node C is removed, along with the links A-C and B-C. At three seconds, node C is reintroduced, restoring the original links A-C and B-C. Every subsequent second alternates between these two steps.

This example uses the general update pattern for data joins. See also modifying a force layout with transitions.

<!DOCTYPE html>
<svg width="960" height="500"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
color = d3.scaleOrdinal(d3.schemeCategory10);
var a = {id: "a"},
b = {id: "b"},
c = {id: "c"},
nodes = [a, b, c],
links = [];
var simulation = d3.forceSimulation(nodes)
.force("charge", d3.forceManyBody().strength(-1000))
.force("link", d3.forceLink(links).distance(200))
.force("x", d3.forceX())
.force("y", d3.forceY())
.alphaTarget(1)
.on("tick", ticked);
var g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"),
link = g.append("g").attr("stroke", "#000").attr("stroke-width", 1.5).selectAll(".link"),
node = g.append("g").attr("stroke", "#fff").attr("stroke-width", 1.5).selectAll(".node");
restart();
d3.timeout(function() {
links.push({source: a, target: b}); // Add a-b.
links.push({source: b, target: c}); // Add b-c.
links.push({source: c, target: a}); // Add c-a.
restart();
}, 1000);
d3.interval(function() {
nodes.pop(); // Remove c.
links.pop(); // Remove c-a.
links.pop(); // Remove b-c.
restart();
}, 2000, d3.now());
d3.interval(function() {
nodes.push(c); // Re-add c.
links.push({source: b, target: c}); // Re-add b-c.
links.push({source: c, target: a}); // Re-add c-a.
restart();
}, 2000, d3.now() + 1000);
function restart() {
// Apply the general update pattern to the nodes.
node = node.data(nodes, function(d) { return d.id;});
node.exit().remove();
node = node.enter().append("circle").attr("fill", function(d) { return color(d.id); }).attr("r", 8).merge(node);
// Apply the general update pattern to the links.
link = link.data(links, function(d) { return d.source.id + "-" + d.target.id; });
link.exit().remove();
link = link.enter().append("line").merge(link);
// Update and restart the simulation.
simulation.nodes(nodes);
simulation.force("link").links(links);
simulation.alpha(1).restart();
}
function ticked() {
node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
link.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
}
</script>
@inactivist
Copy link

What is the purpose of the var color = d3.scale.category10(); at line 28? It appears to have no effect.

Copy link

ghost commented Nov 10, 2015

can you give some description about start() method ? how ( and why ) dose it work ?

@rdpoor
Copy link

rdpoor commented Apr 19, 2016

I've just created a fork of this example, heavily commented, giving what I hope is a detailed explanation of the important concepts: https://gist.github.com/rdpoor/3a66b3e082ffeaeb5e6e79961192f7d8

(And I see that it appears in bl.ocks "by magic". Very nice!)

Copy link

ghost commented Sep 19, 2016

I'm hoping to update this gist from d3 v3 to v4 as it will directly help in a project of mine. I've made an attempt to upgrade however the nodes are positioned in the top left corner and the removal of the nodes doesn't appear to be happening.
My fork:
https://gist.github.com/stevescc/f964f8f4658bc11319765f83f67b7f9f
https://bl.ocks.org/stevescc/f964f8f4658bc11319765f83f67b7f9f
Ta

@jkleiser
Copy link

Is adding and removing nodes from a graph (interactively) something that is not very well supported and documented in D3 v4? Should I look for another library?

@ohollo
Copy link

ohollo commented Oct 20, 2016

Am also having a lot of trouble converting this to v4. Am getting the same results as @stevescc. Please advise how this can be performed in v4.

@glawler
Copy link

glawler commented Nov 8, 2016

This appears to do the trick in V4 though I've not played around with the code yet.

https://bl.ocks.org/tezzutezzu/cd04b3f1efee4186ff42aae66c87d1a7

@jeandat
Copy link

jeandat commented Apr 10, 2019

@rpdoor example above has nice transitions when nodes are added/deleted.
There is no transition in this example which is in v4.
Could someone point me in the right direction in order to achieve the same level or smoothness in v4?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment