Skip to content

Instantly share code, notes, and snippets.

@jpmarindiaz
Created September 11, 2013 17:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jpmarindiaz/6526775 to your computer and use it in GitHub Desktop.
Save jpmarindiaz/6526775 to your computer and use it in GitHub Desktop.
d3 force directed layout
{"description":"d3 force directed layout","endpoint":"","display":"svg","public":true,"require":[],"fileconfigs":{"inlet.js":{"default":true,"vim":false,"emacs":false,"fontSize":12},"data.js":{"default":true,"vim":false,"emacs":false,"fontSize":12},"_.md":{"default":true,"vim":false,"emacs":false,"fontSize":12},"config.json":{"default":true,"vim":false,"emacs":false,"fontSize":12},"style.css":{"default":true,"vim":false,"emacs":false,"fontSize":12},"data2.js":{"default":true,"vim":false,"emacs":false,"fontSize":12}},"fullscreen":false,"play":false,"loop":false,"restart":false,"autoinit":true,"pause":true,"loop_type":"pingpong","bv":false,"nclones":15,"clone_opacity":0.4,"duration":3000,"ease":"linear","dt":0.01,"thumbnail":"http://i.imgur.com/Y8ljKYy.png","inline-console":false}
graph = {
"nodes":[
{"name":"Myriel","group":0,"file":"file0.csv"},
{"name":"Napoleon","group":1,"file":"file1.csv"},
{"name":"Mlle.Baptistine","group":2,"file":"file2.csv"},
{"name":"Mme.Magloire","group":3,"file":"file3.csv"},
{"name":"CountessdeLo","group":4,"file":"file4.csv"},
{"name":"Geborand","group":5,"file":"file5.csv"},
{"name":"Grantaire","group":6,"file":"file6.csv"}
],
"links":[
{"source":1,"target":2,"value":1,"file":"file0.csv"},
{"source":2,"target":0,"value":8,"file":"file0.csv"},
{"source":3,"target":1,"value":10,"file":"file0.csv"},
{"source":3,"target":5,"value":6,"file":"file0.csv"},
{"source":4,"target":6,"value":1,"file":"file0.csv"},
{"source":5,"target":2,"value":1,"file":"file0.csv"},
{"source":4,"target":1,"value":1,"file":"file0.csv"},
{"source":5,"target":2,"value":1,"file":"file0.csv"},
{"source":6,"target":5,"value":1,"file":"file0.csv"}
]
}
var width = 560;
var height = 300;
var margin = 20;
var pad = margin / 2;
var color = d3.scale.category20();
// Generates a tooltip for a SVG circle element based on its ID
function addTooltip(circle) {
var x = parseFloat(circle.attr("cx"));
var y = parseFloat(circle.attr("cy"));
var r = parseFloat(circle.attr("r"));
var text = circle.attr("id");
var tooltip = d3.select("#plot")
.append("text")
.text(text)
.attr("x", x)
.attr("y", y)
.attr("dy", -r * 2)
.attr("id", "tooltip");
var offset = tooltip.node().getBBox().width / 2;
if ((x - offset) < 0) {
tooltip.attr("text-anchor", "start");
tooltip.attr("dx", -r);
}
else if ((x + offset) > (width - margin)) {
tooltip.attr("text-anchor", "end");
tooltip.attr("dx", r);
}
else {
tooltip.attr("text-anchor", "middle");
tooltip.attr("dx", 0);
}
}
function drawGraph(graph) {
var svg = d3.select("svg")
.attr("width", width)
.attr("height", height);
// draw plot background
svg.append("rect")
.attr("width", width)
.attr("height", height)
.style("fill", "#eeeeee");
// create an area within svg for plotting graph
var plot = svg.append("g")
.attr("id", "plot")
.attr("transform", "translate(" + pad + ", " + pad + ")");
// https://github.com/mbostock/d3/wiki/Force-Layout#wiki-force
var layout = d3.layout.force()
.size([width - margin, height - margin])
.charge(-120)
.linkDistance(function(d, i) {
return (d.source.group == d.target.group) ? 50 : 100;
})
.nodes(graph.nodes)
.links(graph.links)
.start();
drawLinks(graph.links);
drawNodes(graph.nodes);
// add ability to drag and update layout
// https://github.com/mbostock/d3/wiki/Force-Layout#wiki-drag
d3.selectAll(".node").call(layout.drag);
//Add info box
d3.select("#plot")
.append("g")
.classed("infobox",1);
d3.select(".infobox")
.append("rect")
.attr("x", 10)
.attr("y", 5)
.attr("rx", 5)
.attr("ry", 5)
.attr("height", 52)
.attr("width", 205);
d3.select(".infobox")
.append("a").append("text")
.text("click nodes to see info")
.attr("x", 15)
.attr("y", 36)
;
// Add click event
d3.selectAll(".node,.link")
.on("click", function(d,i) {
var d = this.__data__;
text = "Download data: " + d.file;
d3.selectAll(".infobox")
//.append("rect")
//.attr("x", 7)
//.attr("y", 5)
//.attr("height", 100)
//.attr("width", 200)
//.attr("id", "infobox")
//.select("text")
.select("a")
.attr("xlink:href", text)
.selectAll("text").text(text)
;
})
;
//Add hover behavior
svg.selectAll(".node,.link")
.on("mouseover", function() {
var sel = d3.select(this);
sel.classed("hovered",true);
addTooltip(sel);
})
.on("mouseout", function() {
var sel = d3.select(this);
sel.classed("hovered",false);
d3.select("#tooltip").remove();
})
// https://github.com/mbostock/d3/wiki/Force-Layout#wiki-on
layout.on("tick", function() {
d3.selectAll(".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; });
d3.selectAll(".node")
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
});
}
// Draws nodes on plot
function drawNodes(nodes) {
// used to assign nodes color by group
var color = d3.scale.category20();
// https://github.com/mbostock/d3/wiki/Force-Layout#wiki-nodes
d3.select("#plot").selectAll(".node")
.data(nodes)
.enter()
.append("circle")
.attr("class", "node")
.attr("id", function(d, i) { return d.name; })
.attr("cx", function(d, i) { return d.x; })
.attr("cy", function(d, i) { return d.y; })
.attr("r", function(d, i) { return 10; })
.style("fill", function(d, i) { return color(d.group); })
.on("mouseover", function(d, i) { addTooltip(d3.select(this)); })
.on("mouseout", function(d, i) { d3.select("#tooltip").remove(); });
}
// Draws edges between nodes
function drawLinks(links) {
var scale = d3.scale.linear()
.domain(d3.extent(links, function(d, i) {
return d.value;
}))
.range([1, 6]);
// https://github.com/mbostock/d3/wiki/Force-Layout#wiki-links
d3.select("#plot").selectAll(".link")
.data(links)
.enter()
.append("line")
.attr("class", "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; })
.style("stroke-width", function(d, i) {
return scale(d.value) + "px";
})
.style("stroke-dasharray", function(d, i) {
return (d.value <= 1) ? "2, 2" : "none";
});
}
drawGraph(graph);
//d3.json("miserables.json", drawGraph);
body {
font-family: 'Source Sans Pro', sans-serif;
font-weight: 300;
}
b {
font-weight: 900;
}
.outline {
fill: none;
stroke: #888888;
stroke-width: 1px;
}
#tooltip {
font-size: 10pt;
font-weight: 900;
fill: #000000;
stroke: #ffffff;
stroke-width: 0.25px;
}
.infobox rect{
opacity: .5;
fill: #F8D9D9;
stroke: #815959;
stroke-width: 0.25px;
}
.infobox text{
fill: #4E1313;
stroke: #815959;
stroke-width: 0.25px;
font-size:14px;
}
.node.hovered {
stroke:#E72E3D;
stroke-opacity: 1;
stroke-width:3
}
.link.hovered {
stroke:#E72E3D;
stroke-opacity: 1;
stroke-width:3
}
.node {
stroke: #ffffff;
stroke-weight: 1px;
}
.link {
fill: #797ED8;
stroke: #888888;
stroke-weight: 1px;
}
.highlight {
stroke: red;
stroke-weight: 4px;
stroke-opacity: 1.0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment