How to draw nodes in D3 Javascript library based on JSON file - javascript

I am trying to draw nodes (circles) in D3 Javascript library based on the following JSON file:
{
"nodes":[{"name":["Node1", "Node2", "Node3"]},
{"name":["Node4"]},
{"name":["Node5"]}]
}
Here are my codes:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Sample2</title>
<style>
.node {
stroke: #fff;
stroke-width: 1.5px;
}
</style>
</head>
<body>
<script type="text/javascript" src="d3/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("folder/jsonsample.json", function(error, graph) {
force
.nodes(graph.nodes)
.start();
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", 10)
.call(force.drag);
node.append("title")
.text(function(d) { return d.name; });
force.on("tick", function() {
node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
});
});
</script>
</body>
</html>
With this HTML file, I drew only three circles because the code is based on the fact that there are three names. I would like to draw five nodes (circles) since I have Node1, Node2, Node3, Node4 and Node5 inside the "name, name, and name". Could anyone please help me draw five circles. Your help is very much appreciated.

Maybe you can use Collapsible Force Layout, see example at mbostock block. With that example and the following json file (changed his readme.json file):
{
"name": "example",
"children": [
{
"name": "group1",
"children": [
{"name": "node1", "size": 3000},
{"name": "node2", "size": 3000},
{"name": "node3", "size": 3000}
]
},
{
"name": "node4", "size": 5000
},
{
"name": "node5", "size": 10000
}
]
}
you can get something similar. You get one root element with 3 children, one has 3 nodes. See
If you select root node everything colapse.

Related

How can I load a json file in d3.js code? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 days ago.
Improve this question
I am trying to create a force directed graph with the help of d3.js. But I am being unable to load the data from a sample JSON file. I have mentioned all the required attributes for both nodes and links in the codes but still the svg page is not showing any image of any sort.
Following is the full HTML code which I wrote:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.node {
fill: blue;
stroke: black;
stroke-width: 2px;
}
.node.visited {
fill: red;
}
.link {
stroke-width: 2px;
}
</style>
<body>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script>
var width = 640;
var height = 480;
var svg = d3.select('body').append('svg')
.attr('width', width)
.attr('height', height);
d3.json('data.json'), function(d){
var nodes = d[nodes];
var links = d[links];
var defs = svg.append('defs');
var gradient = defs
.append('linearGradient')
.attr('id', 'svgGradient')
.attr('x1', '0%')
.attr('x2', '10%')
.attr('y1', '0%')
.attr('y2', '10%');
gradient
.append('stop')
.attr('class', 'start')
.attr('offset', '0%')
.attr('start-color', 'red')
.attr('start-opacity', 1);
gradient
.append('stop')
.attr('class', 'end')
.attr('offset', '100%')
.attr('stop-color', 'blue')
.attr('stop-opacity', 1);
var force = d3.layout.force()
.size([width, height])
.nodes(d3.values(nodes))
.links(links)
.on("tick", tick)
.linkDistance(300)
.start();
var link = svg.selectAll('.link')
.data(links)
.enter().append('line')
.attr('class', 'link')
.attr('stroke', 'url(#svgGradient)');
var node = svg.selectAll('.node')
.data(force.nodes())
.enter().append('circle')
.attr('class', 'node')
.attr('r', width * 0.03)
.attr('cx', function(d) {
return d.x;
})
.attr('cy', function(d) {
return d.y;
});
//define the tick func.
function tick(e) {
node
.attr('cx', function(d) {
return d.x;
})
.attr('cy', function(d) {
return d.y;
})
.call(force.drag);
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>
</body>
And here is the sample JSON file with all the data:
{
"nodes": [
{
"data": {
"id": 1,
"desc": "node_1",
"pos": [
121.0284957885742,
116.3165512084961,
59.36788940429688
]
}
},
{
"data": {
"id": 2,
"desc": "node_2",
"pos": [
123.3528213500977,
102.4375305175781,
85.59683990478516
]
}
},
{
"data": {
"id": 3,
"desc": "node_3",
"pos": [
140.7859497070312,
107.8107681274414,
94.63105773925781
]
}
},
"edges": [
{
"data": {
"id": "1_2",
"source": 1,
"target": 2
}
},
{
"data": {
"id": "2_3",
"source": 2,
"target": 3
}
},
{
"data": {
"id": "3_1",
"source": 3,
"target": 1
}
}
}
]
Please make the required changes so that the file can be uploaded without throwing an error.

Plotting nodes and links from JSON files with SVG

I'm new to D3 and I'm having trouble visualising my json file. I'm supposed to plot the locations (sites) as circles with their radius equal to the "amount". I'm extremely confused about how to work with the nodes and links. I have provided an example of the JSON code as well. Please help me understand where I am going wrong with the coding
<html>
<head>
<title>D3 Visualisation </title>
<h1> Trading Data </h1>
<style>
.svgCanvas {
border: solid 1px
}
</style>
</head>
<body>
<svg></svg>
<script src="https://d3js.org/d3.v4.min.js"></script> <script>
window.onload = function(){
var width = 800;
var height = 300;
var thisCanvas = d3.select("svg")
.attr("width", width)
.attr("height", height)
.attr("class", "svgCanvas");
d3.json("data.json", function(d){
console.log(d);
var svgCanvas.selectAll("circle")
.data(d).enter()
.append("circle")
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.attr("r", function(d) { return d.amount; } )
.style("fill", “lightgreen”); })
})
}
</script>
</body>
</html>
The Json code example is as follows:
{
"nodes": [
{
"id": "site09",
"x": 317.5,
"y": 282.5
},
{
"id": "site01",
"x": 112,
"y": 47
},
{
"id": "site03",
"x": 69.5,
"y": 287
}
],
"links": [
{"node01": "site05", "node02": "site08", "amount": 10},
{"node01": "site05", "node02": "site02", "amount": 120},
{"node01": "site05", "node02": "site03", "amount": 50}
]
}
Here you can get the working solution. Just replace the data object with json.
https://playcode.io/324480?tabs=console&script.js&output

Uncaught TypeError: Cannot read property 'weight' of undefined

I am trying to build a force directed graph in D3. Here is the code for it -
index.html
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.node {
stroke: #FFFF;
stroke-width: 1.5px;
}
.link {
stroke: #111;
}
</style>
<body>
<h1>Hello there</h1>
<script src="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("copy.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) { console.log(d.value); return d.value; });
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", 10)
.style("fill", function(d) { console.log(d.name); 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 code works with copy.json file. I just copy pasted the json from here into that file. I have tried to create my own json by parsing through a txt file. The same code is giving me the error when I use my json file. Here is my json file (part of it) -
{
"nodes":[
"group": 5,
"name": "Nancie"
},
{
"group": 5,
"name": "Jonell"
}
],
"links": [
{
"source": 1,
"target": 29,
"value": 2
},
{
"source": 1,
"target": 43,
"value": 3
}
]
}
I have tested this json on jsonlint. Does the newline make a difference? I did read a couple of answer that are there on SO about this but none of them match. My source and target nodes are within range, I have no null values and I have taken care of the case when creating my JSON.
Well as it turns out I made a stupid mistake while creating my json file. In the links part of the json the numbering for source starts from 0. Hence for the last element I was exceeding the value. And hence I was getting that error.

D3 label on a line in forced graph

There is example how to have a label on the node in a D3 forced graph. What I try to do is to have a label on the line instead.
Example of the label on node: http://bl.ocks.org/mbostock/2706022
This code will display the text for the line up in the left corner. It seems that it takes the x, y cordinates from the canvas and not from my line. How to fix this?
var labelLine = olinks.append("text")
.attr("x", 12)
.attr("dy", ".35em")
.text("eeeeee");
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.node {
stroke: #fff;
stroke-width: 1.5px;
}
.link {
stroke: #999;
stroke-opacity: .6;
}
</style>
<body>
<script src="./Script/d3.v3/d3.v3.min.js"></script>
<script>
var graph = {
"nodes": [
{ "name": "App1-main", "group": 1 },
{ "name": "App2", "group": 1 },
{ "name": "App3", "group": 1 },
{ "name": "App4", "group": 1 },
{ "name": "Content-1", "group": 3 },
{ "name": "Content-1", "group": 3 },
{ "name": "Content-1", "group": 3 },
{ "name": "Content-1", "group": 3 },
{ "name": "Pontmercy", "group": 3 }
],
"links": [
{ "source": 1, "target": 0, "value": 1 },
{ "source": 2, "target": 0, "value": 1 },
{ "source": 0, "target": 3, "value": 1 }
]
};
var width = 960,
height = 500;
var color = d3.scale.category20();
var force = d3.layout.force()
.charge(-300)
.linkDistance(60)
.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 olinks = svg.selectAll("g.link")
.data(graph.links)
.enter().append("g")
.call(force.drag);
var link = olinks.append("line")
.attr("class", "link")
.style("stroke-width", function (d) { return Math.sqrt(d.value); });
var labelLine = olinks.append("text")
.attr("x", 12)
.attr("dy", ".35em")
.text("eeeeee");
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", 5)
.style("fill", function (d) { return color(d.group); })
.call(force.drag);
var labels = gnodes.append("text")
.attr("x", 12)
.attr("dy", ".35em")
.text(function (d) { return d.name; });
console.log(labels);
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>
This is an example that has correct behavior.
The key points are here:
1) You need to define link as SVG "g" element, so that you can define both lines and labels for each link, and that coordinates are computed correctly.
2) Label text must be centered horizontally (code: .attr("text-anchor", "middle")).
3) Inside tick(), you need to compute coordinate of the labels., as arithmetic mean between source and target node.
Hope this helps.
There also was another similar question recently.

How do I make a d3.js force directed graph interactive using ajax and python?

I am trying to make a force directed graph in d3.js interactive.
I created the html that displays it and also wrote the python scripts that generate the content. But I can't get it to work together.
I can call the python script from the browser and it returns valid json but how do i get it into d3?
Somehow it always calls the url with the result appended (*GET http://localhost/vici/[object%20Object] 404 (Not Found)*) but the alert displays the result of the python script.
This is my code:
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8>
<script type="text/javascript" src="d3.v2.js?2.1.3"></script>
<script src="jquery-1.8.3.js"></script>
<style type="text/css">
circle {
stroke-width: 1.5px;
}
line {
stroke: #999;
}
text {
font: 10px sans-serif;
pointer-events: none;
}
</style>
</head>
<body>
<script type="text/javascript">
$(document).ready(function() {
$.ajax({
type: "GET",
url: "/vici/kellner.py/display",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: {name: 302,level: 2}
})
.success(function(pyjson) {
alert(pyjson);
var data = pyjson;
var w = 960,
h = 600,
r = 6;
var svg = d3.select("#d3vis").append("svg:svg")
.attr("width", w)
.attr("height", h);
d3.json(pyjson, function(json) {
var force = d3.layout.force()
.nodes(json.nodes)
.links(json.links)
.gravity(.02)
.distance(50)
.charge(-400)
.size([w, h])
.start();
var link = svg.selectAll("line.link")
.data(json.links)
.attr("class", "link")
.enter().append("svg:line");
var node = svg.selectAll(".node")
.data(json.nodes)
.enter().append("g")
.attr("class", "node")
.call(force.drag);
node.append("image")
.attr("xlink:href", function(d) { return d.avatar })
.attr("x", -8)
.attr("y", -8)
.attr("width", function(d) { return d.avatarWidth })
.attr("height", function(d) { return d.avatarHeight });
node.append("text")
.attr("dx", 12)
.attr("dy", ".70em")
.text(function(d) { return d.avatarName });
node.append("svg:title")
.text(function(d) { return d.author; }, function(d) { return d.institute; } );
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 id="d3vis"></div>
</body>
</html>
But not just that: How can I get d3 to reload after clicking a node? Every node has a name ("author":"Some Name") and my python script can search for that name and return a new result.
I have search for this and found some things (e.g. Updating links on a force directed graph from dynamic json data) what seems would be really nice and what I would want to do, but I do not understand it so I can't modify it to my needs. (Where does the data come from or where can i call my python script to provide the data?)
I just need to get the json into d3 and change the graph when clicking on a node.
I am new to Java Script so any help would be greatly appreciated.
EDIT:
Here still some test data:
{
"nodes": [
{"institute": "None", "avatarWidth": "16", "avatar": "img/user.png", "avatarHeight": "16", "author": "Some Name"},
{"institute": "None", "avatarWidth": "16", "avatar": "img/user.png", "avatarHeight": "16", "author": "Some Name"},
{"institute": "None", "avatarWidth": "16", "avatar": "img/user.png", "avatarHeight": "16", "author": "Some Name"},
{"author": "Main Name", "institute": "None", "avatarName": "Main Name", "avatar": "img/main.png", "avatarHeight": "24", "avatarWidth": "24"},
{"institute": "None", "avatarWidth": "16", "avatar": "img/user.png", "avatarHeight": "16", "author": "Some Name"}
],
"links": [
{"color": "red", "source": 0, "target": 2, "weight": 1},
{"color": "orange", "source": 1, "target": 2, "weight": 1},
{"color": "yellow", "source": 2, "target": 3, "weight": 1},
{"color": "yellow", "source": 2, "target": 4, "weight": 1}
]
}
Okay, so apparently the d3.json(pyjson, function(json) { Line was the "bad" one. Is this d3 trying to make its own ajax request?
Anyway I removed it and it seems to be working now. Also my idea of clicking a node to reload is not really ideal since you have to be able to pull them around and clicking would stop that.
Here my functioning code for future reference: (And others that have the same problem)
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8>
<script type="text/javascript" src="d3.v2.js?2.1.3"></script>
<script src="jquery-1.8.3.js"></script>
<style type="text/css">
circle {
stroke-width: 1.5px;
}
line {
stroke: #999;
}
text {
font: 10px sans-serif;
pointer-events: none;
}
</style>
</head>
<body>
<script type="text/javascript">
$(document).ready(function() {
$.ajax({
type: "GET",
url: "/vici/kellner.py/display",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: {name: 302,level: 2}
})
.done(function(pyjson) {
var w = 960,
h = 600,
r = 6;
var svg = d3.select("#d3vis").append("svg:svg")
.attr("width", w)
.attr("height", h);
var force = d3.layout.force()
.nodes(pyjson.nodes)
.links(pyjson.links)
.gravity(.02)
.distance(50)
.charge(-400)
.size([w, h])
.start();
var link = svg.selectAll("line.link")
.data(pyjson.links)
.attr("class", "link")
.enter().append("svg:line");
var node = svg.selectAll(".node")
.data(pyjson.nodes)
.enter().append("g")
.attr("class", "node")
.call(force.drag);
node.append("image")
.attr("xlink:href", function(d) { return d.avatar })
.attr("x", -8)
.attr("y", -8)
.attr("width", function(d) { return d.avatarWidth })
.attr("height", function(d) { return d.avatarHeight });
node.append("text")
.attr("dx", 12)
.attr("dy", ".70em")
.text(function(d) { return d.avatarName });
node.append("svg:title")
.text(function(d) { return d.author; }, function(d) { return d.institute; } );
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 + ")"; });
}); //End of force.on("tick", function() {
}); //End of .done(function(pyjson) {
}); //End of $(document).ready(function() {
</script>
<div id="d3vis"></div>
</body>
</html>

Categories