Modifyied @mbostock Blocks Graph to use my ForceInABox Library that distributes the nodes on the screen first by users and then by clusters computed with netClustering.
Original readme:
This shows the force-directed network of mentions in the READMEs of various bl.ocks. I cleaned Micah Stubb’s data from May 2016 slightly: I removed missing nodes, solitary nodes, self-links, and redundant links. The original dataset contains 2,101 nodes and 8,617 links, and is 1.2 MB. The cleaned dataset contains 1,238 nodes and 2,602 links, and is 281 KB.
forked from mbostock's block: Blocks Graph
xxxxxxxxxx
<meta charset="utf-8">
<h3 id="title">Original Block</h3>
<a target="_blank" style="outline:none;"><canvas width="960" height="960"></canvas></a>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/gh/john-guerra/forceinabox/3bc1242b/forceinabox.js"></script>
<script src="https://johnguerra.co/viz/netclustering.js"></script>
<script>
var canvas = document.querySelector("canvas"),
context = canvas.getContext("2d"),
width = canvas.width,
height = canvas.height,
searchRadius = 40;
var color = d3.scaleOrdinal()
.range(d3.schemeCategory20);
var simulation = d3.forceSimulation()
.force("charge", d3.forceManyBody().strength(-20))
.force("link", d3.forceLink().iterations(4).id(function(d) { return d.id; }))
.force("x", d3.forceX())
.force("y", d3.forceY());
d3.json("graph.json", function(error, graph) {
if (error) throw error;
var users = d3.nest()
.key(function(d) { return d.user; })
.entries(graph.nodes)
.sort(function(a, b) { return b.values.length - a.values.length; });
color.domain(users.map(function(d) { return d.key; }));
var groupingForce = forceInABox()
.groupBy("user")
.links(graph.links)
.template("treemap") // Try "force" too
.linkStrengthInterCluster(0.01)
.size([width,height])
.offset([width/2,height/2])
.nodeSize(0.1)
.forceCharge(-20)
.strength(0.5);
simulation
.nodes(graph.nodes)
.on("tick", ticked);
simulation.force("link")
.links(graph.links)
.strength(groupingForce.getLinkStrength);
setTimeout(function() {
simulation.force("group",
groupingForce);
d3.select("#title").text("forceInABox by User");
setTimeout(function() {
simulation.stop()
// **** Try it with clustering
netClustering.cluster(graph.nodes, graph.links);
groupingForce.groupBy("cluster").template("treemap");
simulation.alphaTarget(0.9).restart();
d3.select("#title").text("Now forceInABox by cluster");
// **** change colors to clusters if you want
// users = d3.nest()
// .key(function(d) { return d.cluster; })
// .entries(graph.nodes)
// .sort(function(a, b) { return b.values.length - a.values.length; });
// color.domain(users.map(function(d) { return d.key; }));
// ********
}, 3000);
}, 3000);
d3.select(canvas)
.on("mousemove", mousemoved)
.call(d3.drag()
.container(canvas)
.subject(dragsubject)
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
function ticked() {
context.clearRect(0, 0, width, height);
context.save();
context.translate(width / 2, height / 2);
context.beginPath();
graph.links.forEach(drawLink);
context.strokeStyle = "#aaa";
context.stroke();
users.forEach(function(user) {
context.beginPath();
user.values.forEach(drawNode);
context.fillStyle = color(user.key);
context.fill();
});
context.restore();
}
function dragsubject() {
return simulation.find(d3.event.x - width / 2, d3.event.y - height / 2, searchRadius);
}
function mousemoved() {
var a = this.parentNode, m = d3.mouse(this), d = simulation.find(m[0] - width / 2, m[1] - height / 2, searchRadius);
if (!d) return a.removeAttribute("href"), a.removeAttribute("title");
a.setAttribute("href", "https://bl.ocks.org/" + (d.user ? d.user + "/" : "") + d.id);
a.setAttribute("title", d.id + (d.user ? " by " + d.user : "") + (d.description ? "\n" + d.description : ""));
}
});
function dragstarted() {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d3.event.subject.fx = d3.event.subject.x;
d3.event.subject.fy = d3.event.subject.y;
}
function dragged() {
d3.event.subject.fx = d3.event.x;
d3.event.subject.fy = d3.event.y;
}
function dragended() {
if (!d3.event.active) simulation.alphaTarget(0);
d3.event.subject.fx = null;
d3.event.subject.fy = null;
}
function drawLink(d) {
context.moveTo(d.source.x, d.source.y);
context.lineTo(d.target.x, d.target.y);
}
function drawNode(d) {
context.moveTo(d.x + 3, d.y);
context.arc(d.x, d.y, 3, 0, 2 * Math.PI);
}
</script>
Updated missing url https://cdn.rawgit.com/john-guerra/forceInABox/3bc1242b/forceInABox.js to https://cdn.jsdelivr.net/gh/john-guerra/forceinabox/3bc1242b/forceinabox.js
Modified http://johnguerra.co/viz/netClustering.js to a secure url
https://d3js.org/d3.v4.min.js
https://cdn.rawgit.com/john-guerra/forceInABox/3bc1242b/forceInABox.js
https://johnguerra.co/viz/netClustering.js