Skip to content

Instantly share code, notes, and snippets.

@micahstubbs
Last active March 9, 2017 06:16
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 micahstubbs/bb8a7dd10eb6b2a05db14a52ff228bdf to your computer and use it in GitHub Desktop.
Save micahstubbs/bb8a7dd10eb6b2a05db14a52ff228bdf to your computer and use it in GitHub Desktop.
clustered force layout, static data
license: MIT
border: no
{
"nodes": [
{
"cluster": 9,
"r": 9.259670255973901
},
{
"cluster": 7,
"r": 8.909499905215805
},
{
"cluster": 6,
"r": 13.111974353489249
},
{
"cluster": 8,
"r": 11.373085883848557
},
{
"cluster": 2,
"r": 0.813474563335458
},
{
"cluster": 3,
"r": 4.341946600458814
},
{
"cluster": 2,
"r": 6.667333434466238
},
{
"cluster": 9,
"r": 7.911498350320349
},
{
"cluster": 0,
"r": 4.597604124486907
},
{
"cluster": 6,
"r": 4.340571868290901
},
{
"cluster": 5,
"r": 3.5878606980553065
},
{
"cluster": 0,
"r": 0.3818599744977188
},
{
"cluster": 6,
"r": 6.874201213903172
},
{
"cluster": 7,
"r": 11.988881995045055
},
{
"cluster": 0,
"r": 0.7375641615588722
},
{
"cluster": 1,
"r": 3.83142426518969
},
{
"cluster": 5,
"r": 2.7302570653623466
},
{
"cluster": 7,
"r": 2.1650055752224318
},
{
"cluster": 7,
"r": 3.7860658129035656
},
{
"cluster": 4,
"r": 16.962609275339474
},
{
"cluster": 2,
"r": 7.397340156592428
},
{
"cluster": 2,
"r": 6.999531169611245
},
{
"cluster": 6,
"r": 13.019894090019307
},
{
"cluster": 0,
"r": 4.046616197852555
},
{
"cluster": 8,
"r": 3.225328780272923
},
{
"cluster": 8,
"r": 6.087740584733343
},
{
"cluster": 8,
"r": 14.425967477661167
},
{
"cluster": 8,
"r": 3.34470377759449
},
{
"cluster": 1,
"r": 4.293510114124356
},
{
"cluster": 7,
"r": 11.914055313583855
},
{
"cluster": 2,
"r": 3.6810638302844323
},
{
"cluster": 9,
"r": 13.045300117867052
},
{
"cluster": 0,
"r": 1.9679969981361989
},
{
"cluster": 4,
"r": 6.002836962375587
},
{
"cluster": 5,
"r": 5.44559457861006
},
{
"cluster": 3,
"r": 7.112859827105364
},
{
"cluster": 2,
"r": 3.8631945337911615
},
{
"cluster": 5,
"r": 9.808344270855102
},
{
"cluster": 8,
"r": 8.786242195775312
},
{
"cluster": 2,
"r": 2.4304680551459286
},
{
"cluster": 8,
"r": 7.690584140956325
},
{
"cluster": 1,
"r": 3.8063210378920243
},
{
"cluster": 5,
"r": 7.604382514568928
},
{
"cluster": 9,
"r": 17.434628390107957
},
{
"cluster": 0,
"r": 1.6252513672061384
},
{
"cluster": 2,
"r": 7.331808927318587
},
{
"cluster": 4,
"r": 8.116763401587676
},
{
"cluster": 6,
"r": 6.903091426770327
},
{
"cluster": 3,
"r": 8.962587526121954
},
{
"cluster": 4,
"r": 5.087408184352244
},
{
"cluster": 7,
"r": 11.451560642415068
},
{
"cluster": 3,
"r": 11.261865276144224
},
{
"cluster": 8,
"r": 3.7619998884007604
},
{
"cluster": 4,
"r": 5.852465067502188
},
{
"cluster": 3,
"r": 2.2988242179838516
},
{
"cluster": 4,
"r": 19.169514948665487
},
{
"cluster": 9,
"r": 5.862770330322363
},
{
"cluster": 2,
"r": 9.351640223353849
},
{
"cluster": 9,
"r": 10.430131136161929
},
{
"cluster": 7,
"r": 5.289130100573111
},
{
"cluster": 0,
"r": 2.1931576543536737
},
{
"cluster": 8,
"r": 7.344952622197862
},
{
"cluster": 3,
"r": 6.362549353826214
},
{
"cluster": 0,
"r": 5.912921938589746
},
{
"cluster": 5,
"r": 5.84701314380495
},
{
"cluster": 5,
"r": 17.53188903716625
},
{
"cluster": 8,
"r": 16.454719754871196
},
{
"cluster": 1,
"r": 2.0967313521660165
},
{
"cluster": 8,
"r": 22.665073351721833
},
{
"cluster": 0,
"r": 2.3953220941716147
},
{
"cluster": 8,
"r": 17.398089063400704
},
{
"cluster": 2,
"r": 4.489631238988284
},
{
"cluster": 1,
"r": 1.5550861469241708
},
{
"cluster": 7,
"r": 6.828176179631646
},
{
"cluster": 5,
"r": 1.3949983557808792
},
{
"cluster": 7,
"r": 18.15519976143089
},
{
"cluster": 4,
"r": 10.777944013818828
},
{
"cluster": 4,
"r": 5.727158717707772
},
{
"cluster": 7,
"r": 15.263980953990075
},
{
"cluster": 0,
"r": 4.140056876451165
},
{
"cluster": 3,
"r": 11.809815703272445
},
{
"cluster": 3,
"r": 7.625769247350361
},
{
"cluster": 8,
"r": 11.670369407548918
},
{
"cluster": 3,
"r": 2.864976753122453
},
{
"cluster": 1,
"r": 5.782808182124143
},
{
"cluster": 9,
"r": 20.27296671509774
},
{
"cluster": 8,
"r": 7.424973928831013
},
{
"cluster": 4,
"r": 11.477056172978916
},
{
"cluster": 7,
"r": 13.072068416142244
},
{
"cluster": 1,
"r": 1.312838094842473
},
{
"cluster": 3,
"r": 8.5523149371797
},
{
"cluster": 2,
"r": 5.241904021515078
},
{
"cluster": 3,
"r": 11.448925815920003
},
{
"cluster": 0,
"r": 4.609895492082293
},
{
"cluster": 9,
"r": 8.588913842173824
},
{
"cluster": 1,
"r": 5.496249454373348
},
{
"cluster": 4,
"r": 4.9553056846580485
},
{
"cluster": 2,
"r": 6.951273479651984
},
{
"cluster": 9,
"r": 5.759588486541276
},
{
"cluster": 5,
"r": 0.8585655746100416
},
{
"cluster": 8,
"r": 5.4857925910781855
},
{
"cluster": 4,
"r": 9.036566271337456
},
{
"cluster": 5,
"r": 2.9200903345628006
},
{
"cluster": 6,
"r": 9.381396697639099
},
{
"cluster": 3,
"r": 6.095422235806083
},
{
"cluster": 7,
"r": 9.690503428977397
},
{
"cluster": 3,
"r": 6.006485216173571
},
{
"cluster": 3,
"r": 8.76405182817216
},
{
"cluster": 5,
"r": 0.4808168518632294
},
{
"cluster": 2,
"r": 11.450886171521642
},
{
"cluster": 6,
"r": 6.071099103644298
},
{
"cluster": 1,
"r": 6.034605011868475
},
{
"cluster": 7,
"r": 3.640626110465396
},
{
"cluster": 5,
"r": 6.129561103598028
},
{
"cluster": 9,
"r": 5.4690797797471316
},
{
"cluster": 1,
"r": 1.288352602570954
},
{
"cluster": 1,
"r": 4.503481956678496
},
{
"cluster": 0,
"r": 4.968285461344784
},
{
"cluster": 5,
"r": 4.869913292532537
},
{
"cluster": 8,
"r": 19.035513800218055
},
{
"cluster": 2,
"r": 5.1820315591317065
},
{
"cluster": 7,
"r": 18.328291456381145
},
{
"cluster": 8,
"r": 6.4765003613544705
},
{
"cluster": 6,
"r": 9.75904707313678
},
{
"cluster": 3,
"r": 4.071578675034565
},
{
"cluster": 4,
"r": 13.194936050984108
},
{
"cluster": 0,
"r": 4.155648062659441
},
{
"cluster": 0,
"r": 1.0802805219045832
},
{
"cluster": 9,
"r": 23.053981988652996
},
{
"cluster": 5,
"r": 2.463089780679736
},
{
"cluster": 1,
"r": 5.132590626539599
},
{
"cluster": 7,
"r": 6.93572766107949
},
{
"cluster": 0,
"r": 3.4720879272197287
},
{
"cluster": 9,
"r": 15.877291057948877
},
{
"cluster": 9,
"r": 14.134502338886765
},
{
"cluster": 1,
"r": 4.545784293988218
},
{
"cluster": 2,
"r": 9.317274725878152
},
{
"cluster": 8,
"r": 12.123802063260968
},
{
"cluster": 0,
"r": 5.321990904712712
},
{
"cluster": 3,
"r": 1.4041552057405893
},
{
"cluster": 4,
"r": 9.920924102977988
},
{
"cluster": 5,
"r": 5.478774195361606
},
{
"cluster": 9,
"r": 9.526789295392865
},
{
"cluster": 4,
"r": 6.518980383115273
},
{
"cluster": 9,
"r": 14.995010382404313
},
{
"cluster": 9,
"r": 16.642003223956607
},
{
"cluster": 5,
"r": 4.114844420766859
},
{
"cluster": 7,
"r": 0.49892292359509965
},
{
"cluster": 3,
"r": 6.275627467950188
},
{
"cluster": 3,
"r": 9.81168599309813
},
{
"cluster": 6,
"r": 12.64377750017487
},
{
"cluster": 3,
"r": 12.797889781218368
},
{
"cluster": 4,
"r": 7.618020914702662
},
{
"cluster": 5,
"r": 10.731774476576987
},
{
"cluster": 5,
"r": 9.716585571655193
},
{
"cluster": 6,
"r": 18.565683428845595
},
{
"cluster": 6,
"r": 3.8217862145573287
},
{
"cluster": 3,
"r": 3.8588917727479473
},
{
"cluster": 8,
"r": 4.4774999074563855
},
{
"cluster": 3,
"r": 4.318195408619502
},
{
"cluster": 2,
"r": 6.328501633198946
},
{
"cluster": 1,
"r": 4.094078339502131
},
{
"cluster": 3,
"r": 3.8588240066751505
},
{
"cluster": 1,
"r": 4.004632383005384
},
{
"cluster": 6,
"r": 13.881526898543534
},
{
"cluster": 4,
"r": 12.506719650183388
},
{
"cluster": 4,
"r": 0.487449443958749
},
{
"cluster": 3,
"r": 2.993864029861696
},
{
"cluster": 1,
"r": 3.4358535790337443
},
{
"cluster": 9,
"r": 11.61416030506196
},
{
"cluster": 6,
"r": 13.775399779244715
},
{
"cluster": 8,
"r": 7.873977390020491
},
{
"cluster": 1,
"r": 3.097979808541668
},
{
"cluster": 8,
"r": 9.31232564478648
},
{
"cluster": 6,
"r": 11.940072218061433
},
{
"cluster": 0,
"r": 4.10117521077354
},
{
"cluster": 7,
"r": 10.51899397149345
},
{
"cluster": 8,
"r": 8.865336255450714
},
{
"cluster": 6,
"r": 6.963356353488244
},
{
"cluster": 5,
"r": 2.4384432695021627
},
{
"cluster": 4,
"r": 7.6272270137507245
},
{
"cluster": 1,
"r": 1.1509093147707856
},
{
"cluster": 3,
"r": 11.79628492531506
},
{
"cluster": 1,
"r": 9.39586561627845
},
{
"cluster": 8,
"r": 5.451120564138922
},
{
"cluster": 9,
"r": 25.661014262625976
},
{
"cluster": 5,
"r": 16.70431528730784
},
{
"cluster": 8,
"r": 5.789847734049817
},
{
"cluster": 3,
"r": 7.967538691580401
},
{
"cluster": 6,
"r": 16.50366405247469
},
{
"cluster": 2,
"r": 8.28219564420553
},
{
"cluster": 3,
"r": 8.152748149145362
},
{
"cluster": 8,
"r": 5.220993365370065
},
{
"cluster": 5,
"r": 7.2993278654242815
},
{
"cluster": 4,
"r": 7.2263395643139
},
{
"cluster": 2,
"r": 12.25015185685546
},
{
"cluster": 4,
"r": 1.6578362894228034
},
{
"cluster": 1,
"r": 4.094982685322045
},
{
"cluster": 6,
"r": 13.592577795980258
},
{
"cluster": 6,
"r": 7.6784326664344835
}
],
"links": []
}
<!doctype html>
<meta charset='utf-8'>
<body>
<script src='//d3js.org/d3.v4.min.js'></script>
<script src='vis.js'></script>
/* global d3 */
d3.json('graph.json', (error, graph) => {
const nodes = graph.nodes;
console.log('nodes', nodes);
const margin = { top: 100, right: 100, bottom: 100, left: 100 };
const width = 960;
const height = 500;
// separation between same-color circles
const padding = 1.5;
// separation between different-color circles
const clusterPadding = 6;
const maxRadius = 12;
const z = d3.scaleOrdinal(d3.schemeCategory20);
// total number of nodes
const n = nodes.length;
// collect clusters from nodes
const clusters = {};
nodes.forEach((node) => {
const radius = node.r;
const clusterID = node.cluster;
if (!clusters[clusterID] || (radius > clusters[clusterID].r)) {
clusters[clusterID] = node;
}
});
console.log('clusters', clusters);
const svg = d3.select('body')
.append('svg')
.attr('height', height)
.attr('width', width)
.append('g')
.attr('transform', `translate(${width / 2},${height / 2})`);
const circles = svg.append('g')
.datum(nodes)
.selectAll('.circle')
.data(d => d)
.enter().append('circle')
.attr('r', d => d.r)
.attr('fill', d => z(d.cluster))
.attr('stroke', 'black')
.attr('stroke-width', 1);
const simulation = d3.forceSimulation(nodes)
.velocityDecay(0.2)
.force('x', d3.forceX().strength(0.0005))
.force('y', d3.forceY().strength(0.0005))
.force('collide', collide)
.force('cluster', clustering)
.on('tick', ticked);
function ticked() {
circles
.attr('cx', d => d.x)
.attr('cy', d => d.y);
}
// These are implementations of the custom forces
function clustering(alpha) {
nodes.forEach((d) => {
const cluster = clusters[d.cluster];
if (cluster === d) return;
let x = d.x - cluster.x;
let y = d.y - cluster.y;
let l = Math.sqrt((x * x) + (y * y));
const r = d.r + cluster.r;
if (l !== r) {
l = ((l - r) / l) * alpha;
d.x -= x *= l;
d.y -= y *= l;
cluster.x += x;
cluster.y += y;
}
});
}
function collide(alpha) {
const quadtree = d3.quadtree()
.x(d => d.x)
.y(d => d.y)
.addAll(nodes);
nodes.forEach((d) => {
const r = d.r + maxRadius + Math.max(padding, clusterPadding);
const nx1 = d.x - r;
const nx2 = d.x + r;
const ny1 = d.y - r;
const ny2 = d.y + r;
quadtree.visit((quad, x1, y1, x2, y2) => {
if (quad.data && (quad.data !== d)) {
let x = d.x - quad.data.x;
let y = d.y - quad.data.y;
let l = Math.sqrt((x * x) + (y * y));
const r = d.r + quad.data.r + (d.cluster === quad.data.cluster ? padding : clusterPadding);
if (l < r) {
l = ((l - r) / l) * alpha;
d.x -= x *= l;
d.y -= y *= l;
quad.data.x += x;
quad.data.y += y;
}
}
return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
});
});
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment