How to customise the Force-Directed Graph example? - javascript

As soon as I try to modify the json file from the Force-Directed Graph Example it gives me the following error:
Uncaught TypeError: Cannot read property 'nodes' of undefined
SyntaxError: Unexpected token
Code:
<!DOCTYPE html>
<meta charset="UTF8">
<style>
.node {
stroke: #fff;
stroke-width: 1.5px;
}
.link {
fill: none;
stroke: #bbb;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script>
var width = window.innerWidth,
height = window.innerHeight;
var color = d3.scale.category20();
var force = d3.layout.force()
.linkDistance(10)
.linkStrength(2)
.size([width, height]);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
d3.json("xPata.json", function(error, graph) {
var nodes = graph.nodes.slice(),
links = [],
bilinks = [];
graph.links.forEach(function(link) {
var s = nodes[link.source],
t = nodes[link.target],
i = {}; // intermediate node
nodes.push(i);
links.push({
source: s,
target: i
}, {
source: i,
target: t
});
bilinks.push([s, i, t]);
});
force
.nodes(nodes)
.links(links)
.start();
var link = svg.selectAll(".link")
.data(bilinks)
.enter().append("path")
.attr("class", "link");
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("d", function(d) {
return "M" + d[0].x + "," + d[0].y + "S" + d[1].x + "," + d[1].y + " " + d[2].x + "," + d[2].y;
});
node.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
});
});
</script>
</body>
</html>
JSON:
{
"nodes":[
{"name":"Myriel","group":1},
{"name":"Napoleon","group":1},
{"name":"Mlle.Baptistine","group":1},
{"name":"Mme.Magloire","group":1},
{"name":"CountessdeLo","group":1},
{"name":"Geborand","group":1},
{"name":"Geborand","group":1}
],
"links":[
{"source":1,"target":0,"value":8},
{"source":2,"target":0,"value":8},
{"source":3,"target":0,"value":10},
{"source":4,"target":3,"value":10},
{"source":5,"target":3,"value":10},
{"source":6,"target":2,"value":10},
{"source":7,"target":5,"value":10}
]
}
When I rename the json file it loads just fine. What is going on? Happens on other examples as well.

Turns out it had nothing to do with D3.js. My webserver was the cause of the problem; it cached the json file. Doesn't explain the error, but it does explain the rename fix.

Related

Javascript d3.js reading local CSV file

So I need to read a .CSV file using a HTML webpage loaded locally (e.g with file:///) and plot the contants on a graph using d3.js. So far I have attempted to join two examples together without success...
If you open it, it is able to read the contents of the local csv file, but for some reason the graph does not appear.
Any help much appreciated!
<!DOCTYPE html>
<style> /* set the CSS */
body { font: 12px Arial;}
path {
stroke: steelblue;
stroke-width: 2;
fill: none;
}
.axis path,
.axis line {
fill: none;
stroke: grey;
stroke-width: 1;
shape-rendering: crispEdges;
}
</style>
<html lang="en">
<head>
<meta http-equiv="X-UA-Compatible" content="chrome=1" />
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<!--this doesn't seem to help-->
<meta http-equiv="Access-Control-Allow-Origin" content="*"/>
<title>Process local CSV file</title>
<script src="d3.js" charset="utf-8"></script>
</head>
<body>
<script>
var rowToHtml = function( row ) {
var result = "";
for (key in row) {
result += key + ": " + row[key] + "<br/>"
}
return result;
}
var previewCsvUrl = function( csvUrl ) {
d3.csv( csvUrl, function( rows ) {
d3.select("div#preview").html(
"<b>First row:</b><br/>" + rowToHtml(rows[0]));
})
}
d3.select("html")
.style("height","100%")
d3.select("body")
.style("height","100%")
.style("font", "12px sans-serif")
.append("input")
.attr("type", "file")
.attr("accept", ".csv")
.style("margin", "5px")
.on("change", function() {
var file = d3.event.target.files[0];
if (file) {
var reader = new FileReader();
reader.onloadend = function(event1) {
var dataUrl = event1.target.result;
// The following call results in an "Access denied" error in IE.
previewCsvUrl(dataUrl);
rendergraph(dataUrl);
};
reader.readAsDataURL(file);
}
})
d3.select("body")
.append("div")
.attr("id", "preview")
.style("margin", "5px")
var svg = d3.select("svg"),
margin = {top: 20, right: 20, bottom: 30, left: 50},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom,
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var parseTime = d3.timeParse("%d-%b-%y");
var x = d3.scaleTime()
.rangeRound([0, width]);
var y = d3.scaleLinear()
.rangeRound([height, 0]);
var line = d3.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.close); });
var rendergraph = function( url1 ) {
d3.csv(url1, function(d) {
d.date = parseTime(d.date);
d.close = +d.close;
return d;
}, function(error, data) {
if (error) throw error;
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain(d3.extent(data, function(d) { return d.close; }));
g.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.select(".domain")
.remove();
g.append("g")
.call(d3.axisLeft(y))
.append("text")
.attr("fill", "#000")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", "0.71em")
.attr("text-anchor", "end")
.text("Price ($)");
g.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("stroke-width", 1.5)
.attr("d", line);
});
}
</script>
</body>
</html>
svg is being selected here but its not there in dom:
var svg = d3.select("svg"),
Either add svg element in the html or append to body using d3 by replacing the above code with:
var svg = d3.select("body").append('svg').attr('width', 300).attr('height', 300),

How to build a tree with nodes having multiple parents?

I'm using the cluster layout of D3.js and I'd like to allow multiple parents.
How can a node have multiple parents ?
Here is what I have so far: (JSFiddle)
var json = {
"name": "cluster",
"children": [{
"name": "AgglomerativeCluster"
}, {
"name": "CommunityStructure"
}, {
"name": "HierarchicalCluster"
}, {
"name": "MergeEdge"
}]
};
var width = 500,
height = 250;
var cluster = d3.layout.cluster()
.size([width, height - 160]);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(0, 40)");
var nodes = cluster.nodes(json);
var link = svg.selectAll(".link")
.data(cluster.links(nodes))
.enter().append("path")
.attr("class", "link")
.attr("d", function(d, i) {
return "M" + d.source.x + "," + d.source.y + "V" + (d.target.y / 2) + "H" + d.target.x + "V" + d.target.y;
});
var node = svg.selectAll(".node")
.data(nodes)
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
})
node.append("circle")
.attr("r", 4.5);
node.append("text")
.attr("dx", 3)
.attr("dy", function(d) {
return d.children ? -10 : 10;
})
.attr("text-anchor", function(d) {
return d.children ? "end" : "start";
})
.text(function(d) {
return d.name;
});
.node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 1.5px;
}
.node {
font: 10px sans-serif;
}
.link {
fill: none;
stroke: #ccc;
stroke-width: 1.5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
I'm wondering if it is possible. The data model currently doesn't allow this kind of behavior IMHO, but I don't know a lot of D3, so maybe there is a way around ?

Using the JSON result of a SPARQL query with d3.js

I have this problem, I am trying to use the "data" I get from the SPARQL query to make a graph that looks like this:
Bubble Chart
I can do it if I download first the .json file and then use it to make the graph, but not in this way.
<?xml version="1.0" encoding="ISO-8859-1" ?>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="es">
<head>
<title>Contratos Zaragoza</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
<script src="d3/d3.min.js"></script>
<style>
.boton{margin-top:1em;}
</style>
</head>
<body>
<script src="js/jquery-1.10.2.min.js"></script>
<p id="grafico"></p>
</body>
</html>
And here it is the javascript where the problem should be:
<script type="text/javascript">
var SPARQL_ENDPOINT = 'http://datos.zaragoza.es/sparql';
var query = 'PREFIX pproc: <http://contsem.unizar.es/def/sector- publico/pproc#>\
PREFIX dcterms: <http://purl.org/dc/terms/>\
SELECT DISTINCT ?CIF COUNT(?Titulo) as ?Contratos \
WHERE {\
?uri a <http://contsem.unizar.es/def/sector-publico/pproc#Contract>.\
?uri dcterms:title ?Titulo.\
?uri <http://purl.org/procurement/public-contracts#tender> ?a.\
?a <http://purl.org/procurement/public-contracts#supplier> ?empresaid.\
?empresaid <http://www.w3.org/ns/org#identifier> ?CIF.\
}\
ORDER BY desc(?Contratos)\
LIMIT 50';
$.getJSON(SPARQL_ENDPOINT + '?query=' + encodeURIComponent(query) + '&format=application%2Fsparql-results%2Bjson&timeout=0')
.success(function(data) {
var diameter = 1300,
format = d3.format(",d");
var color = d3.scale.ordinal()
.domain(["Sqoop", "Pig", "Apache", "a", "b", "c", "d", "e", "f", "g"])
.range(["steelblue", "pink", "lightgreen", "violet", "orangered", "green", "orange", "skyblue", "gray", "aqua"]);
var bubble = d3.layout.pack()
.sort(null)
.size([diameter, diameter])
.padding(10);
var svg = d3.select("#chart").append("svg")
.attr("width", diameter)
.attr("height", diameter)
.attr("class", "bubble");
var node = svg.selectAll(".node")
.data(bubble.nodes(classes(data.results))
.filter(function (d) {
return !d.children;
}))
.enter().append("g")
.attr("class", "node")
.attr("transform", function (d) {
return "translate(" + d.x + "," + d.y + ")";
});
node.append("title")
.text(function(d) { return d.className.value + ": " + d.value; });
node.append("circle")
.attr("r", function (d) {
return d.r;
})
.style("fill", function (d, i) {
return color(i);
});
node.append("text")
.attr("dy", ".3em")
.style("text-anchor", "middle")
.text(function(d) { return d.className.value + ": " + d.value; });
// Returns a flattened hierarchy containing all leaf nodes under the root.
function classes(root) {
var classes = [];
function recurse(name, node) {
if (node.bindings) node.bindings.forEach(function (child) {
recurse(node.CIF, child);
});
else classes.push({
packageName: name,
className: node.CIF,
value: node.Contratos.value
});
}
recurse(null, root);
return {
children: classes
};
}
d3.select(self.frameElement).style("height", diameter + "px");
});
</script>
I do not understand why it does not work that way because in both cases the object is the same.
Any comment would be very helpful.

Getting Sankey diagram in D3 from csv file

I am attempting to create a Sankey diagram from a csv file. I am utilizing code provided by timelyportfolio, and also the code from the d3 site (and even the sample csv files). However, when I try to run the code in Chrome, I am getting a blank Html page, indicating that the code is crashing. I attempted to redirect the source codes to files on my desktop, but I am still running into the same issues. (I am working on a computer with Windows XP)
I have pasted the code below:
<!DOCTYPE html>
<meta charset="utf-8">
<title>SANKEY Experiment</title>
<style>
.node rect {
cursor: move;
fill-opacity: .9;
shape-rendering: crispEdges;
}
.node text {
pointer-events: none;
text-shadow: 0 1px 0 #fff;
}
.link {
fill: none;
stroke: #000;
stroke-opacity: .2;
}
.link:hover {
stroke-opacity: .5;
}
</style>
<body>
<p id="chart">
<script src="http://d3js.org/d3.v3.js"></script>
<script src="C:\Documents and Settings\jennifer.ducz\Desktop\sankey.js"></script>
<script>
var units = "Units";
var margin = {top: 10, right: 10, bottom: 10, left: 10},
width = 1400 - margin.left - margin.right,
height = 740 - margin.top - margin.bottom;
var formatNumber = d3.format(",.0f"), // zero decimal places
format = function(d) { return formatNumber(d) + " " + units; },
color = d3.scale.category20();
// append the svg canvas to the page
var svg = d3.select("#chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// Set the sankey diagram properties
var sankey = d3.sankey()
.nodeWidth(36)
.nodePadding(10)
.size([width, height]);
var path = sankey.link();
// load the data with d3.csv instead of d3.json
//for another much simpler example uncomment the below
d3.csv("C:\Documents and Settings\jennifer.ducz\Desktop\sankey.csv", function(error, data) {
//d3.csv("d3noob_energy.csv", function(error, data) {
//set up graph in same style as original example but empty
graph = {"nodes" : [], "links" : []};
data.forEach(function (d) {
graph.nodes.push({ "name": d.source });
graph.nodes.push({ "name": d.target });
graph.links.push({ "source": d.source, "target": d.target, "value": +d.value });
});
//thanks Mike Bostock https://groups.google.com/d/msg/d3-js/pl297cFtIQk/Eso4q_eBu1IJ
//this handy little function returns only the distinct / unique nodes
graph.nodes = d3.keys(d3.nest()
.key(function (d) { return d.name; })
.map(graph.nodes));
//it appears d3 with force layout wants a numeric source and target
//so loop through each link replacing the text with its index from node
graph.links.forEach(function (d, i) {
graph.links[i].source = graph.nodes.indexOf(graph.links[i].source);
graph.links[i].target = graph.nodes.indexOf(graph.links[i].target);
});
//now loop through each nodes to make nodes an array of objects rather than an array of strings
graph.nodes.forEach(function (d, i) {
graph.nodes[i] = { "name": d };
});
sankey
.nodes(graph.nodes)
.links(graph.links)
.layout(32);
// add in the links
var link = svg.append("g").selectAll(".link")
.data(graph.links)
.enter().append("path")
.attr("class", "link")
.attr("d", path)
.style("stroke-width", function(d) { return Math.max(1, d.dy); })
.sort(function(a, b) { return b.dy - a.dy; });
// add the link titles
link.append("title")
.text(function(d) {
return d.source.name + " → " +
d.target.name + "\n" + format(d.value); });
// add in the nodes
var node = svg.append("g").selectAll(".node")
.data(graph.nodes)
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")"; })
.call(d3.behavior.drag()
.origin(function(d) { return d; })
.on("dragstart", function() {
this.parentNode.appendChild(this); })
.on("drag", dragmove));
// add the rectangles for the nodes
node.append("rect")
.attr("height", function(d) { return d.dy; })
.attr("width", sankey.nodeWidth())
.style("fill", function(d) {
return d.color = color(d.name.replace(/ .*/, "")); })
.style("stroke", function(d) {
return d3.rgb(d.color).darker(2); })
.append("title")
.text(function(d) {
return d.name + "\n" + format(d.value); });
// add in the title for the nodes
node.append("text")
.attr("x", -6)
.attr("y", function(d) { return d.dy / 2; })
.attr("dy", ".35em")
.attr("text-anchor", "end")
.attr("transform", null)
.text(function(d) { return d.name; })
.filter(function(d) { return d.x < width / 2; })
.attr("x", 6 + sankey.nodeWidth())
.attr("text-anchor", "start");
// the function for moving the nodes
function dragmove(d) {
d3.select(this).attr("transform",
"translate(" + (
d.x = Math.max(0, Math.min(width - d.dx, d3.event.x))
) + "," + (
d.y = Math.max(0, Math.min(height - d.dy, d3.event.y))
) + ")");
sankey.relayout();
link.attr("d", path);
}
});
</script>
</body>
</html>
If someone can tell me what I'm doing wrong, please let me know.
Edit: This is the sample data I'm using courtesy of timelyportfolio
source target value
Barry Elvis 2
Frodo Elvis 2
Frodo Sarah 2
Barry Alice 2
Elvis Sarah 2
Elvis Alice 2
Sarah Alice 4
I've never played with it; however,
1) run your developer tools/console to see exactly which line is crashing the app
2) the following link discusses problems/solutions in formatting the data
http://www.d3noob.org/2013/02/sankey-diagrams-description-of-d3js-code.html
if you are not using MAMP or any other kind of virtual server, Chrome won't load the csv or any other local files other than the html. Try using a local webserver and everything should be fine

How to send a value from D3 node to Servlet

I have an application where i am populating a tree like structure with D3.js.Each node in this tree represents a name.I am able to catch the nodes name in a java script alert when i am clicking on the node .But my requirement is that i should send the name, which is coming with an alert to a Servlet.Here is my code
.node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 1.5px;
}
.node {
font: 10px sans-serif;
}
.link {
fill: none;
stroke: #ccc;
stroke-width: 1.5px;
}
</style>
<body>
<script type="text/javascript" src="d3/d3.v3.min.js"></script>
<script>
var width = 300;
height = 500;
var cluster = d3.layout.cluster()
.size([height, width - 160]);
var diagonal = d3.svg.diagonal()
.projection(function(d) { return [d.y, d.x]; });
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(40,0)");
d3.json("ActionServlet", function(error, root) {
var nodes = cluster.nodes(root),
links = cluster.links(nodes);
var link = svg.selectAll(".link")
.data(links)
.enter().append("path")
.attr("class", "link")
.attr("d", diagonal);
var node = svg.selectAll(".node")
.data(nodes)
.enter().append("g")
.attr("class", "node")
.on("click", click)
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })
node.append("circle")
.attr("r", 4.5);
node.append("text")
.attr("dx", function(d) { return d.children ? -8 : 8; })
.attr("dy", 3)
.style("text-anchor", function(d) { return d.children ? "end" : "start"; })
.text(function(d) { return d.name; });
function click(d){
alert("This Number is: "+d.name);
}
});
d3.select(self.frameElement).style("height", height + "px");
</script>
I want the value in the ActionServlet which i am using to create a json.somebody please help.
Please change your click function with this-
function click(d){
var name=d.name;
$.ajax({
url: "ActionServlet",
type: "post",
data: { "root":name },
error:function(){
alert("error occured!!!");
},
success:function(d){
//alert(d.name);
}
});
}
});

Categories