Old nodes in d3 chart aren't removed during update

Multi tool use
Multi tool use


Old nodes in d3 chart aren't removed during update



I'm trying to make a force directed graph, where nodes and links are added and removed as needed. However, while the chart correctly updates with added/removed links and nodes, all the old nodes are still visible.



Screenshot



Here is the update function. I've tried various tutorials, re-arranged the code, double checked the data being update is correct (i.e. this.dataNodes is being mutated, but replacing the object completely doesn't work either), etc. Honestly don't know what I should be looking for anymore.


// ADDING LINKS
this.link = this.linkGroup.selectAll("path")
.data(this.dataLinks, (link) => {
return link.target.id + link.source.id
});

this.link.exit().remove();

const linkEnter = this.link.enter()
.append("path")
.attr("stroke-width", 2)
.style("stroke", "#ccc")
.style('marker-start', (d) => d.sync ? 'url(#start-arrow)' : '')
.style('marker-end', (d) => 'url(#end-arrow)');


this.link = linkEnter.merge(this.link);

// ADDING NODES
this.node = this.nodeGroup.selectAll(".nodes")
.data(this.dataNodes, function (node) { return node.id });

this.node.exit().remove();

const nodeEnter = this.node.enter()
.append("g")
.call(this.dragAndDrop);

// Main circle
nodeEnter.append("circle")
.attr("r", 10)
.attr("fill", "grey")
// ADDING CHARACTER NAMES
nodeEnter.append("text")
.attr("x", 12)
.attr("dy", ".35em")
.text(function (d) {return d.title;});

this.node = nodeEnter.merge(this.node);

this.simulation.nodes(this.dataNodes).on("tick", this.tickActions );
this.simulation.force('link').links(this.dataLinks);
this.simulation.alphaTarget(1).restart();



EDIT:
This code is called when the force graph is first created. this.updateSimulation is the function above and renders with no problems. Calling it again, all previously created nodes remain in the graph.


this.svg = d3.select('#relationship-chart')
.append('svg')
.attr('width', this.width)
.attr('height', this.height);


// GROUPS
this.linkGroup = this.svg.append("g").attr("class", "links");
this.nodeGroup = this.svg.append("g").attr("class", "nodes");


// MAIN SIMULATION
this.link_force = d3.forceLink()
.id(function(d) { return d.id; })
.distance(100);

this.simulation = d3.forceSimulation()
.force("link", this.link_force)
.force("charge", d3.forceManyBody().strength(-200))
.force('center', d3.forceCenter(this.width / 2, this.height / 2))
//.force('collide', d3.forceCollide(25))
.force("x", d3.forceX())
.force("y", d3.forceY())
.alphaTarget(1);

// MISC DEFINTIONS
this.dragAndDrop = d3.drag()
.on("start", this.dragstarted)
.on("drag", this.dragged)
.on("end", this.dragended);

// ADDING ARROWS
this.svg.append('svg:defs').append('svg:marker')
.attr('id', 'end-arrow')
.attr('viewBox', '0 -5 10 10')
.attr('refX', 7)
.attr('markerWidth', 4)
.attr('markerHeight', 4)
.attr('orient', 'auto')
.append('svg:path')
.attr('d', 'M0,-5L10,0L0,5')
.attr('fill', '#ccc');

this.svg.append('svg:defs').append('svg:marker')
.attr('id', 'start-arrow')
.attr('viewBox', '0 -5 10 10')
.attr('refX', 1)
.attr('markerWidth', 4)
.attr('markerHeight', 4)
.attr('orient', 'auto')
.append('svg:path')
.attr('d', 'M10,-5L0,0L10,5')
.attr('fill', '#ccc');


this.updateSimulation();





Hi - you are selecting nodes using the class ".node", but I can't see that you are assigning that class to the created nodes on the enter selection, so you may be selecting an empty set of elements each time.
– Tom Shanley
Jul 2 at 1:55





Updated my post to include more information. When I create nodeGroup, I add the class nodes.
– Creis
Jul 2 at 2:18





based on that extra code, you are creating one group ("g") element with the class "nodes" (this.nodeGroup = this.svg.append("g").attr("class", "nodes");), but then later you try to select all the nodes within that group using the same class: nodeGroup.selectAll(".nodes"). However, you don't have any elements within that group with class "nodes", only the parent group has that class.
– Tom Shanley
Jul 2 at 2:39





Looks like that was the problem after all. Thank you so much!
– Creis
Jul 2 at 4:34




1 Answer
1



Turns out I was selecting the parent elements class and not the children. I added a class to the nodes I created and this cleared up the problem.



Before:


this.node = this.nodeGroup.selectAll(".nodes")
.data(this.dataNodes, function (node) { return node.id });

this.node.exit().remove();

const nodeEnter = this.node.enter()
.append("g")
.call(this.dragAndDrop);



After:


this.node = this.nodeGroup.selectAll(".onenode")
.data(this.dataNodes, (node) => { return node.id });

this.node.exit().remove();

const nodeEnter = this.node.enter()
.append("g")
.attr("class", "onenode")
.call(this.dragAndDrop);






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

IGr FqSdTLv4VMsTjcMj1hId
vsjUoZY4SJZ4yG,Hv6kA81AYQ0 R,c,q9ofBzj,OMLuEW5y1tCPXfdBF5jvsp0 cNU2soax

Popular posts from this blog

Rothschild family

Cinema of Italy