var canvas = document.getElementById("canvas");
var header = document.getElementById("header");
var height = window.innerHeight - 40 - header.clientHeight - header.offsetTop - header.offsetHeight;
canvas.style.height = height + 'px';
var community = jLouvain().nodes(node_data).edges(edge_data);
var comm_groups = community();
var G = new jsnx.Graph();
for (var i = 0; i < node_names.length; i++) {
G.addNodesFrom([node_names[i]], {
group: comm_groups[i],
label: node_names[i].substr(0, 4)
});
}
G.addEdgesFrom(edge_data_names);
var ebc = jsnx.edgeBetweennessCentrality(G);
//keep reference
G.ebc = ebc;
var color = d3.scale.category20();
jsnx.draw(G, {
element: '#canvas',
withLabels: true,
labels: 'label',
layoutAttr: {
//charge: -300,
charge: function(d){
return (-100) * d.weight;
},
linkDistance: 50
},
nodeAttr: {
r: 22,
title: function(d) {
return d.label;
}
},
nodeStyle: {
fill: function(d) {
return color(d.data.group);
},
stroke: 'none'
},
labelStyle: {
fill: 'white',
fontSize: '4pt'
},
edgeStyle: {
//fill: '#999'
fill: function(d) {
return '#999';
},
'stroke-width': function(d) {
//debugger;
var ebcVal = d.G.ebc._values[d.edge[0] + ',' + d.edge[1]];
return Math.floor(ebcVal * 100);
}
}
});
<body id="canvas">
<h1 id="header">Dolphin Community Detection - Louvain and Edge-Betweenness-Centrality</h1>
<script>
! function() {
jLouvain = function() {
function e(e) {
var t = {};
return e.forEach(function(e, n) {
t[e] = !0
}), Object.keys(t)
}
function t(e) {
var t = [];
for (var n in e) e.hasOwnProperty(n) && t.push(e[n]);
return t
}
function n(e, t) {
var n = e._assoc_mat[t] ? Object.keys(e._assoc_mat[t]) : [],
r = 0;
return n.forEach(function(n, o) {
var a = e._assoc_mat[t][n] || 1;
t === n && (a *= 2), r += a
}), r
}
function r(e, t) {
if ("undefined" == typeof e._assoc_mat[t]) return [];
var n = Object.keys(e._assoc_mat[t]);
return n
}
function o(e, t, n) {
return e._assoc_mat[t] ? e._assoc_mat[t][n] : void 0
}
function a(e) {
var t = 0;
return e.edges.forEach(function(e) {
t += e.weight
}), t
}
function s(e, t) {
i(e, t);
var n = e.edges.map(function(e) {
return e.source + "_" + e.target
}).indexOf(t.source + "_" + t.target); - 1 !== n ? e.edges[n].weight = t.weight : e.edges.push(t)
}
function c(e) {
var t = {};
return e.forEach(function(e, n) {
t[e.source] = t[e.source] || {}, t[e.source][e.target] = e.weight, t[e.target] = t[e.target] || {}, t[e.target][e.source] = e.weight
}), t
}
function i(e, t) {
e._assoc_mat[t.source] = e._assoc_mat[t.source] || {}, e._assoc_mat[t.source][t.target] = t.weight, e._assoc_mat[t.target] = e._assoc_mat[t.target] || {}, e._assoc_mat[t.target][t.source] = t.weight
}
function u(e) {
if (null === e || "object" != typeof e) return e;
var t = e.constructor();
for (var n in e) t[n] = u(e[n]);
return t
}
function f(e, t, s) {
t.nodes_to_com = {}, t.total_weight = 0, t.internals = {}, t.degrees = {}, t.gdegrees = {}, t.loops = {}, t.total_weight = a(e), "undefined" == typeof s ? e.nodes.forEach(function(r, a) {
t.nodes_to_com[r] = a;
var s = n(e, r);
if (0 > s) throw "Bad graph type, use positive weights!";
t.degrees[a] = s, t.gdegrees[r] = s, t.loops[r] = o(e, r, r) || 0, t.internals[a] = t.loops[r]
}) : e.nodes.forEach(function(o, a) {
var c = s[o];
t.nodes_to_com[o] = c;
var i = n(e, o);
t.degrees[c] = (t.degrees[c] || 0) + i, t.gdegrees[o] = i;
var u = 0,
f = r(e, o);
f.forEach(function(t, n) {
var r = e._assoc_mat[o][t];
if (0 >= r) throw "Bad graph type, use positive weights";
s[t] === c && (u += t === o ? r : r / 2)
}), t.internals[c] = (t.internals[c] || 0) + u
})
}
function g(n) {
var r = n.total_weight,
o = 0,
a = e(t(n.nodes_to_com));
return a.forEach(function(e, t) {
var a = n.internals[e] || 0,
s = n.degrees[e] || 0;
r > 0 && (o = o + a / r - Math.pow(s / (2 * r), 2))
}), o
}
function _(e, t, n) {
var o = {},
a = r(t, e);
return a.forEach(function(r, a) {
if (r !== e) {
var s = t._assoc_mat[e][r] || 1,
c = n.nodes_to_com[r];
o[c] = (o[c] || 0) + s
}
}), o
}
function d(e, t, n, r) {
r.nodes_to_com[e] = +t, r.degrees[t] = (r.degrees[t] || 0) + (r.gdegrees[e] || 0), r.internals[t] = (r.internals[t] || 0) + n + (r.loops[e] || 0)
}
function h(e, t, n, r) {
r.degrees[t] = (r.degrees[t] || 0) - (r.gdegrees[e] || 0), r.internals[t] = (r.internals[t] || 0) - n - (r.loops[e] || 0), r.nodes_to_com[e] = -1
}
function v(e) {
var t = 0,
n = u(e),
r = {},
o = Object.keys(e);
return o.forEach(function(o) {
var a = e[o],
s = "undefined" == typeof r[a] ? -1 : r[a]; - 1 === s && (r[a] = t, s = t, t += 1), n[o] = s
}), n
}
function m(e, t) {
for (var n = !0, r = 0, o = g(t), a = o; n && r !== j && (o = a, n = !1, r += 1, e.nodes.forEach(function(r, o) {
var a = t.nodes_to_com[r],
s = (t.gdegrees[r] || 0) / (2 * t.total_weight),
c = _(r, e, t);
h(r, a, c[a] || 0, t);
var i = a,
u = 0,
f = Object.keys(c);
f.forEach(function(e, n) {
var r = c[e] - (t.degrees[e] || 0) * s;
r > u && (u = r, i = e)
}), d(r, i, c[i] || 0, t), i !== a && (n = !0)
}), a = g(t), !(O > a - o)););
}
function l(n, r) {
var a, c, i = {
nodes: [],
edges: [],
_assoc_mat: {}
},
u = t(n);
return i.nodes = i.nodes.concat(e(u)), r.edges.forEach(function(e, t) {
c = e.weight || 1;
var r = n[e.source],
u = n[e.target];
a = o(i, r, u) || 0;
var f = a + c;
s(i, {
source: r,
target: u,
weight: f
})
}), i
}
function p(e, t) {
for (var n = u(e[0]), r = 1; t + 1 > r; r++) Object.keys(n).forEach(function(t, o) {
var a = t,
s = n[t];
n[a] = e[r][s]
});
return n
}
function w(e, t) {
if (0 === e.edges.length) {
var n = {};
return e.nodes.forEach(function(e, t) {
n[e] = e
}), n
}
var r = {};
f(k, r, t);
var o = g(r),
a = [];
m(k, r);
var s = g(r),
c = v(r.nodes_to_com);
a.push(c), o = s;
var i = l(c, k);
for (f(i, r);;) {
if (m(i, r), s = g(r), O > s - o) break;
c = v(r.nodes_to_com), a.push(c), o = s, i = l(c, i), f(i, r)
}
return a
}
var E, y, b, j = -1,
O = 1e-7,
k = {},
B = function() {
var e = w(k, b);
return p(e, e.length - 1)
};
return B.nodes = function(e) {
return arguments.length > 0 && (E = e), B
}, B.edges = function(e) {
if ("undefined" == typeof E) throw "Please provide the graph nodes first!";
if (arguments.length > 0) {
y = e;
var t = c(e);
k = {
nodes: E,
edges: y,
_assoc_mat: t
}
}
return B
}, B.partition_init = function(e) {
return arguments.length > 0 && (b = e), B
}, B
}
}();
//Original node and edge data
var node_data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61];
var edge_data = [{
"source": 8,
"target": 3,
"weight": 1
}, {
"source": 9,
"target": 5,
"weight": 1
}, {
"source": 9,
"target": 6,
"weight": 1
}, {
"source": 10,
"target": 0,
"weight": 1
}, {
"source": 10,
"target": 2,
"weight": 1
}, {
"source": 13,
"target": 5,
"weight": 1
}, {
"source": 13,
"target": 6,
"weight": 1
}, {
"source": 13,
"target": 9,
"weight": 1
}, {
"source": 14,
"target": 0,
"weight": 1
}, {
"source": 14,
"target": 3,
"weight": 1
}, {
"source": 15,
"target": 0,
"weight": 1
}, {
"source": 16,
"target": 14,
"weight": 1
}, {
"source": 17,
"target": 1,
"weight": 1
}, {
"source": 17,
"target": 6,
"weight": 1
}, {
"source": 17,
"target": 9,
"weight": 1
}, {
"source": 17,
"target": 13,
"weight": 1
}, {
"source": 18,
"target": 15,
"weight": 1
}, {
"source": 19,
"target": 1,
"weight": 1
}, {
"source": 19,
"target": 7,
"weight": 1
}, {
"source": 20,
"target": 8,
"weight": 1
}, {
"source": 20,
"target": 16,
"weight": 1
}, {
"source": 20,
"target": 18,
"weight": 1
}, {
"source": 21,
"target": 18,
"weight": 1
}, {
"source": 22,
"target": 17,
"weight": 1
}, {
"source": 24,
"target": 14,
"weight": 1
}, {
"source": 24,
"target": 15,
"weight": 1
}, {
"source": 24,
"target": 18,
"weight": 1
}, {
"source": 25,
"target": 17,
"weight": 1
}, {
"source": 26,
"target": 1,
"weight": 1
}, {
"source": 26,
"target": 25,
"weight": 1
}, {
"source": 27,
"target": 1,
"weight": 1
}, {
"source": 27,
"target": 7,
"weight": 1
}, {
"source": 27,
"target": 17,
"weight": 1
}, {
"source": 27,
"target": 25,
"weight": 1
}, {
"source": 27,
"target": 26,
"weight": 1
}, {
"source": 28,
"target": 1,
"weight": 1
}, {
"source": 28,
"target": 8,
"weight": 1
}, {
"source": 28,
"target": 20,
"weight": 1
}, {
"source": 29,
"target": 10,
"weight": 1
}, {
"source": 29,
"target": 18,
"weight": 1
}, {
"source": 29,
"target": 21,
"weight": 1
}, {
"source": 29,
"target": 24,
"weight": 1
}, {
"source": 30,
"target": 7,
"weight": 1
}, {
"source": 30,
"target": 19,
"weight": 1
}, {
"source": 30,
"target": 28,
"weight": 1
}, {
"source": 31,
"target": 17,
"weight": 1
}, {
"source": 32,
"target": 9,
"weight": 1
}, {
"source": 32,
"target": 13,
"weight": 1
}, {
"source": 33,
"target": 12,
"weight": 1
}, {
"source": 33,
"target": 14,
"weight": 1
}, {
"source": 33,
"target": 16,
"weight": 1
}, {
"source": 33,
"target": 21,
"weight": 1
}, {
"source": 34,
"target": 14,
"weight": 1
}, {
"source": 34,
"target": 33,
"weight": 1
}, {
"source": 35,
"target": 29,
"weight": 1
}, {
"source": 36,
"target": 1,
"weight": 1
}, {
"source": 36,
"target": 20,
"weight": 1
}, {
"source": 36,
"target": 23,
"weight": 1
}, {
"source": 37,
"target": 8,
"weight": 1
}, {
"source": 37,
"target": 14,
"weight": 1
}, {
"source": 37,
"target": 16,
"weight": 1
}, {
"source": 37,
"target": 21,
"weight": 1
}, {
"source": 37,
"target": 33,
"weight": 1
}, {
"source": 37,
"target": 34,
"weight": 1
}, {
"source": 37,
"target": 36,
"weight": 1
}, {
"source": 38,
"target": 14,
"weight": 1
}, {
"source": 38,
"target": 16,
"weight": 1
}, {
"source": 38,
"target": 20,
"weight": 1
}, {
"source": 38,
"target": 33,
"weight": 1
}, {
"source": 39,
"target": 36,
"weight": 1
}, {
"source": 40,
"target": 0,
"weight": 1
}, {
"source": 40,
"target": 7,
"weight": 1
}, {
"source": 40,
"target": 14,
"weight": 1
}, {
"source": 40,
"target": 15,
"weight": 1
}, {
"source": 40,
"target": 33,
"weight": 1
}, {
"source": 40,
"target": 36,
"weight": 1
}, {
"source": 40,
"target": 37,
"weight": 1
}, {
"source": 41,
"target": 1,
"weight": 1
}, {
"source": 41,
"target": 9,
"weight": 1
}, {
"source": 41,
"target": 13,
"weight": 1
}, {
"source": 42,
"target": 0,
"weight": 1
}, {
"source": 42,
"target": 2,
"weight": 1
}, {
"source": 42,
"target": 10,
"weight": 1
}, {
"source": 42,
"target": 30,
"weight": 1
}, {
"source": 43,
"target": 14,
"weight": 1
}, {
"source": 43,
"target": 29,
"weight": 1
}, {
"source": 43,
"target": 33,
"weight": 1
}, {
"source": 43,
"target": 37,
"weight": 1
}, {
"source": 43,
"target": 38,
"weight": 1
}, {
"source": 44,
"target": 2,
"weight": 1
}, {
"source": 44,
"target": 20,
"weight": 1
}, {
"source": 44,
"target": 34,
"weight": 1
}, {
"source": 44,
"target": 38,
"weight": 1
}, {
"source": 45,
"target": 8,
"weight": 1
}, {
"source": 45,
"target": 15,
"weight": 1
}, {
"source": 45,
"target": 18,
"weight": 1
}, {
"source": 45,
"target": 21,
"weight": 1
}, {
"source": 45,
"target": 23,
"weight": 1
}, {
"source": 45,
"target": 24,
"weight": 1
}, {
"source": 45,
"target": 29,
"weight": 1
}, {
"source": 45,
"target": 37,
"weight": 1
}, {
"source": 46,
"target": 43,
"weight": 1
}, {
"source": 47,
"target": 0,
"weight": 1
}, {
"source": 47,
"target": 10,
"weight": 1
}, {
"source": 47,
"target": 20,
"weight": 1
}, {
"source": 47,
"target": 28,
"weight": 1
}, {
"source": 47,
"target": 30,
"weight": 1
}, {
"source": 47,
"target": 42,
"weight": 1
}, {
"source": 49,
"target": 34,
"weight": 1
}, {
"source": 49,
"target": 46,
"weight": 1
}, {
"source": 50,
"target": 14,
"weight": 1
}, {
"source": 50,
"target": 16,
"weight": 1
}, {
"source": 50,
"target": 20,
"weight": 1
}, {
"source": 50,
"target": 33,
"weight": 1
}, {
"source": 50,
"target": 42,
"weight": 1
}, {
"source": 50,
"target": 45,
"weight": 1
}, {
"source": 51,
"target": 4,
"weight": 1
}, {
"source": 51,
"target": 11,
"weight": 1
}, {
"source": 51,
"target": 18,
"weight": 1
}, {
"source": 51,
"target": 21,
"weight": 1
}, {
"source": 51,
"target": 23,
"weight": 1
}, {
"source": 51,
"target": 24,
"weight": 1
}, {
"source": 51,
"target": 29,
"weight": 1
}, {
"source": 51,
"target": 45,
"weight": 1
}, {
"source": 51,
"target": 50,
"weight": 1
}, {
"source": 52,
"target": 14,
"weight": 1
}, {
"source": 52,
"target": 29,
"weight": 1
}, {
"source": 52,
"target": 38,
"weight": 1
}, {
"source": 52,
"target": 40,
"weight": 1
}, {
"source": 53,
"target": 43,
"weight": 1
}, {
"source": 54,
"target": 1,
"weight": 1
}, {
"source": 54,
"target": 6,
"weight": 1
}, {
"source": 54,
"target": 7,
"weight": 1
}, {
"source": 54,
"target": 13,
"weight": 1
}, {
"source": 54,
"target": 19,
"weight": 1
}, {
"source": 54,
"target": 41,
"weight": 1
}, {
"source": 55,
"target": 15,
"weight": 1
}, {
"source": 55,
"target": 51,
"weight": 1
}, {
"source": 56,
"target": 5,
"weight": 1
}, {
"source": 56,
"target": 6,
"weight": 1
}, {
"source": 57,
"target": 5,
"weight": 1
}, {
"source": 57,
"target": 6,
"weight": 1
}, {
"source": 57,
"target": 9,
"weight": 1
}, {
"source": 57,
"target": 13,
"weight": 1
}, {
"source": 57,
"target": 17,
"weight": 1
}, {
"source": 57,
"target": 39,
"weight": 1
}, {
"source": 57,
"target": 41,
"weight": 1
}, {
"source": 57,
"target": 48,
"weight": 1
}, {
"source": 57,
"target": 54,
"weight": 1
}, {
"source": 58,
"target": 38,
"weight": 1
}, {
"source": 59,
"target": 3,
"weight": 1
}, {
"source": 59,
"target": 8,
"weight": 1
}, {
"source": 59,
"target": 15,
"weight": 1
}, {
"source": 59,
"target": 36,
"weight": 1
}, {
"source": 59,
"target": 45,
"weight": 1
}, {
"source": 60,
"target": 32,
"weight": 1
}, {
"source": 61,
"target": 2,
"weight": 1
}, {
"source": 61,
"target": 37,
"weight": 1
}, {
"source": 61,
"target": 53,
"weight": 1
}];
var node_names = ["Beak", "Beescratch", "Bumper", "CCL", "Cross", "DN16", "DN21", "DN63", "Double", "Feather", "Fish", "Five", "Fork", "Gallatin", "Grin", "Haecksel", "Hook", "Jet", "Jonah", "Knit", "Kringel", "MN105", "MN23", "MN60", "MN83", "Mus", "Notch", "Number1", "Oscar", "Patchback", "PL", "Quasi", "Ripplefluke", "Scabs", "Shmuddel", "SMN5", "SN100", "SN4", "SN63", "SN89", "SN9", "SN90", "SN96", "Stripes", "Thumper", "Topless", "TR120", "TR77", "TR82", "TR88", "TR99", "Trigger", "TSN103", "TSN83", "Upbang", "Vau", "Wave", "Web", "Whitetip", "Zap", "Zig", "Zipfel"];
var edge_data_names = [
["Double", "CCL"],
["Feather", "DN16"],
["Feather", "DN21"],
["Fish", "Beak"],
["Fish", "Bumper"],
["Gallatin", "DN16"],
["Gallatin", "DN21"],
["Gallatin", "Feather"],
["Grin", "Beak"],
["Grin", "CCL"],
["Haecksel", "Beak"],
["Hook", "Grin"],
["Jet", "Beescratch"],
["Jet", "DN21"],
["Jet", "Feather"],
["Jet", "Gallatin"],
["Jonah", "Haecksel"],
["Knit", "Beescratch"],
["Knit", "DN63"],
["Kringel", "Double"],
["Kringel", "Hook"],
["Kringel", "Jonah"],
["MN105", "Jonah"],
["MN23", "Jet"],
["MN83", "Grin"],
["MN83", "Haecksel"],
["MN83", "Jonah"],
["Mus", "Jet"],
["Notch", "Beescratch"],
["Notch", "Mus"],
["Number1", "Beescratch"],
["Number1", "DN63"],
["Number1", "Jet"],
["Number1", "Mus"],
["Number1", "Notch"],
["Oscar", "Beescratch"],
["Oscar", "Double"],
["Oscar", "Kringel"],
["Patchback", "Fish"],
["Patchback", "Jonah"],
["Patchback", "MN105"],
["Patchback", "MN83"],
["PL", "DN63"],
["PL", "Knit"],
["PL", "Oscar"],
["Quasi", "Jet"],
["Ripplefluke", "Feather"],
["Ripplefluke", "Gallatin"],
["Scabs", "Fork"],
["Scabs", "Grin"],
["Scabs", "Hook"],
["Scabs", "MN105"],
["Shmuddel", "Grin"],
["Shmuddel", "Scabs"],
["SMN5", "Patchback"],
["SN100", "Beescratch"],
["SN100", "Kringel"],
["SN100", "MN60"],
["SN4", "Double"],
["SN4", "Grin"],
["SN4", "Hook"],
["SN4", "MN105"],
["SN4", "Scabs"],
["SN4", "Shmuddel"],
["SN4", "SN100"],
["SN63", "Grin"],
["SN63", "Hook"],
["SN63", "Kringel"],
["SN63", "Scabs"],
["SN89", "SN100"],
["SN9", "Beak"],
["SN9", "DN63"],
["SN9", "Grin"],
["SN9", "Haecksel"],
["SN9", "Scabs"],
["SN9", "SN100"],
["SN9", "SN4"],
["SN90", "Beescratch"],
["SN90", "Feather"],
["SN90", "Gallatin"],
["SN96", "Beak"],
["SN96", "Bumper"],
["SN96", "Fish"],
["SN96", "PL"],
["Stripes", "Grin"],
["Stripes", "Patchback"],
["Stripes", "Scabs"],
["Stripes", "SN4"],
["Stripes", "SN63"],
["Thumper", "Bumper"],
["Thumper", "Kringel"],
["Thumper", "Shmuddel"],
["Thumper", "SN63"],
["Topless", "Double"],
["Topless", "Haecksel"],
["Topless", "Jonah"],
["Topless", "MN105"],
["Topless", "MN60"],
["Topless", "MN83"],
["Topless", "Patchback"],
["Topless", "SN4"],
["TR120", "Stripes"],
["TR77", "Beak"],
["TR77", "Fish"],
["TR77", "Kringel"],
["TR77", "Oscar"],
["TR77", "PL"],
["TR77", "SN96"],
["TR88", "Shmuddel"],
["TR88", "TR120"],
["TR99", "Grin"],
["TR99", "Hook"],
["TR99", "Kringel"],
["TR99", "Scabs"],
["TR99", "SN96"],
["TR99", "Topless"],
["Trigger", "Cross"],
["Trigger", "Five"],
["Trigger", "Jonah"],
["Trigger", "MN105"],
["Trigger", "MN60"],
["Trigger", "MN83"],
["Trigger", "Patchback"],
["Trigger", "Topless"],
["Trigger", "TR99"],
["TSN103", "Grin"],
["TSN103", "Patchback"],
["TSN103", "SN63"],
["TSN103", "SN9"],
["TSN83", "Stripes"],
["Upbang", "Beescratch"],
["Upbang", "DN21"],
["Upbang", "DN63"],
["Upbang", "Gallatin"],
["Upbang", "Knit"],
["Upbang", "SN90"],
["Vau", "Haecksel"],
["Vau", "Trigger"],
["Wave", "DN16"],
["Wave", "DN21"],
["Web", "DN16"],
["Web", "DN21"],
["Web", "Feather"],
["Web", "Gallatin"],
["Web", "Jet"],
["Web", "SN89"],
["Web", "SN90"],
["Web", "TR82"],
["Web", "Upbang"],
["Whitetip", "SN63"],
["Zap", "CCL"],
["Zap", "Double"],
["Zap", "Haecksel"],
["Zap", "SN100"],
["Zap", "Topless"],
["Zig", "Ripplefluke"],
["Zipfel", "Bumper"],
["Zipfel", "SN4"],
["Zipfel", "TSN83"]
];
</script>
</body>
#canvas {
/*height: 700px;*/
}
svg {
border: solid 1px black;
}
body{
font-family: 'calibri';
}
h1{
text-align: center;
}
External resources loaded into this fiddle: