D3 Force Directed Graph - Removing Nodes
I am trying to incorporate this example for adding/removing nodes from a Force Directed Graph. I am able to add nodes just fine, and for some reason I am also able to remove the nodes I have added without issues. However when I try to remove any of the original nodes, the node is not removed from the display, and it also breaks many other nodes' links. However, it and it's links are properly removed from the JSON based on the logs.
This example uses seemingly the same method as I do for removing nodes with splice.
Here also seems to use splice method though I don't fully follow the rest of what it is doing with filtering.
There is also this question that asks a somewhat similar thing though the answers only address adding.
I have tried exit/removing after the append which did not work. I have also tried using .insert
instead of .append
. The console.log
during the update()
function prints the JSON being used and it shows that nodes and links are all properly removed, but the display doesn't reflect that.
Relevant code is below.
Initializing/updating graph
//Get the SVG element
var svg = d3.select("svg");
var width = 960, height = 600;
var color = d3.scaleOrdinal(d3.schemeCategory20);
var link = svg.append("g").selectAll(".link");
var node = svg.append("g").selectAll(".node");
var label = svg.append("g").selectAll(".label");
//Begin the force simulation
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function (d) { return d.id; }).distance(50).strength(0.3))
.force("charge", d3.forceManyBody().strength(-15))
.force("center", d3.forceCenter(width / 2, height / 2));
//Highlight variables
var highlight_color = "blue";
var tHighlight = 0.05;
var config;
var linkedByIndex = {};
//Get the data
d3.json("/../../data.json", function (data) {
//if (!localStorage.graph)
//{
localStorage.graph = JSON.stringify(data);
//}
update();
forms();
});
function update() {
config = JSON.parse(localStorage.graph);
console.log(JSON.stringify(config));
linkedByIndex = {};
//Create an array of source,target containing all links
config.links.forEach(function (d) {
linkedByIndex[d.source + "," + d.target] = true;
linkedByIndex[d.target + "," + d.source] = true;
});
//Draw links
link = link.data(config.links);
link.exit().remove();
link = link.enter().append("line")
.attr("class", "link")
.attr("stroke-width", 2)
.attr("stroke", "#888")
//.attr("opacity", function (d) { if (d.target.radius > 7) { return 1 }; return 0; })
.merge(link);
node = node.data(config.nodes);
node.exit().remove();
node = node.enter().append("circle")
.attr("class", "node")
.attr("r", function(d) { return d.radius; })
.attr("fill", function (d) { return color(d.id); })
.attr("stroke", "black")
// .attr("pointer-events", function (d) { if (d.radius <= 7) { return "none"; } return "visibleAll"; })
// .attr("opacity", function (d) { if (d.radius <= 7) { return 0; } return 1; })
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended))
.on("mouseover", mouseOver)
.on("mouseout", mouseOut)
.merge(node);
label = label.data(config.nodes);
label.exit().remove();
label = label.enter().append("text")
.attr("class", "label")
.attr("dx", function (d) { return d.radius * 1.25; })
.attr("dy", ".35em")
.attr("opacity", function (d) { if (d.radius <= 7) { return 0; } return 1; })
.attr("font-weight", "normal")
.style("font-size", 10)
.text(function (d) { return d.id; })
.merge(label);
//Add nodes to simulation
simulation
.nodes(config.nodes)
.on("tick", ticked);
//Add links to simulation
simulation.force("link")
.links(config.links);
simulation.alphaTarget(0.3).restart();
}
//Animating by ticks function
function ticked() {
node
.attr("cx", function (d) { return d.x = Math.max(d.radius, Math.min(width - d.radius, d.x)); })
.attr("cy", function (d) { return d.y = Math.max(d.radius, Math.min(height - d.radius, 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; });
label
.attr("x", function (d) { return d.x = Math.max(d.radius, Math.min(width - d.radius, d.x)); })
.attr("y", function (d) { return d.y = Math.max(d.radius, Math.min(height - d.radius, d.y)); });
}
//Using above array, check if two nodes are linked
function isConnected(node1, node2) {
return linkedByIndex[node1.id + "," + node2.id] || node1.index == node2.index;
}
Adding/removing nodes and links.
ADDING works perfectly fine for both nodes and links this way.
function newNode(name, rad)
{
if (name == "")
{
alert("Must specify name");
return;
}
console.log("Adding node with name: " + name + " and radius: " + rad);
var temp = JSON.parse(localStorage.graph);
temp.nodes.push({ "id": name, "radius": Number(rad) });
localStorage.graph = JSON.stringify(temp);
update();
}
function newLink(source, target)
{
var foundSource = false;
var foundTarget = false;
if (source == "" && target == "")
{
alert("Must specify source and target");
return;
}
else if(source == "")
{
alert("Must specify source");
return;
}
else if (target == "")
{
alert("Must specify target")
return;
}
var temp = JSON.parse(localStorage.graph);
for (var i=0; i < temp.nodes.length; i++)
{
if(temp.nodes[i]['id'] === source)
{
foundSource = true;
}
if(temp.nodes[i]['id'] === target)
{
foundTarget = true;
}
}
if (foundSource && foundTarget) {
temp.links.push({ "source": source, "target": target });
localStorage.graph = JSON.stringify(temp);
update();
}
else {
alert("Invalid source or target");
return;
}
return;
}
function removeLink(linkSource, linkTarget)
{
}
function removeNode(nodeName)
{
var temp = JSON.parse(localStorage.graph);
var found = false;
if (nodeName == "")
{
alert("Must specify node name");
return;
}
for(var i=0; i<temp.nodes.length; i++)
{
if(temp.nodes[i]['id'] === nodeName)
{
console.log("Removing node: " + nodeName);
found = true;
temp.nodes.splice(i, 1);
temp.links = temp.links.filter(function (d) { return d.source != nodeName && d.target != nodeName; });
}
}
if(!found)
{
alert("Node does not exist");
return;
}
localStorage.graph = JSON.stringify(temp);
update();
}
JSON Data is in the format
{
"nodes":[
{
"id": "id1",
"radius": 5},
{
"id: "id2",
"radius": 6}
],
"links":[{
"source": "id1",
"target": "id2"
]
}
javascript html d3.js force-layout
add a comment |
I am trying to incorporate this example for adding/removing nodes from a Force Directed Graph. I am able to add nodes just fine, and for some reason I am also able to remove the nodes I have added without issues. However when I try to remove any of the original nodes, the node is not removed from the display, and it also breaks many other nodes' links. However, it and it's links are properly removed from the JSON based on the logs.
This example uses seemingly the same method as I do for removing nodes with splice.
Here also seems to use splice method though I don't fully follow the rest of what it is doing with filtering.
There is also this question that asks a somewhat similar thing though the answers only address adding.
I have tried exit/removing after the append which did not work. I have also tried using .insert
instead of .append
. The console.log
during the update()
function prints the JSON being used and it shows that nodes and links are all properly removed, but the display doesn't reflect that.
Relevant code is below.
Initializing/updating graph
//Get the SVG element
var svg = d3.select("svg");
var width = 960, height = 600;
var color = d3.scaleOrdinal(d3.schemeCategory20);
var link = svg.append("g").selectAll(".link");
var node = svg.append("g").selectAll(".node");
var label = svg.append("g").selectAll(".label");
//Begin the force simulation
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function (d) { return d.id; }).distance(50).strength(0.3))
.force("charge", d3.forceManyBody().strength(-15))
.force("center", d3.forceCenter(width / 2, height / 2));
//Highlight variables
var highlight_color = "blue";
var tHighlight = 0.05;
var config;
var linkedByIndex = {};
//Get the data
d3.json("/../../data.json", function (data) {
//if (!localStorage.graph)
//{
localStorage.graph = JSON.stringify(data);
//}
update();
forms();
});
function update() {
config = JSON.parse(localStorage.graph);
console.log(JSON.stringify(config));
linkedByIndex = {};
//Create an array of source,target containing all links
config.links.forEach(function (d) {
linkedByIndex[d.source + "," + d.target] = true;
linkedByIndex[d.target + "," + d.source] = true;
});
//Draw links
link = link.data(config.links);
link.exit().remove();
link = link.enter().append("line")
.attr("class", "link")
.attr("stroke-width", 2)
.attr("stroke", "#888")
//.attr("opacity", function (d) { if (d.target.radius > 7) { return 1 }; return 0; })
.merge(link);
node = node.data(config.nodes);
node.exit().remove();
node = node.enter().append("circle")
.attr("class", "node")
.attr("r", function(d) { return d.radius; })
.attr("fill", function (d) { return color(d.id); })
.attr("stroke", "black")
// .attr("pointer-events", function (d) { if (d.radius <= 7) { return "none"; } return "visibleAll"; })
// .attr("opacity", function (d) { if (d.radius <= 7) { return 0; } return 1; })
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended))
.on("mouseover", mouseOver)
.on("mouseout", mouseOut)
.merge(node);
label = label.data(config.nodes);
label.exit().remove();
label = label.enter().append("text")
.attr("class", "label")
.attr("dx", function (d) { return d.radius * 1.25; })
.attr("dy", ".35em")
.attr("opacity", function (d) { if (d.radius <= 7) { return 0; } return 1; })
.attr("font-weight", "normal")
.style("font-size", 10)
.text(function (d) { return d.id; })
.merge(label);
//Add nodes to simulation
simulation
.nodes(config.nodes)
.on("tick", ticked);
//Add links to simulation
simulation.force("link")
.links(config.links);
simulation.alphaTarget(0.3).restart();
}
//Animating by ticks function
function ticked() {
node
.attr("cx", function (d) { return d.x = Math.max(d.radius, Math.min(width - d.radius, d.x)); })
.attr("cy", function (d) { return d.y = Math.max(d.radius, Math.min(height - d.radius, 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; });
label
.attr("x", function (d) { return d.x = Math.max(d.radius, Math.min(width - d.radius, d.x)); })
.attr("y", function (d) { return d.y = Math.max(d.radius, Math.min(height - d.radius, d.y)); });
}
//Using above array, check if two nodes are linked
function isConnected(node1, node2) {
return linkedByIndex[node1.id + "," + node2.id] || node1.index == node2.index;
}
Adding/removing nodes and links.
ADDING works perfectly fine for both nodes and links this way.
function newNode(name, rad)
{
if (name == "")
{
alert("Must specify name");
return;
}
console.log("Adding node with name: " + name + " and radius: " + rad);
var temp = JSON.parse(localStorage.graph);
temp.nodes.push({ "id": name, "radius": Number(rad) });
localStorage.graph = JSON.stringify(temp);
update();
}
function newLink(source, target)
{
var foundSource = false;
var foundTarget = false;
if (source == "" && target == "")
{
alert("Must specify source and target");
return;
}
else if(source == "")
{
alert("Must specify source");
return;
}
else if (target == "")
{
alert("Must specify target")
return;
}
var temp = JSON.parse(localStorage.graph);
for (var i=0; i < temp.nodes.length; i++)
{
if(temp.nodes[i]['id'] === source)
{
foundSource = true;
}
if(temp.nodes[i]['id'] === target)
{
foundTarget = true;
}
}
if (foundSource && foundTarget) {
temp.links.push({ "source": source, "target": target });
localStorage.graph = JSON.stringify(temp);
update();
}
else {
alert("Invalid source or target");
return;
}
return;
}
function removeLink(linkSource, linkTarget)
{
}
function removeNode(nodeName)
{
var temp = JSON.parse(localStorage.graph);
var found = false;
if (nodeName == "")
{
alert("Must specify node name");
return;
}
for(var i=0; i<temp.nodes.length; i++)
{
if(temp.nodes[i]['id'] === nodeName)
{
console.log("Removing node: " + nodeName);
found = true;
temp.nodes.splice(i, 1);
temp.links = temp.links.filter(function (d) { return d.source != nodeName && d.target != nodeName; });
}
}
if(!found)
{
alert("Node does not exist");
return;
}
localStorage.graph = JSON.stringify(temp);
update();
}
JSON Data is in the format
{
"nodes":[
{
"id": "id1",
"radius": 5},
{
"id: "id2",
"radius": 6}
],
"links":[{
"source": "id1",
"target": "id2"
]
}
javascript html d3.js force-layout
Hi! I am trying to reproduce your problem here: stackblitz.com/edit/q53397252. I've made functionsnewNode
,newLink
,removeNode
, andremoveLink
global, so you can call them in console. In my browser I do not see any errors after removing any of initial nodes.
– Yaroslav Sergienko
Nov 22 '18 at 11:39
I'm not able to use this site for some reason it just says "starting dev server" and never loads. How do you call functions from the console? Right now I am using some buttons so I can test using console to see if it works
– A Zibuda
Nov 26 '18 at 12:48
Update: I tried running remove node from the console and it still doesn't properly update display. To clarify @YaroslavSergienko there are no errors that show up...but the display is not correct. Nodes will get jumbled and the 'removed' node which is no longer in the JSON is usually still there.
– A Zibuda
Nov 26 '18 at 14:15
add a comment |
I am trying to incorporate this example for adding/removing nodes from a Force Directed Graph. I am able to add nodes just fine, and for some reason I am also able to remove the nodes I have added without issues. However when I try to remove any of the original nodes, the node is not removed from the display, and it also breaks many other nodes' links. However, it and it's links are properly removed from the JSON based on the logs.
This example uses seemingly the same method as I do for removing nodes with splice.
Here also seems to use splice method though I don't fully follow the rest of what it is doing with filtering.
There is also this question that asks a somewhat similar thing though the answers only address adding.
I have tried exit/removing after the append which did not work. I have also tried using .insert
instead of .append
. The console.log
during the update()
function prints the JSON being used and it shows that nodes and links are all properly removed, but the display doesn't reflect that.
Relevant code is below.
Initializing/updating graph
//Get the SVG element
var svg = d3.select("svg");
var width = 960, height = 600;
var color = d3.scaleOrdinal(d3.schemeCategory20);
var link = svg.append("g").selectAll(".link");
var node = svg.append("g").selectAll(".node");
var label = svg.append("g").selectAll(".label");
//Begin the force simulation
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function (d) { return d.id; }).distance(50).strength(0.3))
.force("charge", d3.forceManyBody().strength(-15))
.force("center", d3.forceCenter(width / 2, height / 2));
//Highlight variables
var highlight_color = "blue";
var tHighlight = 0.05;
var config;
var linkedByIndex = {};
//Get the data
d3.json("/../../data.json", function (data) {
//if (!localStorage.graph)
//{
localStorage.graph = JSON.stringify(data);
//}
update();
forms();
});
function update() {
config = JSON.parse(localStorage.graph);
console.log(JSON.stringify(config));
linkedByIndex = {};
//Create an array of source,target containing all links
config.links.forEach(function (d) {
linkedByIndex[d.source + "," + d.target] = true;
linkedByIndex[d.target + "," + d.source] = true;
});
//Draw links
link = link.data(config.links);
link.exit().remove();
link = link.enter().append("line")
.attr("class", "link")
.attr("stroke-width", 2)
.attr("stroke", "#888")
//.attr("opacity", function (d) { if (d.target.radius > 7) { return 1 }; return 0; })
.merge(link);
node = node.data(config.nodes);
node.exit().remove();
node = node.enter().append("circle")
.attr("class", "node")
.attr("r", function(d) { return d.radius; })
.attr("fill", function (d) { return color(d.id); })
.attr("stroke", "black")
// .attr("pointer-events", function (d) { if (d.radius <= 7) { return "none"; } return "visibleAll"; })
// .attr("opacity", function (d) { if (d.radius <= 7) { return 0; } return 1; })
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended))
.on("mouseover", mouseOver)
.on("mouseout", mouseOut)
.merge(node);
label = label.data(config.nodes);
label.exit().remove();
label = label.enter().append("text")
.attr("class", "label")
.attr("dx", function (d) { return d.radius * 1.25; })
.attr("dy", ".35em")
.attr("opacity", function (d) { if (d.radius <= 7) { return 0; } return 1; })
.attr("font-weight", "normal")
.style("font-size", 10)
.text(function (d) { return d.id; })
.merge(label);
//Add nodes to simulation
simulation
.nodes(config.nodes)
.on("tick", ticked);
//Add links to simulation
simulation.force("link")
.links(config.links);
simulation.alphaTarget(0.3).restart();
}
//Animating by ticks function
function ticked() {
node
.attr("cx", function (d) { return d.x = Math.max(d.radius, Math.min(width - d.radius, d.x)); })
.attr("cy", function (d) { return d.y = Math.max(d.radius, Math.min(height - d.radius, 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; });
label
.attr("x", function (d) { return d.x = Math.max(d.radius, Math.min(width - d.radius, d.x)); })
.attr("y", function (d) { return d.y = Math.max(d.radius, Math.min(height - d.radius, d.y)); });
}
//Using above array, check if two nodes are linked
function isConnected(node1, node2) {
return linkedByIndex[node1.id + "," + node2.id] || node1.index == node2.index;
}
Adding/removing nodes and links.
ADDING works perfectly fine for both nodes and links this way.
function newNode(name, rad)
{
if (name == "")
{
alert("Must specify name");
return;
}
console.log("Adding node with name: " + name + " and radius: " + rad);
var temp = JSON.parse(localStorage.graph);
temp.nodes.push({ "id": name, "radius": Number(rad) });
localStorage.graph = JSON.stringify(temp);
update();
}
function newLink(source, target)
{
var foundSource = false;
var foundTarget = false;
if (source == "" && target == "")
{
alert("Must specify source and target");
return;
}
else if(source == "")
{
alert("Must specify source");
return;
}
else if (target == "")
{
alert("Must specify target")
return;
}
var temp = JSON.parse(localStorage.graph);
for (var i=0; i < temp.nodes.length; i++)
{
if(temp.nodes[i]['id'] === source)
{
foundSource = true;
}
if(temp.nodes[i]['id'] === target)
{
foundTarget = true;
}
}
if (foundSource && foundTarget) {
temp.links.push({ "source": source, "target": target });
localStorage.graph = JSON.stringify(temp);
update();
}
else {
alert("Invalid source or target");
return;
}
return;
}
function removeLink(linkSource, linkTarget)
{
}
function removeNode(nodeName)
{
var temp = JSON.parse(localStorage.graph);
var found = false;
if (nodeName == "")
{
alert("Must specify node name");
return;
}
for(var i=0; i<temp.nodes.length; i++)
{
if(temp.nodes[i]['id'] === nodeName)
{
console.log("Removing node: " + nodeName);
found = true;
temp.nodes.splice(i, 1);
temp.links = temp.links.filter(function (d) { return d.source != nodeName && d.target != nodeName; });
}
}
if(!found)
{
alert("Node does not exist");
return;
}
localStorage.graph = JSON.stringify(temp);
update();
}
JSON Data is in the format
{
"nodes":[
{
"id": "id1",
"radius": 5},
{
"id: "id2",
"radius": 6}
],
"links":[{
"source": "id1",
"target": "id2"
]
}
javascript html d3.js force-layout
I am trying to incorporate this example for adding/removing nodes from a Force Directed Graph. I am able to add nodes just fine, and for some reason I am also able to remove the nodes I have added without issues. However when I try to remove any of the original nodes, the node is not removed from the display, and it also breaks many other nodes' links. However, it and it's links are properly removed from the JSON based on the logs.
This example uses seemingly the same method as I do for removing nodes with splice.
Here also seems to use splice method though I don't fully follow the rest of what it is doing with filtering.
There is also this question that asks a somewhat similar thing though the answers only address adding.
I have tried exit/removing after the append which did not work. I have also tried using .insert
instead of .append
. The console.log
during the update()
function prints the JSON being used and it shows that nodes and links are all properly removed, but the display doesn't reflect that.
Relevant code is below.
Initializing/updating graph
//Get the SVG element
var svg = d3.select("svg");
var width = 960, height = 600;
var color = d3.scaleOrdinal(d3.schemeCategory20);
var link = svg.append("g").selectAll(".link");
var node = svg.append("g").selectAll(".node");
var label = svg.append("g").selectAll(".label");
//Begin the force simulation
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function (d) { return d.id; }).distance(50).strength(0.3))
.force("charge", d3.forceManyBody().strength(-15))
.force("center", d3.forceCenter(width / 2, height / 2));
//Highlight variables
var highlight_color = "blue";
var tHighlight = 0.05;
var config;
var linkedByIndex = {};
//Get the data
d3.json("/../../data.json", function (data) {
//if (!localStorage.graph)
//{
localStorage.graph = JSON.stringify(data);
//}
update();
forms();
});
function update() {
config = JSON.parse(localStorage.graph);
console.log(JSON.stringify(config));
linkedByIndex = {};
//Create an array of source,target containing all links
config.links.forEach(function (d) {
linkedByIndex[d.source + "," + d.target] = true;
linkedByIndex[d.target + "," + d.source] = true;
});
//Draw links
link = link.data(config.links);
link.exit().remove();
link = link.enter().append("line")
.attr("class", "link")
.attr("stroke-width", 2)
.attr("stroke", "#888")
//.attr("opacity", function (d) { if (d.target.radius > 7) { return 1 }; return 0; })
.merge(link);
node = node.data(config.nodes);
node.exit().remove();
node = node.enter().append("circle")
.attr("class", "node")
.attr("r", function(d) { return d.radius; })
.attr("fill", function (d) { return color(d.id); })
.attr("stroke", "black")
// .attr("pointer-events", function (d) { if (d.radius <= 7) { return "none"; } return "visibleAll"; })
// .attr("opacity", function (d) { if (d.radius <= 7) { return 0; } return 1; })
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended))
.on("mouseover", mouseOver)
.on("mouseout", mouseOut)
.merge(node);
label = label.data(config.nodes);
label.exit().remove();
label = label.enter().append("text")
.attr("class", "label")
.attr("dx", function (d) { return d.radius * 1.25; })
.attr("dy", ".35em")
.attr("opacity", function (d) { if (d.radius <= 7) { return 0; } return 1; })
.attr("font-weight", "normal")
.style("font-size", 10)
.text(function (d) { return d.id; })
.merge(label);
//Add nodes to simulation
simulation
.nodes(config.nodes)
.on("tick", ticked);
//Add links to simulation
simulation.force("link")
.links(config.links);
simulation.alphaTarget(0.3).restart();
}
//Animating by ticks function
function ticked() {
node
.attr("cx", function (d) { return d.x = Math.max(d.radius, Math.min(width - d.radius, d.x)); })
.attr("cy", function (d) { return d.y = Math.max(d.radius, Math.min(height - d.radius, 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; });
label
.attr("x", function (d) { return d.x = Math.max(d.radius, Math.min(width - d.radius, d.x)); })
.attr("y", function (d) { return d.y = Math.max(d.radius, Math.min(height - d.radius, d.y)); });
}
//Using above array, check if two nodes are linked
function isConnected(node1, node2) {
return linkedByIndex[node1.id + "," + node2.id] || node1.index == node2.index;
}
Adding/removing nodes and links.
ADDING works perfectly fine for both nodes and links this way.
function newNode(name, rad)
{
if (name == "")
{
alert("Must specify name");
return;
}
console.log("Adding node with name: " + name + " and radius: " + rad);
var temp = JSON.parse(localStorage.graph);
temp.nodes.push({ "id": name, "radius": Number(rad) });
localStorage.graph = JSON.stringify(temp);
update();
}
function newLink(source, target)
{
var foundSource = false;
var foundTarget = false;
if (source == "" && target == "")
{
alert("Must specify source and target");
return;
}
else if(source == "")
{
alert("Must specify source");
return;
}
else if (target == "")
{
alert("Must specify target")
return;
}
var temp = JSON.parse(localStorage.graph);
for (var i=0; i < temp.nodes.length; i++)
{
if(temp.nodes[i]['id'] === source)
{
foundSource = true;
}
if(temp.nodes[i]['id'] === target)
{
foundTarget = true;
}
}
if (foundSource && foundTarget) {
temp.links.push({ "source": source, "target": target });
localStorage.graph = JSON.stringify(temp);
update();
}
else {
alert("Invalid source or target");
return;
}
return;
}
function removeLink(linkSource, linkTarget)
{
}
function removeNode(nodeName)
{
var temp = JSON.parse(localStorage.graph);
var found = false;
if (nodeName == "")
{
alert("Must specify node name");
return;
}
for(var i=0; i<temp.nodes.length; i++)
{
if(temp.nodes[i]['id'] === nodeName)
{
console.log("Removing node: " + nodeName);
found = true;
temp.nodes.splice(i, 1);
temp.links = temp.links.filter(function (d) { return d.source != nodeName && d.target != nodeName; });
}
}
if(!found)
{
alert("Node does not exist");
return;
}
localStorage.graph = JSON.stringify(temp);
update();
}
JSON Data is in the format
{
"nodes":[
{
"id": "id1",
"radius": 5},
{
"id: "id2",
"radius": 6}
],
"links":[{
"source": "id1",
"target": "id2"
]
}
javascript html d3.js force-layout
javascript html d3.js force-layout
asked Nov 20 '18 at 16:20
A ZibudaA Zibuda
388
388
Hi! I am trying to reproduce your problem here: stackblitz.com/edit/q53397252. I've made functionsnewNode
,newLink
,removeNode
, andremoveLink
global, so you can call them in console. In my browser I do not see any errors after removing any of initial nodes.
– Yaroslav Sergienko
Nov 22 '18 at 11:39
I'm not able to use this site for some reason it just says "starting dev server" and never loads. How do you call functions from the console? Right now I am using some buttons so I can test using console to see if it works
– A Zibuda
Nov 26 '18 at 12:48
Update: I tried running remove node from the console and it still doesn't properly update display. To clarify @YaroslavSergienko there are no errors that show up...but the display is not correct. Nodes will get jumbled and the 'removed' node which is no longer in the JSON is usually still there.
– A Zibuda
Nov 26 '18 at 14:15
add a comment |
Hi! I am trying to reproduce your problem here: stackblitz.com/edit/q53397252. I've made functionsnewNode
,newLink
,removeNode
, andremoveLink
global, so you can call them in console. In my browser I do not see any errors after removing any of initial nodes.
– Yaroslav Sergienko
Nov 22 '18 at 11:39
I'm not able to use this site for some reason it just says "starting dev server" and never loads. How do you call functions from the console? Right now I am using some buttons so I can test using console to see if it works
– A Zibuda
Nov 26 '18 at 12:48
Update: I tried running remove node from the console and it still doesn't properly update display. To clarify @YaroslavSergienko there are no errors that show up...but the display is not correct. Nodes will get jumbled and the 'removed' node which is no longer in the JSON is usually still there.
– A Zibuda
Nov 26 '18 at 14:15
Hi! I am trying to reproduce your problem here: stackblitz.com/edit/q53397252. I've made functions
newNode
, newLink
, removeNode
, and removeLink
global, so you can call them in console. In my browser I do not see any errors after removing any of initial nodes.– Yaroslav Sergienko
Nov 22 '18 at 11:39
Hi! I am trying to reproduce your problem here: stackblitz.com/edit/q53397252. I've made functions
newNode
, newLink
, removeNode
, and removeLink
global, so you can call them in console. In my browser I do not see any errors after removing any of initial nodes.– Yaroslav Sergienko
Nov 22 '18 at 11:39
I'm not able to use this site for some reason it just says "starting dev server" and never loads. How do you call functions from the console? Right now I am using some buttons so I can test using console to see if it works
– A Zibuda
Nov 26 '18 at 12:48
I'm not able to use this site for some reason it just says "starting dev server" and never loads. How do you call functions from the console? Right now I am using some buttons so I can test using console to see if it works
– A Zibuda
Nov 26 '18 at 12:48
Update: I tried running remove node from the console and it still doesn't properly update display. To clarify @YaroslavSergienko there are no errors that show up...but the display is not correct. Nodes will get jumbled and the 'removed' node which is no longer in the JSON is usually still there.
– A Zibuda
Nov 26 '18 at 14:15
Update: I tried running remove node from the console and it still doesn't properly update display. To clarify @YaroslavSergienko there are no errors that show up...but the display is not correct. Nodes will get jumbled and the 'removed' node which is no longer in the JSON is usually still there.
– A Zibuda
Nov 26 '18 at 14:15
add a comment |
1 Answer
1
active
oldest
votes
By default d3 joins data by index, so after you remove node, it assigns data incorrectly. The solution is to pass second argument to .data
function. You need to replace
node = node.data(config.nodes);
with
node = node.data(config.nodes, d => d.id);
You can also do this for links, but if their styles are equal (i.e. they only differ by x1
, x2
, y1
and y2
) it will make no difference.
Update: you should do this for labels as well
label = label.data(config.nodes, d => d.id);
I tried changing this but I'm seeing the same result. Is there some documentation regarding the way data is joined that I can reference in this case? It does seem something like that could be the cause as colors are mixed up as well when removing.
– A Zibuda
Nov 26 '18 at 16:22
The most comprehensive about joins it this: bost.ocks.org/mike/selection/#key. Can you share example with colors and steps to reproduce the problem?
– Yaroslav Sergienko
Nov 26 '18 at 16:32
The color of the node is defined by its ID. Here is standard graph that is drawn by my code: imgur.com/CcTL4mL Next I execute removeNode('CCC') This is result: imgur.com/a/d0ThkhU Most nodes stay the same, some change color and name. (KYC changes to MAL and MAL changes to CCC) However JSON shows no nodes with name "CCC" being loaded.
– A Zibuda
Nov 26 '18 at 16:47
I haven't noticed, that you also have labels, so you should pass second argument for them as well
– Yaroslav Sergienko
Nov 26 '18 at 17:00
That fixed it, thank you!
– A Zibuda
Nov 26 '18 at 17:47
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53397252%2fd3-force-directed-graph-removing-nodes%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
By default d3 joins data by index, so after you remove node, it assigns data incorrectly. The solution is to pass second argument to .data
function. You need to replace
node = node.data(config.nodes);
with
node = node.data(config.nodes, d => d.id);
You can also do this for links, but if their styles are equal (i.e. they only differ by x1
, x2
, y1
and y2
) it will make no difference.
Update: you should do this for labels as well
label = label.data(config.nodes, d => d.id);
I tried changing this but I'm seeing the same result. Is there some documentation regarding the way data is joined that I can reference in this case? It does seem something like that could be the cause as colors are mixed up as well when removing.
– A Zibuda
Nov 26 '18 at 16:22
The most comprehensive about joins it this: bost.ocks.org/mike/selection/#key. Can you share example with colors and steps to reproduce the problem?
– Yaroslav Sergienko
Nov 26 '18 at 16:32
The color of the node is defined by its ID. Here is standard graph that is drawn by my code: imgur.com/CcTL4mL Next I execute removeNode('CCC') This is result: imgur.com/a/d0ThkhU Most nodes stay the same, some change color and name. (KYC changes to MAL and MAL changes to CCC) However JSON shows no nodes with name "CCC" being loaded.
– A Zibuda
Nov 26 '18 at 16:47
I haven't noticed, that you also have labels, so you should pass second argument for them as well
– Yaroslav Sergienko
Nov 26 '18 at 17:00
That fixed it, thank you!
– A Zibuda
Nov 26 '18 at 17:47
add a comment |
By default d3 joins data by index, so after you remove node, it assigns data incorrectly. The solution is to pass second argument to .data
function. You need to replace
node = node.data(config.nodes);
with
node = node.data(config.nodes, d => d.id);
You can also do this for links, but if their styles are equal (i.e. they only differ by x1
, x2
, y1
and y2
) it will make no difference.
Update: you should do this for labels as well
label = label.data(config.nodes, d => d.id);
I tried changing this but I'm seeing the same result. Is there some documentation regarding the way data is joined that I can reference in this case? It does seem something like that could be the cause as colors are mixed up as well when removing.
– A Zibuda
Nov 26 '18 at 16:22
The most comprehensive about joins it this: bost.ocks.org/mike/selection/#key. Can you share example with colors and steps to reproduce the problem?
– Yaroslav Sergienko
Nov 26 '18 at 16:32
The color of the node is defined by its ID. Here is standard graph that is drawn by my code: imgur.com/CcTL4mL Next I execute removeNode('CCC') This is result: imgur.com/a/d0ThkhU Most nodes stay the same, some change color and name. (KYC changes to MAL and MAL changes to CCC) However JSON shows no nodes with name "CCC" being loaded.
– A Zibuda
Nov 26 '18 at 16:47
I haven't noticed, that you also have labels, so you should pass second argument for them as well
– Yaroslav Sergienko
Nov 26 '18 at 17:00
That fixed it, thank you!
– A Zibuda
Nov 26 '18 at 17:47
add a comment |
By default d3 joins data by index, so after you remove node, it assigns data incorrectly. The solution is to pass second argument to .data
function. You need to replace
node = node.data(config.nodes);
with
node = node.data(config.nodes, d => d.id);
You can also do this for links, but if their styles are equal (i.e. they only differ by x1
, x2
, y1
and y2
) it will make no difference.
Update: you should do this for labels as well
label = label.data(config.nodes, d => d.id);
By default d3 joins data by index, so after you remove node, it assigns data incorrectly. The solution is to pass second argument to .data
function. You need to replace
node = node.data(config.nodes);
with
node = node.data(config.nodes, d => d.id);
You can also do this for links, but if their styles are equal (i.e. they only differ by x1
, x2
, y1
and y2
) it will make no difference.
Update: you should do this for labels as well
label = label.data(config.nodes, d => d.id);
edited Nov 26 '18 at 16:59
answered Nov 26 '18 at 16:15
Yaroslav SergienkoYaroslav Sergienko
40016
40016
I tried changing this but I'm seeing the same result. Is there some documentation regarding the way data is joined that I can reference in this case? It does seem something like that could be the cause as colors are mixed up as well when removing.
– A Zibuda
Nov 26 '18 at 16:22
The most comprehensive about joins it this: bost.ocks.org/mike/selection/#key. Can you share example with colors and steps to reproduce the problem?
– Yaroslav Sergienko
Nov 26 '18 at 16:32
The color of the node is defined by its ID. Here is standard graph that is drawn by my code: imgur.com/CcTL4mL Next I execute removeNode('CCC') This is result: imgur.com/a/d0ThkhU Most nodes stay the same, some change color and name. (KYC changes to MAL and MAL changes to CCC) However JSON shows no nodes with name "CCC" being loaded.
– A Zibuda
Nov 26 '18 at 16:47
I haven't noticed, that you also have labels, so you should pass second argument for them as well
– Yaroslav Sergienko
Nov 26 '18 at 17:00
That fixed it, thank you!
– A Zibuda
Nov 26 '18 at 17:47
add a comment |
I tried changing this but I'm seeing the same result. Is there some documentation regarding the way data is joined that I can reference in this case? It does seem something like that could be the cause as colors are mixed up as well when removing.
– A Zibuda
Nov 26 '18 at 16:22
The most comprehensive about joins it this: bost.ocks.org/mike/selection/#key. Can you share example with colors and steps to reproduce the problem?
– Yaroslav Sergienko
Nov 26 '18 at 16:32
The color of the node is defined by its ID. Here is standard graph that is drawn by my code: imgur.com/CcTL4mL Next I execute removeNode('CCC') This is result: imgur.com/a/d0ThkhU Most nodes stay the same, some change color and name. (KYC changes to MAL and MAL changes to CCC) However JSON shows no nodes with name "CCC" being loaded.
– A Zibuda
Nov 26 '18 at 16:47
I haven't noticed, that you also have labels, so you should pass second argument for them as well
– Yaroslav Sergienko
Nov 26 '18 at 17:00
That fixed it, thank you!
– A Zibuda
Nov 26 '18 at 17:47
I tried changing this but I'm seeing the same result. Is there some documentation regarding the way data is joined that I can reference in this case? It does seem something like that could be the cause as colors are mixed up as well when removing.
– A Zibuda
Nov 26 '18 at 16:22
I tried changing this but I'm seeing the same result. Is there some documentation regarding the way data is joined that I can reference in this case? It does seem something like that could be the cause as colors are mixed up as well when removing.
– A Zibuda
Nov 26 '18 at 16:22
The most comprehensive about joins it this: bost.ocks.org/mike/selection/#key. Can you share example with colors and steps to reproduce the problem?
– Yaroslav Sergienko
Nov 26 '18 at 16:32
The most comprehensive about joins it this: bost.ocks.org/mike/selection/#key. Can you share example with colors and steps to reproduce the problem?
– Yaroslav Sergienko
Nov 26 '18 at 16:32
The color of the node is defined by its ID. Here is standard graph that is drawn by my code: imgur.com/CcTL4mL Next I execute removeNode('CCC') This is result: imgur.com/a/d0ThkhU Most nodes stay the same, some change color and name. (KYC changes to MAL and MAL changes to CCC) However JSON shows no nodes with name "CCC" being loaded.
– A Zibuda
Nov 26 '18 at 16:47
The color of the node is defined by its ID. Here is standard graph that is drawn by my code: imgur.com/CcTL4mL Next I execute removeNode('CCC') This is result: imgur.com/a/d0ThkhU Most nodes stay the same, some change color and name. (KYC changes to MAL and MAL changes to CCC) However JSON shows no nodes with name "CCC" being loaded.
– A Zibuda
Nov 26 '18 at 16:47
I haven't noticed, that you also have labels, so you should pass second argument for them as well
– Yaroslav Sergienko
Nov 26 '18 at 17:00
I haven't noticed, that you also have labels, so you should pass second argument for them as well
– Yaroslav Sergienko
Nov 26 '18 at 17:00
That fixed it, thank you!
– A Zibuda
Nov 26 '18 at 17:47
That fixed it, thank you!
– A Zibuda
Nov 26 '18 at 17:47
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53397252%2fd3-force-directed-graph-removing-nodes%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Hi! I am trying to reproduce your problem here: stackblitz.com/edit/q53397252. I've made functions
newNode
,newLink
,removeNode
, andremoveLink
global, so you can call them in console. In my browser I do not see any errors after removing any of initial nodes.– Yaroslav Sergienko
Nov 22 '18 at 11:39
I'm not able to use this site for some reason it just says "starting dev server" and never loads. How do you call functions from the console? Right now I am using some buttons so I can test using console to see if it works
– A Zibuda
Nov 26 '18 at 12:48
Update: I tried running remove node from the console and it still doesn't properly update display. To clarify @YaroslavSergienko there are no errors that show up...but the display is not correct. Nodes will get jumbled and the 'removed' node which is no longer in the JSON is usually still there.
– A Zibuda
Nov 26 '18 at 14:15