<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
.node {
stroke: #fff;
stroke-width: 1.5px;
}
.nodeDetail {
stroke: #fff;
stroke-width: 1.5px;
}
.link {
stroke: #999;
stroke-opacity: .6;
}
.text {
font: 12px sans-serif;
pointer-events: none; }
.node {
stroke:#fff;
stroke-width:3px;
fill:#008876;
}
</style>
</head>
<body>
<script src="http://d3js.org/d3.v3.js"></script>
<script>
var graph = {
"nodes":[
{"name":"RFID Scanner","group":1},
{"name":"Chemical 1 Tag ID: 10001 ","group":1},
{"name":"Chemical 2 Tag ID: 10002","group":1},
{"name":"Chemical 3 Tag ID: 10003","group":1},
{"name":"Chemical 4 Tag ID: 10004","group":1}
],
"links":[
{"source":0,"target":1,"value":1 },
{"source":0,"target":2,"value":1},
{"source":0,"target":3,"value":1},
{"source":0,"target":4,"value":1},
{"source":0,"target":0,"value":1}
]
};
var width = 1000,
height = 1000;
var force = d3.layout.force()
.charge(-300)
.linkDistance(100)
.linkStrength(15)
.size([width,height]);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var drawGraph = function(graph) {
force
.nodes(graph.nodes)
.links(graph.links)
.start();
var link = svg.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(d.value); });
var gnodes = svg.selectAll('g.gnode')
.data(graph.nodes)
.enter()
.append('g')
.classed('gnode', true);
var node = gnodes.append("circle")
.attr("class", "node")
.attr("r", function(d) { return d.name === 'RFID Scanner'? 40 : 20; })
.call(force.drag)
.filter(function(d) { return d.name !== 'RFID Scanner'})
.on("mouseover", function(d)
{
d3.select(labels[0][d.index]).style("visibility","visible")
})
.on("mouseout", function(d)
{
d3.select(labels[0][d.index]).style("visibility","hidden")
})
var labels = gnodes.append("text")
.text(function(d) { return d.name; })
.style("visibility", function(d) { return d.name === 'RFID Scanner'? 'visible' : 'hidden'; });
force.on("tick", function() {
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; });
gnodes.attr("transform", function(d) {
return 'translate(' + [d.x, d.y] + ')';
});
});
};
drawGraph(graph);
</script>
</body>
</html>
Im trying to make different lengths in the network graph. I went through the API and I think it has something to do w .linkDistance(100). I am not too sure how to go about doing this. but I want to give each node a specific length. I tried going through the links data that I hard coded but it seems pretty limited. Thank you in advance, im curious to see how you do this.
It appears that you are using d3.js version 3.
The documentation about linkDistance states:
if distance is a function, then the function is evaluated for each link (in order), being passed the link and its index, with the this context as the force layout; the function's return value is then used to set each link's distance.
So if each link valueattribute contains the desired distance, instead of:
.linkDistance(100)
You may specify:
.linkDistance(function(d) {return d.value})
Related
Hi I have this nice network graph going. The node that says "scanner" I am trying to make that radius bigger than the other nodes and I want the scanner to be printed on the node while the other nodes have the hover feature. I am struggling since the nodes have to be linked together in order for it to work cohesively. Thank you in advance, looking forward to how you tackle this issue.
var graph = {
"nodes":[
{"name":" Scanner","group":1},
{"name":"Chemical 1 ","group":1},
{"name":"Chemical 2","group":1},
{"name":"Chemical 3","group":1},
{"name":"Chemical 4","group":1}
],
"links":[
{"source":0,"target":1,"value":1},
{"source":0,"target":2,"value":1},
{"source":0,"target":3,"value":1},
{"source":0,"target":4,"value":1},
{"source":0,"target":0,"value":1}
]
};
var width = 1000,
height = 1000;
var force = d3.layout.force()
.charge(-300)
.linkDistance(300)
.size([width, height]);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var drawGraph = function(graph) {
force
.nodes(graph.nodes)
.links(graph.links)
.start();
var link = svg.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(d.value); });
var gnodes = svg.selectAll('g.gnode')
.data(graph.nodes)
.enter()
.append('g')
.classed('gnode', true);
var node = gnodes.append("circle")
.attr("class", "node")
.attr("r", 25)
.on("mouseover", function(d)
{
d3.select(labels[0][d.index]).style("visibility","visible")
})
.on("mouseout", function(d)
{
d3.select(labels[0][d.index]).style("visibility","hidden")
})
.call(force.drag);
var labels = gnodes.append("text")
.text(function(d) { return d.name; })
.style("visibility", "hidden");
force.on("tick", function() {
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; });
gnodes.attr("transform", function(d) {
return 'translate(' + [d.x, d.y] + ')';
});
});
};
drawGraph(graph);
.node {
stroke: #fff;
stroke-width: 1.5px;
}
.nodeDetail {
stroke: #fff;
stroke-width: 1.5px;
}
.link {
stroke: #999;
stroke-opacity: .6;
}
.text {
font: 12px sans-serif;
pointer-events: none; }
.node {
stroke:#fff;
stroke-width:3px;
fill:#2E8B57;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
Larger radius for "scanner" circle
d3.js selection.attr accepts a function as the second parameter, allowing to set different values according to the data.
In this function, you should check whether d.name is "Scanner", and return a radius value accordingly.
.attr("r", function(d) { return d.name === 'Scanner'? 40 : 25; })
Always display the label for Scanner
Similarly, selection.style setting visibility for labels should be initialized in a function checking data value:
.style("visibility", function(d) { return d.name === 'Scanner'? 'visible' : 'hidden'; });
In order to have the mouseover and mouseout event listeners only applying to the other nodes, use selection.filter:
.filter(function(d) { return d.name !== 'Scanner'})
.on("mouseover", function(d)
// ...
Demo
The snippet below illustrates the solution.
Remark: The leading space character scanner node found in the question has been removed in this demo : "Scanner" instead of " Scanner"
var graph = {
"nodes":[
{"name":"Scanner","group":1},
{"name":"Chemical 1 ","group":1},
{"name":"Chemical 2","group":1},
{"name":"Chemical 3","group":1},
{"name":"Chemical 4","group":1}
],
"links":[
{"source":0,"target":1,"value":1},
{"source":0,"target":2,"value":1},
{"source":0,"target":3,"value":1},
{"source":0,"target":4,"value":1},
{"source":0,"target":0,"value":1}
]
};
var width = 1000,
height = 1000;
var force = d3.layout.force()
.charge(-300)
.linkDistance(300)
.size([width, height]);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var drawGraph = function(graph) {
force
.nodes(graph.nodes)
.links(graph.links)
.start();
var link = svg.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(d.value); });
var gnodes = svg.selectAll('g.gnode')
.data(graph.nodes)
.enter()
.append('g')
.classed('gnode', true);
var node = gnodes.append("circle")
.attr("class", "node")
.attr("r", function(d) { return d.name === 'Scanner'? 40 : 25; })
.call(force.drag)
.filter(function(d) { return d.name !== 'Scanner'})
.on("mouseover", function(d)
{
d3.select(labels[0][d.index]).style("visibility","visible")
})
.on("mouseout", function(d)
{
d3.select(labels[0][d.index]).style("visibility","hidden")
})
var labels = gnodes.append("text")
.text(function(d) { return d.name; })
.style("visibility", function(d) { return d.name === 'Scanner'? 'visible' : 'hidden'; });
force.on("tick", function() {
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; });
gnodes.attr("transform", function(d) {
return 'translate(' + [d.x, d.y] + ')';
});
});
};
drawGraph(graph);
.node {
stroke: #fff;
stroke-width: 1.5px;
}
.nodeDetail {
stroke: #fff;
stroke-width: 1.5px;
}
.link {
stroke: #999;
stroke-opacity: .6;
}
.text {
font: 12px sans-serif;
pointer-events: none; }
.node {
stroke:#fff;
stroke-width:3px;
fill:#2E8B57;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
I am working in D3 version 3, and I have a simple working program that can read a JSON file and convert it into an animated, linked graph.
I was wondering if there was a way for me to color separate connected components differently, for example, have the first component colored blue and another colored red, in a way that could be applied to a larger JSON file. I am pretty new to javascript, but wondering if I could use the group id to determine a node's color. I organized my example JSON file as follows-
{
"nodes":[
{"name":"node1","group":1},
{"name":"node2","group":1},
{"name":"node3","group":1},
{"name":"node4","group":3}
],
"links":[
{"source":2,"target":1,"weight":3},
{"source":0,"target":2,"weight":3}
]
}
Note that each node is part of a group (connected component).
My index.html is as follows.
<!DOCTYPE html>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v3.min.js"></script>
<style>
svg {
background-color:red;
width: 100%;
}
.link {
stroke: #fff;
}
.node text {
stroke:#fff;
fill: aliceblue;
cursor: pointer;
font-family: fantasy;
padding: 10%;
}
.node circle{
stroke:#fff;
stroke-width:3px;
fill:#fff;
padding: 20px;
}
</style>
<body>
<div class="nodeContainer">
<script>
var width = 960,
height = 500
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var force = d3.layout.force()
.gravity(.05)
.distance(100)
.charge(-100)
.size([width, height]);
d3.json("graphFile.json", function(json) {
force
.nodes(json.nodes)
.links(json.links)
.start();
var link = svg.selectAll(".link")
.data(json.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(d.weight); });
var node = svg.selectAll(".node")
.data(json.nodes)
.enter().append("g")
.attr("class", "node")
.call(force.drag);
node.append("circle")
.attr("r","20");
node.append("text")
.attr("dx", 23)
.attr("dy", ".35em")
.text(function(d) { return d.name });
force.on("tick", function() {
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; });
node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
});
});
</script>
</div>
Here are a few approaches to color the nodes based on the group:
Using a pre-defined d3 colorScale (d3 oridnal color schemas)
var colorScale = d3.scale.category10().domain(json.nodes.map(function(d) { return d.group; }));
User defined ordinal color scale:
var colorScale = d3.scale.ordinal().domain([1, 2, 3]).range(["blue", "green", "red"]);
If the extent of the groups is huge, I'd recommend a linear scale using a gradient of colors. Similar to this: http://bl.ocks.org/jfreyre/b1882159636cc9e1283a
Using one of the above and applying to the nodes:
node.append("circle")
.attr("r","20")
.style('fill', function(d) {
return colorScale(d.group);
});
Here's a snippet:
var json = {
"nodes":[
{"name":"node1","group":1},
{"name":"node2","group":1},
{"name":"node3","group":1},
{"name":"node4","group":3}
],
"links":[
{"source":2,"target":1,"weight":3},
{"source":0,"target":2,"weight":3}
]
};
var width = 960,
height = 500
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var force = d3.layout.force()
.gravity(.05)
.distance(100)
.charge(-100)
.size([width, height]);
var colorScale = d3.scale.category10().domain(json.nodes.map(function(d) { return d.group; }));
//var colorScale = d3.scale.ordinal().domain([1, 2, 3]).range(["blue", "green", "red"]);
force
.nodes(json.nodes)
.links(json.links)
.start();
var link = svg.selectAll(".link")
.data(json.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(d.weight); });
var node = svg.selectAll(".node")
.data(json.nodes)
.enter().append("g")
.attr("class", "node")
.call(force.drag);
node.append("circle")
.attr("r","20")
.style('fill', function(d) {
return colorScale(d.group);
});
node.append("text")
.attr("dx", 23)
.attr("dy", ".35em")
.text(function(d) { return d.name });
force.on("tick", function() {
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; });
node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
});
svg {
background-color:red;
width: 100%;
}
.link {
stroke: #fff;
}
.node text {
stroke:#fff;
fill: aliceblue;
cursor: pointer;
font-family: fantasy;
padding: 10%;
}
.node circle{
stroke:#fff;
stroke-width:3px;
fill:#fff;
padding: 20px;
}
<script src="https://d3js.org/d3.v3.min.js"></script>
<div class="nodeContainer">
</div>
Hope this helps.
I am a newbie in D3JS and I was trying to do a similar example to this one : http://bl.ocks.org/mbostock/4062045
I have generated this JSON file output.json and I try to get it running but nothing shows up!
{"nodes":[{"name":"Hiroyasu Nakata","group":1},{"name":"Kazuo Satoh","group":1},{"name":"Tyuzi Ohyama","group":1},{"name":"Yasufumi Fujiwara","group":1},{"name":"Youichi Nonogaki","group":1},{"name":"Yoshikazu Takeda","group":1},{"name":"N. Tamari","group":2},{"name":"S. H. Wemple","group":3},{"name":"Kun-Jing Lee","group":4},{"name":"Z. C. Huang","group":4},{"name":"J. C. Chen","group":4},{"name":"L. Cai","group":5},{"name":"S. Han","group":5},{"name":"G. May","group":5},{"name":"S. Kamra","group":5},{"name":"T. Krygowski","group":5},{"name":"A. Rohatgi","group":5},{"name":"Stephen Miller","group":7},{"name":"Paul H. Holloway","group":7}],"links":[{"source":1,"target":2},{"source":1,"target":3},{"source":1,"target":4},{"source":1,"target":5},{"source":1,"target":6},{"source":2,"target":3},{"source":2,"target":4},{"source":2,"target":5},{"source":2,"target":6},{"source":3,"target":4},{"source":3,"target":5},{"source":3,"target":6},{"source":4,"target":5},{"source":4,"target":6},{"source":5,"target":6},{"source":9,"target":10},{"source":9,"target":11},{"source":10,"target":11},{"source":12,"target":13},{"source":12,"target":14},{"source":12,"target":15},{"source":12,"target":16},{"source":12,"target":17},{"source":13,"target":14},{"source":13,"target":15},{"source":13,"target":16},{"source":13,"target":17},{"source":14,"target":15},{"source":14,"target":16},{"source":14,"target":17},{"source":15,"target":16},{"source":15,"target":17},{"source":16,"target":17},{"source":18,"target":19}]}
This is the HTML file :
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.node {
stroke: #fff;
stroke-width: 1.5px;
}
.link {
stroke: #999;
stroke-opacity: .6;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var width = 960,
height = 500;
var color = d3.scale.category20();
var force = d3.layout.force()
.charge(-120)
.linkDistance(30)
.size([width, height]);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
d3.json("output.json", function(error, graph) {
force
.nodes(graph.nodes)
.links(graph.links)
.start();
var link = svg.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(d.value); });
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", 5)
.style("fill", function(d) { return color(d.group); })
.call(force.drag);
node.append("title")
.text(function(d) { return d.name; });
force.on("tick", function() {
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; });
node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
});
});
</script>
What did I do wrong? And how can I fix it?
Thanks!
I am trying to display the text when I move the mouse over a node in Force-Directed Graph in D3.js. My problem is that when I move the mouse over any node, all the texts of these nodes are displayed. Here is my code:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
.node {
stroke: #fff;
stroke-width: 1.5px;
}
.nodeDetail {
stroke: #fff;
stroke-width: 1.5px;
}
.link {
stroke: #999;
stroke-opacity: .6;
}
node .text {
font: 12px sans-serif;
pointer-events: none;
}
</style>
</head>
<body>
<script src="http://d3js.org/d3.v3.js"></script>
<script src="d3/d3.v3.min.js charset=UTF-8"></script>
<script>
var graph = {
"nodes":[
{"name":"Myriel","group":1},
{"name":"Napoleon","group":1},
{"name":"Mlle.Baptistine","group":1},
{"name":"Mme.Magloire","group":1},
{"name":"CountessdeLo","group":1}
],
"links":[
{"source":1,"target":0,"value":1},
{"source":2,"target":0,"value":8},
{"source":3,"target":0,"value":10},
{"source":3,"target":2,"value":6},
{"source":4,"target":0,"value":1}
]
};
var width = 960,
height = 500;
var color = d3.scale.category20();
var force = d3.layout.force()
.charge(-120)
.linkDistance(30)
.size([width, height]);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var drawGraph = function(graph) {
force
.nodes(graph.nodes)
.links(graph.links)
.start();
var link = svg.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(d.value); });
var gnodes = svg.selectAll('g.gnode')//('g.gnode')
.data(graph.nodes)
.enter()
.append('g')
.classed('gnode', true);
var node = gnodes.append("circle")
.attr("class", "node")
.attr("r", 5)
.style("fill", function(d) { return color(d.group); })
.on("mouseover", function(d)
{
d3.select(this).transition()
.duration(750)
.attr("r", 15);
return labels.style("visibility", "visible");
})
.on("mouseout", function()
{
d3.select(this).transition()
.duration(750)
.attr("r", 5);
return labels.style("visibility", "hidden");//})
})
.call(force.drag);
var labels = gnodes.append("text")
.text(function(d) { return d.name; })
.style("visibility", "hidden");
/*gnodes.append("text")
.text(function(d) { return d.name; })
.style("visibility", "hidden");*/
force.on("tick", function() {
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; });
gnodes.attr("transform", function(d) {
return 'translate(' + [d.x, d.y] + ')';
});
});
};
drawGraph(graph);
</script>
</body>
</html>
I tried to do the following codes but it did not work neither:
.on("mouseover", function(d)
{
d3.select(this).transition()
.duration(750)
.attr("r", 15);
d3.select(this).append(text)
.style("visibility", "visible");
})
How can I display the text that is related to a particular node when I move the mouse over that node? Could anyone please help me solve this problem. Thank you in advance.
This should help:
.on("mouseover", function(d)
{
d3.select(labels[0][d.index]).style("visibility","visible")
})
.on("mouseout", function(d)
{
d3.select(labels[0][d.index]).style("visibility","hidden")
})
Learning d3 myself here - also thanks very much to juvian
I find a more transparent way of coding this would be to say
.on("mouseover", function(d) {
d3.select(this).select("text").style("visibility", "visible")
})
which selects the object you hover over (a group), selects the text inside it and changes the style to visible. This also avoids the need to make a labels variable which gets a bit messy with the array indexing.
I have created three nodes (circles) based on reading some data from JSON file using D3 Javascript. Here are my code and the JSON file:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<style>
.node {
stroke: #fff;
stroke-width: 1.5px;
}
.link {
stroke: #999;
stroke-opacity: .6;
}
</style>
<body>
<script type="text/javascript" src="d3.v3.js"></script>
<script>
var width = 960,
height = 500;
var color = d3.scale.category20();
var force = d3.layout.force()
.charge(-120)
.linkDistance(30)
.size([width, height]);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
d3.json("input.json", function(error, graph) {
force
.nodes(graph.nodes)
.links(graph.links)
.start();
var link = svg.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(d.value); });
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", 5)
.style("fill", function(d) { return color(d.group); })
.call(force.drag);
node.append("title")
.text(function(d) { return d.name; });
force.on("tick", function() {
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; });
node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
});
});
</script>
</body>
</html>
This is the JSON file:
{
"nodes": [
{
"name": "A",
"group": 1
},
{
"name": "B",
"group": 1
},
{
"name": "C",
"group": 1
}
],
"links": [
{
"source": 0,
"target": 1,
"value": 2
},
{
"source": 0,
"target": 2,
"value": 2
}
]
}
The code works simply as follows: There is a base node that is linked to two other nodes. What I would like to do is when I move the mouse over the base node, the other two nodes that connected to the base node will be displayed. As soon as you move the mouse out of the base node, the other two nodes will hide. I am new to D3 Javascript and do not know how to code this part.
You can do this by attaching mouse event handlers to the nodes that set the visibility accordingly. I've taken your example and modified the data slightly so that the node that's triggering these actions has group 2 to be able to identify it.
Then all you need to do is select the other nodes based on the group and set visibility:
var node = svg
.selectAll(".node")
.data(graph.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", 5)
.style("fill", function (d) { return color(d.group); })
.call(force.drag)
.style("visibility", function (d) {
return d.group === 1 ? "hidden" : "visible";
})
.on("mouseover", function (d) {
if (d.group === 2) {
node.filter(function (d) { return d.group === 1; })
.style("visibility", "visible");
}
})
.on("mouseout", function (d) {
if (d.group === 2) {
node.filter(function (d) { return d.group === 1; })
.style("visibility", "hidden");
}
});
Complete example here.