Skip to content

Instantly share code, notes, and snippets.

@aberner
Forked from mbostock/.block
Last active May 3, 2017 13:05
Show Gist options
  • Select an option

  • Save aberner/ce5103d43cfa6cd516f5dd7d434a291f to your computer and use it in GitHub Desktop.

Select an option

Save aberner/ce5103d43cfa6cd516f5dd7d434a291f to your computer and use it in GitHub Desktop.
Force-Directed Graph
license: gpl-3.0
height: 600

This simple force-directed graph shows character co-occurence in Les Misérables. A physical simulation of charged particles and springs places related characters in closer proximity, while unrelated characters are farther apart. Layout algorithm inspired by Tim Dwyer and Thomas Jakobsen. Data based on character coappearence in Victor Hugo's Les Misérables, compiled by Donald Knuth.

Compare this display to a force layout with curved links, a force layout with fisheye distortion and a matrix diagram.

<!DOCTYPE html>
<meta charset="utf-8">
<style>
.links line {
stroke: #999;
stroke-opacity: 0.6;
}
.nodes circle {
stroke: #fff;
stroke-width: 1.5px;
}
</style>
<svg width="960" height="600"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");
var color = d3.scaleOrdinal(d3.schemeCategory20);
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d) { return d.id; }))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2));
d3.json("miserables.json", function(error, graph) {
if (error) throw error;
var link = svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(graph.links)
.enter().append("line")
.attr("stroke-width", function(d) { return Math.sqrt(d.value); });
var node = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(graph.nodes)
.enter().append("circle")
.attr("r", 5)
.attr("fill", function(d) { return color(d.group); })
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
node.append("title")
.text(function(d) { return d.id; });
simulation
.nodes(graph.nodes)
.on("tick", ticked);
simulation.force("link")
.links(graph.links);
function ticked() {
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; });
}
});
function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
</script>
{
"nodes": [
{"id": "Kommune", "group": 1},
{"id": "Statlig virksomhet", "group": 1},
{"id": "Fylkeskommune", "group": 1},
{"id": "Kommunesamarbeid", "group": 1},
{"id": "Privat virksomhet", "group": 2},
{"id": "Innbygger", "group": 2},
{"id": "Digital postkasse for innbyggere", "group": 3},
{"id": "Altinn", "group": 3},
{"id": "KS Fiks", "group": 3}
],
"links": [
{"source": "Kommune", "target": "Innbygger", "value": 1},
{"source": "Kommune", "target": "Statlig virksomhet", "value": 2},
{"source": "Kommune", "target": "Fylkeskommune", "value": 3},
{"source": "Kommune", "target": "Kommunesamarbeid", "value": 4},
{"source": "Kommune", "target": "Privat virksomhet", "value": 5},
{"source": "Kommune", "target": "KS Fiks", "value": 6},
{"source": "Statlig virksomhet", "target": "Innbygger", "value": 7},
{"source": "Statlig virksomhet", "target": "Digital postkasse for innbyggere", "value": 1},
{"source": "Statlig virksomhet", "target": "Kommune", "value": 1},
{"source": "Statlig virksomhet", "target": "Statlig virksomhet", "value": 1},
{"source": "Statlig virksomhet", "target": "Fylkeskommune", "value": 1},
{"source": "Statlig virksomhet", "target": "Kommunesamarbeid", "value": 7},
{"source": "Statlig virksomhet", "target": "Privat virksomhet", "value": 1},
{"source": "Statlig virksomhet", "target": "Altinn", "value": 1},
{"source": "Privat virksomhet", "target": "Innbygger", "value": 1},
{"source": "Innbygger", "target": "Innbygger", "value": 1},
{"source": "Digital postkasse for innbyggere", "target": "Innbygger", "value": 1},
{"source": "Altinn", "target": "Innbygger", "value": 1},
{"source": "Privat virksomhet", "target": "Digital postkasse for innbyggere", "value": 1},
{"source": "Statlig virksomhet", "target": "Altinn", "value": 1}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment