a small iteration on @vastur‘s block 3D Force-Directed Graph (ThreeJS) that adds the groups.json
graph dataset from @tomshanleynz‘s Network of groups example
3-dimensional representation of a force-directed iterative layout, using 3d-force-graph. This wrapper component uses ThreeJS/WebGL for rendering and ngraph for the 3D physics engine.
Cycle through various topological data sets using the button on the top-right.
THREE.TrackballControls = TrackballControls; //Link module to Three
const Graph = ForceGraph3D()
(document.getElementById("3d-graph"));
let curDataSetIdx;
const dataSets = getGraphDataSets();
console.log('dataSets from index.js', dataSets);
let toggleData;
(toggleData = function() {
curDataSetIdx = curDataSetIdx === undefined ? 0 : (curDataSetIdx+1)%dataSets.length;
const dataSet = dataSets[curDataSetIdx];
dataSet(Graph); // Load data set
document.getElementById('graph-data-description').innerHTML = dataSet.description ? `Viewing ${dataSet.description}` : '';
})(); // IIFE init
<head>
<script src="//cdnjs.cloudflare.com/ajax/libs/three.js/84/three.min.js"></script>
<script src="//unpkg.com/three-trackballcontrols-web@0.0.2/dist/three-trackballcontrols.min.js"></script>
<script src="//unpkg.com/forcelayout3d-web@0.0.1/dist/forcelayout3d.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/qwest/4.4.5/qwest.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/PapaParse/4.1.4/papaparse.min.js"></script>
<script src="data-set-loader.js"></script>
<script src="3d-force-graph.js"></script>
<link rel="stylesheet" href="3d-force-graph.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="graph-data">
<span id="graph-data-description"></span>
<button class="toggle-data-btn" onClick="toggleData()">Show me something else</button>
</div>
<div id="3d-graph"></div>
<script src="index.js"></script>
</body>
.graph-nav-info {
position: absolute;
bottom: 5px;
width: 100%;
text-align: center;
color: slategrey;
opacity: 0.7;
font-size: 10px;
}
.graph-tooltip {
position: absolute;
color: lavender;
font-size: 18px;
}
function ForceGraph3D() {
const CAMERA_DISTANCE2NODES_FACTOR = 150;
class CompProp {
constructor(name, initVal = null, redigest = true, onChange = newVal => {}) {
this.name = name;
this.initVal = initVal;
this.redigest = redigest;
this.onChange = onChange;
}
}
const env = { // Holds component state
initialised: false,
onFrame: () => {}
};
const exposeProps = [
new CompProp('width', window.innerWidth),
new CompProp('height', window.innerHeight),
new CompProp('graphData', {
nodes: { 1: { name: 'mock', val: 1 } },
links: [[1, 1]] // [from, to]
}),
new CompProp('nodeRelSize', 4), // volume per val unit
new CompProp('lineOpacity', 0.2),
new CompProp('valAccessor', node => node.val),
new CompProp('nameAccessor', node => node.name),
new CompProp('colorAccessor', node => node.color),
new CompProp('initialEngineTicks', 0), // how many times to tick the force engine at init before starting to render
new CompProp('maxConvergeTime', 15000), // ms
new CompProp('maxConvergeFrames', 300)
];
function initStatic() {
// Wipe DOM
env.domNode.innerHTML = '';
// Add nav info section
const navInfo = document.createElement('div');
navInfo.classList.add('graph-nav-info');
navInfo.innerHTML = "MOVE mouse & press LEFT/A: rotate, MIDDLE/S: zoom, RIGHT/D: pan";
env.domNode.appendChild(navInfo);
// Setup tooltip
env.toolTipElem = document.createElement('div');
env.toolTipElem.classList.add('graph-tooltip');
env.domNode.appendChild(env.toolTipElem);
// Capture mouse coords on move
env.raycaster = new THREE.Raycaster();
env.mouse = new THREE.Vector2();
env.mouse.x = -2; // Initialize off canvas
env.mouse.y = -2;
env.domNode.addEventListener("mousemove", ev => {
// update the mouse pos
const offset = getOffset(env.domNode),
relPos = {
x: ev.pageX - offset.left,
y: ev.pageY - offset.top
};
env.mouse.x = (relPos.x / env.width) * 2 - 1;
env.mouse.y = -(relPos.y / env.height) * 2 + 1;
// Move tooltip
env.toolTipElem.style.top = (relPos.y - 40) + 'px';
env.toolTipElem.style.left = (relPos.x - 20) + 'px';
function getOffset(el) {
const rect = el.getBoundingClientRect(),
scrollLeft = window.pageXOffset || document.documentElement.scrollLeft,
scrollTop = window.pageYOffset || document.documentElement.scrollTop;
return { top: rect.top + scrollTop, left: rect.left + scrollLeft };
}
}, false);
// Setup camera
env.camera = new THREE.PerspectiveCamera();
env.camera.far = 20000;
env.camera.position.z = 1000;
// Setup scene
env.scene = new THREE.Scene();
// Setup renderer
env.renderer = new THREE.WebGLRenderer();
env.domNode.appendChild(env.renderer.domElement);
// Add camera interaction
env.controls = new THREE.TrackballControls(env.camera, env.renderer.domElement);
env.initialised = true;
//
// Kick-off renderer
(function animate() { // IIFE
env.onFrame();
// Update tooltip
env.raycaster.setFromCamera(env.mouse, env.camera);
const intersects = env.raycaster.intersectObjects(env.scene.children);
env.toolTipElem.innerHTML = intersects.length ? intersects[0].object.name || '' : '';
// Frame cycle
env.controls.update();
env.renderer.render(env.scene, env.camera);
requestAnimationFrame(animate);
})()
}
function digest() {
if (!env.initialised) { return }
resizeCanvas();
env.onFrame = ()=>{}; // Clear previous frame hook
env.scene = new THREE.Scene(); // Clear the place
// Build graph with data
const graph = ngraph.graph();
for (let nodeId in env.graphData.nodes) {
graph.addNode(nodeId, env.graphData.nodes[nodeId]);
}
for (let link of env.graphData.links) {
graph.addLink(...link, {});
}
// console.log('graph from 3d-force-graph', graph);
// Add WebGL objects
graph.forEachNode(node => {
const nodeMaterial = new THREE.MeshBasicMaterial({ color: env.colorAccessor(node.data) || 0xffffaa, transparent: true });
nodeMaterial.opacity = 0.75;
const sphere = new THREE.Mesh(
new THREE.SphereGeometry(Math.cbrt(env.valAccessor(node.data) || 1) * env.nodeRelSize),
nodeMaterial
);
sphere.name = env.nameAccessor(node.data) || '';
env.scene.add(node.data.sphere = sphere)
});
const lineMaterial = new THREE.MeshBasicMaterial({ color: 0xf0f0f0, transparent: true });
lineMaterial.opacity = env.lineOpacity;
graph.forEachLink(link => {
const line = new THREE.Line(new THREE.Geometry(), lineMaterial);
line.name = `${getNodeName(link.fromId)} > ${getNodeName(link.toId)}`;
env.scene.add(link.data.line = line)
function getNodeName(nodeId) {
return env.nameAccessor(graph.getNode(nodeId).data);
}
});
env.camera.lookAt(env.scene.position);
env.camera.position.z = Math.cbrt(Object.keys(env.graphData.nodes).length) * CAMERA_DISTANCE2NODES_FACTOR;
// Add force-directed layout
const layout = ngraph.forcelayout3d(graph);
for (let i=0; i<env.initialEngineTicks; i++) { layout.step(); } // Initial ticks before starting to render
let cntTicks = 0;
const startTickTime = new Date();
env.onFrame = layoutTick;
//
function resizeCanvas() {
if (env.width && env.height) {
env.renderer.setSize(env.width, env.height);
env.camera.aspect = env.width/env.height;
env.camera.updateProjectionMatrix();
}
}
function layoutTick() {
if (cntTicks++ > env.maxConvergeFrames || (new Date()) - startTickTime > env.maxConvergeTime) {
env.onFrame = ()=>{}; // Stop ticking graph
}
layout.step(); // Tick it
// Update nodes position
graph.forEachNode(node => {
const sphere = node.data.sphere,
pos = layout.getNodePosition(node.id);
sphere.position.x = pos.x;
sphere.position.y = pos.y;
sphere.position.z = pos.z;
});
// Update links position
graph.forEachLink(link => {
const line = link.data.line,
pos = layout.getLinkPosition(link.id);
line.geometry.vertices = [
new THREE.Vector3(pos.from.x, pos.from.y, pos.from.z),
new THREE.Vector3(pos.to.x, pos.to.y, pos.to.z)
];
line.geometry.verticesNeedUpdate = true;
})
}
}
// Component constructor
function chart(nodeElement) {
env.domNode = nodeElement;
initStatic();
digest();
return chart;
}
// Getter/setter methods
exposeProps.forEach(prop => {
chart[prop.name] = getSetEnv(prop.name, prop.redigest, prop.onChange);
env[prop.name] = prop.initVal;
prop.onChange(prop.initVal);
function getSetEnv(prop, redigest = false, onChange = newVal => {}) {
return _ => {
if (!arguments.length) { return env[prop] }
env[prop] = _;
onChange(_);
if (redigest) { digest() }
return chart;
}
}
});
// Reset to default state
chart.resetState = function() {
this.graphData({nodes: [], links: []})
.nodeRelSize(4)
.lineOpacity(0.2)
.valAccessor(node => node.val)
.nameAccessor(node => node.name)
.colorAccessor(node => node.color)
.initialEngineTicks(0)
.maxConvergeTime(15000) // ms
.maxConvergeFrames(300);
return this;
};
chart.resetState(); // Set defaults at instantiation
return chart;
}
size,path
,d3
,d3/d3-array
,d3/d3-array/threshold
,d3/d3-axis
,d3/d3-brush
,d3/d3-chord
,d3/d3-collection
,d3/d3-color
,d3/d3-dispatch
,d3/d3-drag
,d3/d3-dsv
,d3/d3-ease
,d3/d3-force
,d3/d3-format
,d3/d3-geo
,d3/d3-geo/clip
,d3/d3-geo/path
,d3/d3-geo/projection
,d3/d3-hierarchy
,d3/d3-hierarchy/hierarchy
,d3/d3-hierarchy/pack
,d3/d3-hierarchy/treemap
,d3/d3-interpolate
,d3/d3-interpolate/transform
,d3/d3-path
,d3/d3-polygon
,d3/d3-quadtree
,d3/d3-queue
,d3/d3-random
,d3/d3-request
,d3/d3-scale
,d3/d3-selection
,d3/d3-selection/selection
,d3/d3-shape
,d3/d3-shape/curve
,d3/d3-shape/offset
,d3/d3-shape/order
,d3/d3-shape/symbol
,d3/d3-time-format
,d3/d3-time
,d3/d3-timer
,d3/d3-transition
,d3/d3-transition/selection
,d3/d3-transition/transition
,d3/d3-voronoi
,d3/d3-zoom
90,d3/d3-array/array.js
86,d3/d3-array/ascending.js
238,d3/d3-array/bisect.js
786,d3/d3-array/bisector.js
72,d3/d3-array/constant.js
86,d3/d3-array/descending.js
135,d3/d3-array/deviation.js
553,d3/d3-array/extent.js
1876,d3/d3-array/histogram.js
43,d3/d3-array/identity.js
451,d3/d3-array/max.js
362,d3/d3-array/mean.js
452,d3/d3-array/median.js
339,d3/d3-array/merge.js
451,d3/d3-array/min.js
63,d3/d3-array/number.js
182,d3/d3-array/pairs.js
161,d3/d3-array/permute.js
416,d3/d3-array/quantile.js
344,d3/d3-array/range.js
357,d3/d3-array/scan.js
285,d3/d3-array/shuffle.js
295,d3/d3-array/sum.js
361,d3/d3-array/threshold/freedmanDiaconis.js
180,d3/d3-array/threshold/scott.js
96,d3/d3-array/threshold/sturges.js
672,d3/d3-array/ticks.js
356,d3/d3-array/transpose.js
540,d3/d3-array/variance.js
99,d3/d3-array/zip.js
42,d3/d3-axis/array.js
5239,d3/d3-axis/axis.js
43,d3/d3-axis/identity.js
15778,d3/d3-brush/brush.js
72,d3/d3-brush/constant.js
127,d3/d3-brush/event.js
202,d3/d3-brush/noevent.js
42,d3/d3-chord/array.js
3178,d3/d3-chord/chord.js
72,d3/d3-chord/constant.js
159,d3/d3-chord/math.js
2340,d3/d3-chord/ribbon.js
137,d3/d3-collection/entries.js
104,d3/d3-collection/keys.js
1988,d3/d3-collection/map.js
2021,d3/d3-collection/nest.js
800,d3/d3-collection/set.js
115,d3/d3-collection/values.js
9276,d3/d3-color/color.js
1855,d3/d3-color/cubehelix.js
340,d3/d3-color/define.js
3167,d3/d3-color/lab.js
72,d3/d3-color/math.js
2729,d3/d3-dispatch/dispatch.js
72,d3/d3-drag/constant.js
4297,d3/d3-drag/drag.js
430,d3/d3-drag/event.js
857,d3/d3-drag/nodrag.js
202,d3/d3-drag/noevent.js
199,d3/d3-dsv/csv.js
3582,d3/d3-dsv/dsv.js
200,d3/d3-dsv/tsv.js
653,d3/d3-ease/back.js
521,d3/d3-ease/bounce.js
261,d3/d3-ease/circle.js
210,d3/d3-ease/cubic.js
1309,d3/d3-ease/elastic.js
251,d3/d3-ease/exp.js
43,d3/d3-ease/linear.js
596,d3/d3-ease/poly.js
192,d3/d3-ease/quad.js
236,d3/d3-ease/sin.js
654,d3/d3-force/center.js
2447,d3/d3-force/collide.js
72,d3/d3-force/constant.js
69,d3/d3-force/jiggle.js
3213,d3/d3-force/link.js
3181,d3/d3-force/manyBody.js
3444,d3/d3-force/simulation.js
1030,d3/d3-force/x.js
1030,d3/d3-force/y.js
361,d3/d3-format/defaultLocale.js
134,d3/d3-format/exponent.js
656,d3/d3-format/formatDecimal.js
368,d3/d3-format/formatDefault.js
475,d3/d3-format/formatGroup.js
611,d3/d3-format/formatPrefixAuto.js
458,d3/d3-format/formatRounded.js
1589,d3/d3-format/formatSpecifier.js
846,d3/d3-format/formatTypes.js
5247,d3/d3-format/locale.js
119,d3/d3-format/precisionFixed.js
190,d3/d3-format/precisionPrefix.js
186,d3/d3-format/precisionRound.js
906,d3/d3-geo/adder.js
1958,d3/d3-geo/area.js
5361,d3/d3-geo/bounds.js
929,d3/d3-geo/cartesian.js
3816,d3/d3-geo/centroid.js
2373,d3/d3-geo/circle.js
2897,d3/d3-geo/clip/antimeridian.js
470,d3/d3-geo/clip/buffer.js
5956,d3/d3-geo/clip/circle.js
5527,d3/d3-geo/clip/extent.js
3813,d3/d3-geo/clip/index.js
1099,d3/d3-geo/clip/line.js
2802,d3/d3-geo/clip/polygon.js
250,d3/d3-geo/compose.js
72,d3/d3-geo/constant.js
229,d3/d3-geo/distance.js
3034,d3/d3-geo/graticule.js
43,d3/d3-geo/identity.js
911,d3/d3-geo/interpolate.js
1309,d3/d3-geo/length.js
880,d3/d3-geo/math.js
34,d3/d3-geo/noop.js
945,d3/d3-geo/path/area.js
485,d3/d3-geo/path/bounds.js
2033,d3/d3-geo/path/centroid.js
914,d3/d3-geo/path/context.js
1690,d3/d3-geo/path/index.js
1149,d3/d3-geo/path/string.js
139,d3/d3-geo/pointEqual.js
2491,d3/d3-geo/polygonContains.js
235,d3/d3-geo/projection/albers.js
3986,d3/d3-geo/projection/albersUsa.js
502,d3/d3-geo/projection/azimuthal.js
447,d3/d3-geo/projection/azimuthalEqualArea.js
443,d3/d3-geo/projection/azimuthalEquidistant.js
402,d3/d3-geo/projection/conic.js
1017,d3/d3-geo/projection/conicConformal.js
871,d3/d3-geo/projection/conicEqualArea.js
771,d3/d3-geo/projection/conicEquidistant.js
314,d3/d3-geo/projection/cylindricalEqualArea.js
253,d3/d3-geo/projection/equirectangular.js
910,d3/d3-geo/projection/fit.js
387,d3/d3-geo/projection/gnomonic.js
1922,d3/d3-geo/projection/identity.js
3752,d3/d3-geo/projection/index.js
1119,d3/d3-geo/projection/mercator.js
376,d3/d3-geo/projection/orthographic.js
3275,d3/d3-geo/projection/resample.js
436,d3/d3-geo/projection/stereographic.js
762,d3/d3-geo/projection/transverseMercator.js
2509,d3/d3-geo/rotation.js
2305,d3/d3-geo/stream.js
701,d3/d3-geo/transform.js
166,d3/d3-hierarchy/accessors.js
2093,d3/d3-hierarchy/cluster.js
120,d3/d3-hierarchy/constant.js
138,d3/d3-hierarchy/hierarchy/ancestors.js
121,d3/d3-hierarchy/hierarchy/descendants.js
381,d3/d3-hierarchy/hierarchy/each.js
353,d3/d3-hierarchy/hierarchy/eachAfter.js
282,d3/d3-hierarchy/hierarchy/eachBefore.js
1819,d3/d3-hierarchy/hierarchy/index.js
164,d3/d3-hierarchy/hierarchy/leaves.js
246,d3/d3-hierarchy/hierarchy/links.js
606,d3/d3-hierarchy/hierarchy/path.js
151,d3/d3-hierarchy/hierarchy/sort.js
264,d3/d3-hierarchy/hierarchy/sum.js
2452,d3/d3-hierarchy/pack/enclose.js
1917,d3/d3-hierarchy/pack/index.js
389,d3/d3-hierarchy/pack/shuffle.js
3497,d3/d3-hierarchy/pack/siblings.js
1266,d3/d3-hierarchy/partition.js
1934,d3/d3-hierarchy/stratify.js
7060,d3/d3-hierarchy/tree.js
1184,d3/d3-hierarchy/treemap/binary.js
309,d3/d3-hierarchy/treemap/dice.js
2810,d3/d3-hierarchy/treemap/index.js
1029,d3/d3-hierarchy/treemap/resquarify.js
166,d3/d3-hierarchy/treemap/round.js
309,d3/d3-hierarchy/treemap/slice.js
170,d3/d3-hierarchy/treemap/sliceDice.js
1868,d3/d3-hierarchy/treemap/squarify.js
372,d3/d3-interpolate/array.js
600,d3/d3-interpolate/basis.js
360,d3/d3-interpolate/basisClosed.js
697,d3/d3-interpolate/color.js
72,d3/d3-interpolate/constant.js
760,d3/d3-interpolate/cubehelix.js
134,d3/d3-interpolate/date.js
547,d3/d3-interpolate/hcl.js
547,d3/d3-interpolate/hsl.js
447,d3/d3-interpolate/lab.js
100,d3/d3-interpolate/number.js
390,d3/d3-interpolate/object.js
163,d3/d3-interpolate/quantize.js
1277,d3/d3-interpolate/rgb.js
112,d3/d3-interpolate/round.js
1758,d3/d3-interpolate/string.js
672,d3/d3-interpolate/transform/decompose.js
2064,d3/d3-interpolate/transform/index.js
980,d3/d3-interpolate/transform/parse.js
598,d3/d3-interpolate/value.js
1387,d3/d3-interpolate/zoom.js
4089,d3/d3-path/path.js
243,d3/d3-polygon/area.js
346,d3/d3-polygon/centroid.js
411,d3/d3-polygon/contains.js
402,d3/d3-polygon/cross.js
1710,d3/d3-polygon/hull.js
375,d3/d3-polygon/length.js
2441,d3/d3-quadtree/add.js
1667,d3/d3-quadtree/cover.js
170,d3/d3-quadtree/data.js
206,d3/d3-quadtree/extent.js
1696,d3/d3-quadtree/find.js
134,d3/d3-quadtree/quad.js
2077,d3/d3-quadtree/quadtree.js
1898,d3/d3-quadtree/remove.js
51,d3/d3-quadtree/root.js
155,d3/d3-quadtree/size.js
695,d3/d3-quadtree/visit.js
773,d3/d3-quadtree/visitAfter.js
138,d3/d3-quadtree/x.js
138,d3/d3-quadtree/y.js
29,d3/d3-queue/array.js
2870,d3/d3-queue/queue.js
168,d3/d3-random/bates.js
113,d3/d3-random/exponential.js
137,d3/d3-random/irwinHall.js
178,d3/d3-random/logNormal.js
503,d3/d3-random/normal.js
236,d3/d3-random/uniform.js
101,d3/d3-request/csv.js
517,d3/d3-request/dsv.js
157,d3/d3-request/html.js
127,d3/d3-request/json.js
4593,d3/d3-request/request.js
109,d3/d3-request/text.js
118,d3/d3-request/tsv.js
370,d3/d3-request/type.js
174,d3/d3-request/xml.js
90,d3/d3-scale/array.js
2637,d3/d3-scale/band.js
119,d3/d3-scale/category10.js
179,d3/d3-scale/category20.js
179,d3/d3-scale/category20b.js
179,d3/d3-scale/category20c.js
101,d3/d3-scale/colors.js
72,d3/d3-scale/constant.js
3328,d3/d3-scale/continuous.js
188,d3/d3-scale/cubehelix.js
463,d3/d3-scale/identity.js
1206,d3/d3-scale/linear.js
3273,d3/d3-scale/log.js
340,d3/d3-scale/nice.js
44,d3/d3-scale/number.js
1116,d3/d3-scale/ordinal.js
1000,d3/d3-scale/pow.js
1280,d3/d3-scale/quantile.js
1066,d3/d3-scale/quantize.js
536,d3/d3-scale/rainbow.js
717,d3/d3-scale/sequential.js
802,d3/d3-scale/threshold.js
1203,d3/d3-scale/tickFormat.js
4565,d3/d3-scale/time.js
379,d3/d3-scale/utcTime.js
6471,d3/d3-scale/viridis.js
72,d3/d3-selection/constant.js
662,d3/d3-selection/creator.js
536,d3/d3-selection/local.js
533,d3/d3-selection/matcher.js
224,d3/d3-selection/mouse.js
303,d3/d3-selection/namespace.js
254,d3/d3-selection/namespaces.js
448,d3/d3-selection/point.js
259,d3/d3-selection/select.js
282,d3/d3-selection/selectAll.js
235,d3/d3-selection/selection/append.js
1460,d3/d3-selection/selection/attr.js
134,d3/d3-selection/selection/call.js
1740,d3/d3-selection/selection/classed.js
3597,d3/d3-selection/selection/data.js
132,d3/d3-selection/selection/datum.js
869,d3/d3-selection/selection/dispatch.js
289,d3/d3-selection/selection/each.js
53,d3/d3-selection/selection/empty.js
792,d3/d3-selection/selection/enter.js
176,d3/d3-selection/selection/exit.js
546,d3/d3-selection/selection/filter.js
520,d3/d3-selection/selection/html.js
2216,d3/d3-selection/selection/index.js
468,d3/d3-selection/selection/insert.js
171,d3/d3-selection/selection/lower.js
575,d3/d3-selection/selection/merge.js
258,d3/d3-selection/selection/node.js
140,d3/d3-selection/selection/nodes.js
3119,d3/d3-selection/selection/on.js
367,d3/d3-selection/selection/order.js
617,d3/d3-selection/selection/property.js
138,d3/d3-selection/selection/raise.js
153,d3/d3-selection/selection/remove.js
653,d3/d3-selection/selection/select.js
550,d3/d3-selection/selection/selectAll.js
98,d3/d3-selection/selection/size.js
681,d3/d3-selection/selection/sort.js
71,d3/d3-selection/selection/sparse.js
889,d3/d3-selection/selection/style.js
528,d3/d3-selection/selection/text.js
152,d3/d3-selection/selector.js
171,d3/d3-selection/selectorAll.js
175,d3/d3-selection/sourceEvent.js
407,d3/d3-selection/touch.js
323,d3/d3-selection/touches.js
218,d3/d3-selection/window.js
8831,d3/d3-shape/arc.js
2917,d3/d3-shape/area.js
42,d3/d3-shape/array.js
81,d3/d3-shape/constant.js
1436,d3/d3-shape/curve/basis.js
1530,d3/d3-shape/curve/basisClosed.js
1069,d3/d3-shape/curve/basisOpen.js
1081,d3/d3-shape/curve/bundle.js
1633,d3/d3-shape/curve/cardinal.js
1605,d3/d3-shape/curve/cardinalClosed.js
1288,d3/d3-shape/curve/cardinalOpen.js
2637,d3/d3-shape/curve/catmullRom.js
2083,d3/d3-shape/curve/catmullRomClosed.js
1760,d3/d3-shape/curve/catmullRomOpen.js
738,d3/d3-shape/curve/linear.js
514,d3/d3-shape/curve/linearClosed.js
3203,d3/d3-shape/curve/monotone.js
1761,d3/d3-shape/curve/natural.js
655,d3/d3-shape/curve/radial.js
1367,d3/d3-shape/curve/step.js
86,d3/d3-shape/descending.js
43,d3/d3-shape/identity.js
1516,d3/d3-shape/line.js
106,d3/d3-shape/math.js
29,d3/d3-shape/noop.js
319,d3/d3-shape/offset/expand.js
310,d3/d3-shape/offset/none.js
314,d3/d3-shape/offset/silhouette.js
740,d3/d3-shape/offset/wiggle.js
305,d3/d3-shape/order/ascending.js
112,d3/d3-shape/order/descending.js
545,d3/d3-shape/order/insideOut.js
120,d3/d3-shape/order/none.js
97,d3/d3-shape/order/reverse.js
2336,d3/d3-shape/pie.js
81,d3/d3-shape/point.js
934,d3/d3-shape/radialArea.js
396,d3/d3-shape/radialLine.js
1432,d3/d3-shape/stack.js
186,d3/d3-shape/symbol/circle.js
476,d3/d3-shape/symbol/cross.js
307,d3/d3-shape/symbol/diamond.js
137,d3/d3-shape/symbol/square.js
609,d3/d3-shape/symbol/star.js
255,d3/d3-shape/symbol/triangle.js
733,d3/d3-shape/symbol/wye.js
1160,d3/d3-shape/symbol.js
867,d3/d3-time-format/defaultLocale.js
284,d3/d3-time-format/isoFormat.js
319,d3/d3-time-format/isoParse.js
13876,d3/d3-time-format/locale.js
462,d3/d3-time/day.js
164,d3/d3-time/duration.js
569,d3/d3-time/hour.js
1845,d3/d3-time/interval.js
668,d3/d3-time/millisecond.js
437,d3/d3-time/minute.js
414,d3/d3-time/month.js
440,d3/d3-time/second.js
397,d3/d3-time/utcDay.js
399,d3/d3-time/utcHour.js
412,d3/d3-time/utcMinute.js
453,d3/d3-time/utcMonth.js
979,d3/d3-time/utcWeek.js
808,d3/d3-time/utcYear.js
963,d3/d3-time/week.js
754,d3/d3-time/year.js
400,d3/d3-timer/interval.js
250,d3/d3-timer/timeout.js
2771,d3/d3-timer/timer.js
484,d3/d3-transition/active.js
665,d3/d3-transition/interrupt.js
245,d3/d3-transition/selection/index.js
138,d3/d3-transition/selection/interrupt.js
1090,d3/d3-transition/selection/transition.js
2473,d3/d3-transition/transition/attr.js
904,d3/d3-transition/transition/attrTween.js
510,d3/d3-transition/transition/delay.js
528,d3/d3-transition/transition/duration.js
348,d3/d3-transition/transition/ease.js
574,d3/d3-transition/transition/filter.js
1892,d3/d3-transition/transition/index.js
340,d3/d3-transition/transition/interpolate.js
653,d3/d3-transition/transition/merge.js
853,d3/d3-transition/transition/on.js
284,d3/d3-transition/transition/remove.js
4792,d3/d3-transition/transition/schedule.js
826,d3/d3-transition/transition/select.js
883,d3/d3-transition/transition/selectAll.js
174,d3/d3-transition/transition/selection.js
2119,d3/d3-transition/transition/style.js
607,d3/d3-transition/transition/styleTween.js
473,d3/d3-transition/transition/text.js
691,d3/d3-transition/transition/transition.js
2026,d3/d3-transition/transition/tween.js
4381,d3/d3-voronoi/Beach.js
4087,d3/d3-voronoi/Cell.js
1632,d3/d3-voronoi/Circle.js
72,d3/d3-voronoi/constant.js
3415,d3/d3-voronoi/Diagram.js
3634,d3/d3-voronoi/Edge.js
81,d3/d3-voronoi/point.js
5302,d3/d3-voronoi/RedBlackTree.js
1420,d3/d3-voronoi/voronoi.js
72,d3/d3-zoom/constant.js
137,d3/d3-zoom/event.js
202,d3/d3-zoom/noevent.js
1336,d3/d3-zoom/transform.js
12133,d3/d3-zoom/zoom.js
function getGraphDataSets() {
// Color brewer paired set
const colors = ['#a6cee3','#1f78b4','#b2df8a','#33a02c','#fb9a99','#e31a1c','#fdbf6f','#ff7f00','#cab2d6','#6a3d9a','#ffff99','#b15928'];
const loadMiserables = function(Graph) {
qwest.get('miserables.json').then((_, data) => {
const nodes = {};
data.nodes.forEach(node => { nodes[node.id] = node }); // Index by ID
console.log('data from loadMiserables', data);
Graph
.resetState()
.nameAccessor(node => node.id)
.colorAccessor(node => parseInt(colors[node.group%colors.length].slice(1),16))
.graphData({
nodes: nodes,
links: data.links.map(link => [link.source, link.target])
});
});
};
loadMiserables.description = "<em>Les Miserables</em> data (<a href='https://bl.ocks.org/mbostock/4062045'>4062045</a>)";
//
const loadBlocks = function(Graph) {
qwest.get('blocks.json').then((_, data) => {
const userColors = {};
Array.from(new Set(data.nodes.map(node => node.user || null))).forEach((user, idx) => {
userColors[user] = colors[idx%colors.length]; // Rotate colors
});
const nodes = {};
data.nodes.forEach(node => { nodes[node.id] = node }); // Index by ID
Graph
.resetState()
.nameAccessor(node => `${node.user?node.user+': ':''}${node.description || node.id}`)
.colorAccessor(node => parseInt(userColors[node.user || null].slice(1), 16))
.graphData({
nodes: nodes,
links: data.links.map(link => [link.source, link.target])
});
});
};
loadBlocks.description = "<em>Blocks</em> data (<a href='https://bl.ocks.org/mbostock/afecf1ce04644ad9036ca146d2084895'>afecf1ce04644ad9036ca146d2084895</a>)";
//
const loadD3Dependencies= function(Graph) {
qwest.get('d3.csv').then((_, csvData) => {
const { data: [, ...data] } = Papa.parse(csvData); // Parse csv
data.pop(); // Remove last empty row
const nodes = {}, links = [], modules = new Set();
data.forEach(([size, path]) => {
const levels = path.split('/'),
module = levels.length > 1 ? levels[1] : null,
leaf = levels.pop(),
parent = levels.join('/');
modules.add(module);
nodes[path] = {
leaf: leaf,
module: module,
path: path,
size: +size || 1
};
if (parent) {
links.push([parent, path]);
}
});
const moduleColors = {};
Array.from(modules).forEach((module, idx) => {
moduleColors[module] = colors[idx%colors.length]; // Rotate colors
});
Graph
.resetState()
.nodeRelSize(0.5)
.valAccessor(node => node.size)
.nameAccessor(node => node.path)
.colorAccessor(node => parseInt(moduleColors[node.module || null].slice(1), 16))
.graphData({ nodes: nodes, links: links });
});
};
loadD3Dependencies.description = "<em>D3 dependencies</em> data (<a href='https://bl.ocks.org/mbostock/9a8124ccde3a4e9625bc413b48f14b30'>9a8124ccde3a4e9625bc413b48f14b30</a>)";
//
const loadGroups = function(Graph) {
qwest.get('groups.json').then((_, data) => {
const nodes = {};
// add an id property and
// Index by name
data.nodes.forEach((node, i) => {
node.id = i;
node.groupLabel = node.group;
node.group = Number(node.group.split(' ')[1]) || 0;
nodes[node.id] = node;
});
console.log('data from loadGroups', data);
console.log('nodes from loadGroups', nodes);
Graph
.resetState()
.nameAccessor(node => node.id)
.colorAccessor(node => parseInt(colors[node.group%colors.length].slice(1),16))
.graphData({
nodes: nodes,
links: data.links.map(link => [link.source, link.target])
});
});
};
loadGroups.description = "<em>Group Membership</em> data (<a href='http://bl.ocks.org/tomshanley/d3185cf3bde18b223376'>d3185cf3bde18b223376</a>)";
//
return [loadGroups, loadMiserables, loadBlocks, loadD3Dependencies];
}
{
"nodes":[
{"name":"Agnes Partee","group":"Organisation 1","single":"no"},
{"name":"Ellyn Arzola","group":"Organisation 1","single":"no"},
{"name":"Antone Milazzo","group":"Organisation 1","single":"no"},
{"name":"Francina Schnee","group":"Organisation 1","single":"no"},
{"name":"Lia Fetzer","group":"Organisation 1","single":"no"},
{"name":"Heike Maurice","group":"Organisation 1","single":"no"},
{"name":"Gertrude Hayek","group":"Organisation 1","single":"no"},
{"name":"Aurea Gayer","group":"Organisation 1","single":"no"},
{"name":"Sylvia Pellham","group":"Organisation 1","single":"no"},
{"name":"Katerine Lough","group":"Organisation 1","single":"no"},
{"name":"Ute Moss","group":"Organisation 10","single":"no"},
{"name":"Jerrica Raatz","group":"Organisation 2","single":"no"},
{"name":"Maggie Lamacchia","group":"Organisation 4","single":"no"},
{"name":"Suanne Wesely","group":"Organisation 1","single":"yes"},
{"name":"Ida Golston","group":"Organisation 5","single":"yes"},
{"name":"Danuta Haggett","group":"Organisation 6","single":"yes"},
{"name":"Owen Elms","group":"Organisation 8","single":"yes"},
{"name":"Evelynn Lovin","group":"Organisation 2","single":"yes"},
{"name":"Jacqulyn Demello","group":"Organisation 3","single":"yes"},
{"name":"Fredia Ashbrook","group":"Organisation 7","single":"yes"},
{"name":"Elena Fout","group":"Organisation 3","single":"no"},
{"name":"Porfirio Bengston","group":"Organisation 5","single":"no"},
{"name":"Yi Lounsbury","group":"Organisation 8","single":"no"},
{"name":"Santina Kong","group":"Organisation 4","single":"no"},
{"name":"Juana Krogh","group":"Organisation 1","single":"no"},
{"name":"Emmy Cornman","group":"Organisation 1","single":"no"},
{"name":"Ivory Whitsitt","group":"Organisation 1","single":"yes"},
{"name":"Yevette Ullery","group":"Organisation 1","single":"yes"},
{"name":"Yesenia Stillwell","group":"Organisation 2","single":"yes"},
{"name":"Brett Haar","group":"Organisation 7","single":"no"},
{"name":"Buford Garraway","group":"Organisation 8","single":"no"},
{"name":"Lou Christon","group":"Organisation 2","single":"yes"},
{"name":"Kanisha Keaney","group":"Organisation 1","single":"yes"},
{"name":"Janise Fish","group":"Organisation 1","single":"yes"},
{"name":"Adalberto Dombrosky","group":"Organisation 1","single":"yes"},
{"name":"Emma Vernon","group":"Organisation 2","single":"yes"},
{"name":"Stephania Stringham","group":"Organisation 2","single":"yes"},
{"name":"Shila Hurlbut","group":"Organisation 4","single":"yes"},
{"name":"Ciera Dube","group":"Organisation 4","single":"yes"},
{"name":"Lauran Hardesty","group":"Organisation 3","single":"yes"},
{"name":"Ila Jiminez","group":"Organisation 8","single":"yes"},
{"name":"Elise Jovel","group":"Organisation 8","single":"yes"},
{"name":"Tarah Mcdavid","group":"Organisation 8","single":"yes"},
{"name":"Julietta Raap","group":"Organisation 1","single":"no"},
{"name":"Herlinda Hagel","group":"Organisation 8","single":"no"},
{"name":"Mauro Canez","group":"Organisation 1","single":"no"},
{"name":"Arthur Farias","group":"Organisation 1","single":"no"},
{"name":"Reyes Fey","group":"Organisation 8","single":"no"},
{"name":"Oretha Huisman","group":"Organisation 5","single":"yes"},
{"name":"Lucie Fettig","group":"Organisation 2","single":"yes"},
{"name":"Maribel Ericsson","group":"Organisation 2","single":"yes"},
{"name":"Estelle Speight","group":"Organisation 4","single":"yes"},
{"name":"Krysta Wahlen","group":"Organisation 4","single":"yes"},
{"name":"Marielle Geibel","group":"Organisation 3","single":"yes"},
{"name":"Jackelyn Fonda","group":"Organisation 8","single":"yes"},
{"name":"Roxanna Swink","group":"Organisation 8","single":"yes"},
{"name":"Adena Defrancisco","group":"Organisation 4","single":"yes"},
{"name":"Veronique Farrington","group":"Organisation 8","single":"no"},
{"name":"Bud Teeters","group":"Organisation 9","single":"yes"},
{"name":"Allyn Ibarra","group":"Organisation 10","single":"yes"},
{"name":"Clemmie Stultz","group":"Organisation 2","single":"yes"},
{"name":"Mayra Fluellen","group":"Organisation 4","single":"yes"},
{"name":"Malia Saffer","group":"Organisation 7","single":"yes"},
{"name":"Tressa Heacock","group":"Organisation 3","single":"no"},
{"name":"Jeannine Weise","group":"Organisation 10","single":"yes"},
{"name":"Reagan Stonecipher","group":"Organisation 4","single":"yes"},
{"name":"Madlyn Moretti","group":"Organisation 3","single":"yes"},
{"name":"Alfonso Letendre","group":"Organisation 1","single":"yes"},
{"name":"Alissa Sabatini","group":"Organisation 1","single":"yes"},
{"name":"Kimbra Olson","group":"Organisation 2","single":"yes"},
{"name":"Earline Bergen","group":"Organisation 4","single":"yes"},
{"name":"Sheilah Gill","group":"Organisation 3","single":"yes"},
{"name":"Coretta Hine","group":"Organisation 7","single":"yes"},
{"name":"German Arata","group":"Organisation 5","single":"yes"},
{"name":"Alleen Jaco","group":"Organisation 10","single":"no"},
{"name":"Qiana Gaskamp","group":"Organisation 4","single":"no"},
{"name":"Lynelle Fairbairn","group":"Organisation 4","single":"no"},
{"name":"Blanch Brain","group":"Organisation 11","single":"yes"},
{"name":"Mamie Stampley","group":"Organisation 4","single":"yes"},
{"name":"Brianna Haycock","group":"Organisation 4","single":"yes"},
{"name":"Kirstie Price","group":"Organisation 1","single":"yes"},
{"name":"Takako Macleod","group":"Organisation 2","single":"yes"},
{"name":"Gerry Schiffer","group":"Organisation 12","single":"no"},
{"name":"Cinderella Smithwick","group":"Organisation 1","single":"no"},
{"name":"Ambrose Foronda","group":"Organisation 10","single":"yes"},
{"name":"Geraldine Kaczorowski","group":"Organisation 1","single":"yes"},
{"name":"Shonna Severs","group":"Organisation 11","single":"yes"},
{"name":"Rona Hakim","group":"Organisation 2","single":"yes"},
{"name":"Jewel Verrill","group":"Organisation 7","single":"yes"},
{"name":"Genevive Thibeau","group":"Organisation 7","single":"yes"},
{"name":"Machelle Rahimi","group":"Organisation 13","single":"yes"},
{"name":"Kymberly Ashlock","group":"Organisation 4","single":"yes"},
{"name":"Elmo Upson","group":"Organisation 4","single":"yes"},
{"name":"Yuri Alonso","group":"Organisation 1","single":"yes"},
{"name":"Jacinto Dowdle","group":"Organisation 5","single":"yes"},
{"name":"Shannan Finger","group":"Organisation 2","single":"yes"},
{"name":"Cori Perrin","group":"Organisation 7","single":"yes"},
{"name":"Tamica Akers","group":"Organisation 14","single":"yes"},
{"name":"Geneva Mogensen","group":"Organisation 9","single":"yes"},
{"name":"Gladis Flemings","group":"Organisation 5","single":"yes"},
{"name":"Helena Chamlee","group":"Organisation 8","single":"yes"},
{"name":"Tereasa Wold","group":"Organisation 2","single":"yes"},
{"name":"Alton Santini","group":"Organisation 8","single":"no"},
{"name":"Estella Savory","group":"Organisation 10","single":"yes"},
{"name":"Adrianna Mader","group":"Organisation 10","single":"yes"},
{"name":"Anastasia Blass","group":"Organisation 1","single":"yes"},
{"name":"Dominic Wilborn","group":"Organisation 2","single":"yes"},
{"name":"Xavier Liddell","group":"Organisation 4","single":"yes"},
{"name":"Franchesca Eggert","group":"Organisation 4","single":"yes"},
{"name":"Rubye Boze","group":"Organisation 4","single":"yes"},
{"name":"Avelina Vannostrand","group":"Organisation 3","single":"yes"},
{"name":"Lucille Witty","group":"Organisation 7","single":"yes"},
{"name":"Chanelle Trew","group":"Organisation 15","single":"yes"},
{"name":"Alta Neuner","group":"Organisation 15","single":"yes"},
{"name":"Carroll Mcglade","group":"Organisation 2","single":"yes"},
{"name":"Albert Almanza","group":"Organisation 9","single":"yes"},
{"name":"Lillia Reaper","group":"Organisation 10","single":"yes"},
{"name":"Wilma Veach","group":"Organisation 13 NZ","single":"yes"},
{"name":"Shantae Torgrimson","group":"Organisation 11","single":"yes"},
{"name":"Adrienne Poovey","group":"Organisation 11","single":"yes"},
{"name":"Carey Vonderheide","group":"Organisation 2","single":"yes"},
{"name":"Jerilyn Rochon","group":"Organisation 4","single":"yes"},
{"name":"Shanita Stanfield","group":"Organisation 14","single":"yes"},
{"name":"Miesha Franklin","group":"Organisation 16","single":"yes"},
{"name":"Lucien Bevan","group":"Organisation 17","single":"yes"},
{"name":"Elana Kain","group":"Organisation 2","single":"yes"},
{"name":"Britany Dominique","group":"Organisation 2","single":"yes"},
{"name":"Garnet Lazos","group":"Organisation 17","single":"yes"},
{"name":"Cody Carrasquillo","group":"Organisation 17","single":"yes"},
{"name":"Catarina Ullery","group":"Organisation 17","single":"yes"},
{"name":"Group 1","group":"Group","single":"no"},
{"name":"Group 2","group":"Group","single":"no"},
{"name":"Group 3","group":"Group","single":"no"},
{"name":"Group 4","group":"Group","single":"no"},
{"name":"Group 5","group":"Group","single":"no"},
{"name":"Group 6","group":"Group","single":"no"},
{"name":"Group 7","group":"Group","single":"no"},
{"name":"Group 8","group":"Group","single":"no"},
{"name":"Group 9","group":"Group","single":"no"},
{"name":"Group 10","group":"Group","single":"no"},
{"name":"Group 11","group":"Group","single":"no"},
{"name":"Group 12","group":"Group","single":"no"},
{"name":"Group 13","group":"Group","single":"no"},
{"name":"Group 14","group":"Group","single":"no"},
{"name":"Group 15","group":"Group","single":"no"},
{"name":"Group 16","group":"Group","single":"no"},
{"name":"Group 17","group":"Group","single":"no"},
{"name":"Group 18","group":"Group","single":"no"},
{"name":"Group 19","group":"Group","single":"no"}
],
"links":[
{"source":0,"target":130,"value":1},
{"source":0,"target":131,"value":1},
{"source":0,"target":148,"value":1},
{"source":1,"target":130,"value":1},
{"source":1,"target":132,"value":1},
{"source":1,"target":135,"value":1},
{"source":2,"target":130,"value":1},
{"source":2,"target":133,"value":1},
{"source":2,"target":148,"value":1},
{"source":3,"target":130,"value":1},
{"source":3,"target":134,"value":1},
{"source":4,"target":130,"value":1},
{"source":4,"target":136,"value":1},
{"source":5,"target":130,"value":1},
{"source":5,"target":137,"value":1},
{"source":6,"target":130,"value":1},
{"source":6,"target":138,"value":1},
{"source":7,"target":130,"value":1},
{"source":7,"target":135,"value":1},
{"source":7,"target":139,"value":1},
{"source":8,"target":130,"value":1},
{"source":8,"target":140,"value":1},
{"source":9,"target":130,"value":1},
{"source":9,"target":140,"value":1},
{"source":10,"target":131,"value":1},
{"source":10,"target":132,"value":1},
{"source":11,"target":131,"value":1},
{"source":11,"target":141,"value":1},
{"source":11,"target":143,"value":1},
{"source":11,"target":144,"value":1},
{"source":12,"target":131,"value":1},
{"source":12,"target":143,"value":1},
{"source":12,"target":144,"value":1},
{"source":13,"target":131,"value":1},
{"source":14,"target":131,"value":1},
{"source":15,"target":131,"value":1},
{"source":16,"target":131,"value":1},
{"source":17,"target":131,"value":1},
{"source":18,"target":131,"value":1},
{"source":19,"target":131,"value":1},
{"source":20,"target":132,"value":1},
{"source":20,"target":134,"value":1},
{"source":20,"target":137,"value":1},
{"source":20,"target":148,"value":1},
{"source":21,"target":132,"value":1},
{"source":21,"target":137,"value":1},
{"source":21,"target":148,"value":1},
{"source":22,"target":132,"value":1},
{"source":22,"target":137,"value":1},
{"source":23,"target":132,"value":1},
{"source":23,"target":145,"value":1},
{"source":23,"target":148,"value":1},
{"source":24,"target":132,"value":1},
{"source":24,"target":146,"value":1},
{"source":25,"target":132,"value":1},
{"source":25,"target":147,"value":1},
{"source":26,"target":132,"value":1},
{"source":27,"target":132,"value":1},
{"source":28,"target":132,"value":1},
{"source":29,"target":133,"value":1},
{"source":29,"target":134,"value":1},
{"source":29,"target":148,"value":1},
{"source":30,"target":133,"value":1},
{"source":30,"target":138,"value":1},
{"source":31,"target":133,"value":1},
{"source":32,"target":133,"value":1},
{"source":33,"target":133,"value":1},
{"source":34,"target":133,"value":1},
{"source":35,"target":133,"value":1},
{"source":36,"target":133,"value":1},
{"source":37,"target":133,"value":1},
{"source":38,"target":133,"value":1},
{"source":39,"target":133,"value":1},
{"source":40,"target":133,"value":1},
{"source":41,"target":133,"value":1},
{"source":42,"target":133,"value":1},
{"source":43,"target":134,"value":1},
{"source":43,"target":137,"value":1},
{"source":44,"target":134,"value":1},
{"source":44,"target":139,"value":1},
{"source":45,"target":134,"value":1},
{"source":45,"target":148,"value":1},
{"source":46,"target":134,"value":1},
{"source":46,"target":148,"value":1},
{"source":47,"target":134,"value":1},
{"source":47,"target":148,"value":1},
{"source":48,"target":134,"value":1},
{"source":49,"target":134,"value":1},
{"source":50,"target":134,"value":1},
{"source":51,"target":134,"value":1},
{"source":52,"target":134,"value":1},
{"source":53,"target":134,"value":1},
{"source":54,"target":134,"value":1},
{"source":55,"target":134,"value":1},
{"source":56,"target":134,"value":1},
{"source":57,"target":137,"value":1},
{"source":57,"target":142,"value":1},
{"source":57,"target":143,"value":1},
{"source":57,"target":144,"value":1},
{"source":58,"target":137,"value":1},
{"source":59,"target":137,"value":1},
{"source":60,"target":137,"value":1},
{"source":61,"target":137,"value":1},
{"source":62,"target":137,"value":1},
{"source":63,"target":138,"value":1},
{"source":63,"target":140,"value":1},
{"source":63,"target":145,"value":1},
{"source":64,"target":138,"value":1},
{"source":65,"target":138,"value":1},
{"source":66,"target":138,"value":1},
{"source":67,"target":139,"value":1},
{"source":68,"target":139,"value":1},
{"source":69,"target":139,"value":1},
{"source":70,"target":139,"value":1},
{"source":71,"target":139,"value":1},
{"source":72,"target":139,"value":1},
{"source":73,"target":139,"value":1},
{"source":74,"target":140,"value":1},
{"source":74,"target":141,"value":1},
{"source":75,"target":140,"value":1},
{"source":75,"target":141,"value":1},
{"source":76,"target":140,"value":1},
{"source":76,"target":142,"value":1},
{"source":77,"target":140,"value":1},
{"source":78,"target":140,"value":1},
{"source":79,"target":140,"value":1},
{"source":80,"target":140,"value":1},
{"source":81,"target":140,"value":1},
{"source":82,"target":141,"value":1},
{"source":82,"target":142,"value":1},
{"source":82,"target":143,"value":1},
{"source":82,"target":144,"value":1},
{"source":83,"target":141,"value":1},
{"source":83,"target":143,"value":1},
{"source":83,"target":144,"value":1},
{"source":84,"target":141,"value":1},
{"source":85,"target":141,"value":1},
{"source":86,"target":141,"value":1},
{"source":87,"target":141,"value":1},
{"source":88,"target":141,"value":1},
{"source":89,"target":141,"value":1},
{"source":90,"target":142,"value":1},
{"source":91,"target":142,"value":1},
{"source":92,"target":142,"value":1},
{"source":93,"target":145,"value":1},
{"source":94,"target":145,"value":1},
{"source":95,"target":145,"value":1},
{"source":96,"target":145,"value":1},
{"source":97,"target":145,"value":1},
{"source":98,"target":145,"value":1},
{"source":99,"target":145,"value":1},
{"source":100,"target":145,"value":1},
{"source":101,"target":145,"value":1},
{"source":102,"target":147,"value":1},
{"source":102,"target":148,"value":1},
{"source":103,"target":147,"value":1},
{"source":104,"target":147,"value":1},
{"source":105,"target":147,"value":1},
{"source":106,"target":147,"value":1},
{"source":107,"target":147,"value":1},
{"source":108,"target":147,"value":1},
{"source":109,"target":147,"value":1},
{"source":110,"target":147,"value":1},
{"source":111,"target":147,"value":1},
{"source":112,"target":147,"value":1},
{"source":113,"target":147,"value":1},
{"source":114,"target":147,"value":1},
{"source":115,"target":148,"value":1},
{"source":116,"target":148,"value":1},
{"source":117,"target":148,"value":1},
{"source":118,"target":148,"value":1},
{"source":119,"target":148,"value":1},
{"source":120,"target":148,"value":1},
{"source":121,"target":148,"value":1},
{"source":122,"target":148,"value":1},
{"source":123,"target":148,"value":1},
{"source":124,"target":148,"value":1},
{"source":125,"target":148,"value":1},
{"source":126,"target":148,"value":1},
{"source":127,"target":148,"value":1},
{"source":128,"target":148,"value":1},
{"source":129,"target":148,"value":1}
]
}
{"nodes":[{"id":"Myriel","group":1},{"id":"Napoleon","group":1},{"id":"Mlle.Baptistine","group":1},{"id":"Mme.Magloire","group":1},{"id":"CountessdeLo","group":1},{"id":"Geborand","group":1},{"id":"Champtercier","group":1},{"id":"Cravatte","group":1},{"id":"Count","group":1},{"id":"OldMan","group":1},{"id":"Labarre","group":2},{"id":"Valjean","group":2},{"id":"Marguerite","group":3},{"id":"Mme.deR","group":2},{"id":"Isabeau","group":2},{"id":"Gervais","group":2},{"id":"Tholomyes","group":3},{"id":"Listolier","group":3},{"id":"Fameuil","group":3},{"id":"Blacheville","group":3},{"id":"Favourite","group":3},{"id":"Dahlia","group":3},{"id":"Zephine","group":3},{"id":"Fantine","group":3},{"id":"Mme.Thenardier","group":4},{"id":"Thenardier","group":4},{"id":"Cosette","group":5},{"id":"Javert","group":4},{"id":"Fauchelevent","group":0},{"id":"Bamatabois","group":2},{"id":"Perpetue","group":3},{"id":"Simplice","group":2},{"id":"Scaufflaire","group":2},{"id":"Woman1","group":2},{"id":"Judge","group":2},{"id":"Champmathieu","group":2},{"id":"Brevet","group":2},{"id":"Chenildieu","group":2},{"id":"Cochepaille","group":2},{"id":"Pontmercy","group":4},{"id":"Boulatruelle","group":6},{"id":"Eponine","group":4},{"id":"Anzelma","group":4},{"id":"Woman2","group":5},{"id":"MotherInnocent","group":0},{"id":"Gribier","group":0},{"id":"Jondrette","group":7},{"id":"Mme.Burgon","group":7},{"id":"Gavroche","group":8},{"id":"Gillenormand","group":5},{"id":"Magnon","group":5},{"id":"Mlle.Gillenormand","group":5},{"id":"Mme.Pontmercy","group":5},{"id":"Mlle.Vaubois","group":5},{"id":"Lt.Gillenormand","group":5},{"id":"Marius","group":8},{"id":"BaronessT","group":5},{"id":"Mabeuf","group":8},{"id":"Enjolras","group":8},{"id":"Combeferre","group":8},{"id":"Prouvaire","group":8},{"id":"Feuilly","group":8},{"id":"Courfeyrac","group":8},{"id":"Bahorel","group":8},{"id":"Bossuet","group":8},{"id":"Joly","group":8},{"id":"Grantaire","group":8},{"id":"MotherPlutarch","group":9},{"id":"Gueulemer","group":4},{"id":"Babet","group":4},{"id":"Claquesous","group":4},{"id":"Montparnasse","group":4},{"id":"Toussaint","group":5},{"id":"Child1","group":10},{"id":"Child2","group":10},{"id":"Brujon","group":4},{"id":"Mme.Hucheloup","group":8}],"links":[{"source":"Napoleon","target":"Myriel","value":1},{"source":"Mlle.Baptistine","target":"Myriel","value":8},{"source":"Mme.Magloire","target":"Myriel","value":10},{"source":"Mme.Magloire","target":"Mlle.Baptistine","value":6},{"source":"CountessdeLo","target":"Myriel","value":1},{"source":"Geborand","target":"Myriel","value":1},{"source":"Champtercier","target":"Myriel","value":1},{"source":"Cravatte","target":"Myriel","value":1},{"source":"Count","target":"Myriel","value":2},{"source":"OldMan","target":"Myriel","value":1},{"source":"Valjean","target":"Labarre","value":1},{"source":"Valjean","target":"Mme.Magloire","value":3},{"source":"Valjean","target":"Mlle.Baptistine","value":3},{"source":"Valjean","target":"Myriel","value":5},{"source":"Marguerite","target":"Valjean","value":1},{"source":"Mme.deR","target":"Valjean","value":1},{"source":"Isabeau","target":"Valjean","value":1},{"source":"Gervais","target":"Valjean","value":1},{"source":"Listolier","target":"Tholomyes","value":4},{"source":"Fameuil","target":"Tholomyes","value":4},{"source":"Fameuil","target":"Listolier","value":4},{"source":"Blacheville","target":"Tholomyes","value":4},{"source":"Blacheville","target":"Listolier","value":4},{"source":"Blacheville","target":"Fameuil","value":4},{"source":"Favourite","target":"Tholomyes","value":3},{"source":"Favourite","target":"Listolier","value":3},{"source":"Favourite","target":"Fameuil","value":3},{"source":"Favourite","target":"Blacheville","value":4},{"source":"Dahlia","target":"Tholomyes","value":3},{"source":"Dahlia","target":"Listolier","value":3},{"source":"Dahlia","target":"Fameuil","value":3},{"source":"Dahlia","target":"Blacheville","value":3},{"source":"Dahlia","target":"Favourite","value":5},{"source":"Zephine","target":"Tholomyes","value":3},{"source":"Zephine","target":"Listolier","value":3},{"source":"Zephine","target":"Fameuil","value":3},{"source":"Zephine","target":"Blacheville","value":3},{"source":"Zephine","target":"Favourite","value":4},{"source":"Zephine","target":"Dahlia","value":4},{"source":"Fantine","target":"Tholomyes","value":3},{"source":"Fantine","target":"Listolier","value":3},{"source":"Fantine","target":"Fameuil","value":3},{"source":"Fantine","target":"Blacheville","value":3},{"source":"Fantine","target":"Favourite","value":4},{"source":"Fantine","target":"Dahlia","value":4},{"source":"Fantine","target":"Zephine","value":4},{"source":"Fantine","target":"Marguerite","value":2},{"source":"Fantine","target":"Valjean","value":9},{"source":"Mme.Thenardier","target":"Fantine","value":2},{"source":"Mme.Thenardier","target":"Valjean","value":7},{"source":"Thenardier","target":"Mme.Thenardier","value":13},{"source":"Thenardier","target":"Fantine","value":1},{"source":"Thenardier","target":"Valjean","value":12},{"source":"Cosette","target":"Mme.Thenardier","value":4},{"source":"Cosette","target":"Valjean","value":31},{"source":"Cosette","target":"Tholomyes","value":1},{"source":"Cosette","target":"Thenardier","value":1},{"source":"Javert","target":"Valjean","value":17},{"source":"Javert","target":"Fantine","value":5},{"source":"Javert","target":"Thenardier","value":5},{"source":"Javert","target":"Mme.Thenardier","value":1},{"source":"Javert","target":"Cosette","value":1},{"source":"Fauchelevent","target":"Valjean","value":8},{"source":"Fauchelevent","target":"Javert","value":1},{"source":"Bamatabois","target":"Fantine","value":1},{"source":"Bamatabois","target":"Javert","value":1},{"source":"Bamatabois","target":"Valjean","value":2},{"source":"Perpetue","target":"Fantine","value":1},{"source":"Simplice","target":"Perpetue","value":2},{"source":"Simplice","target":"Valjean","value":3},{"source":"Simplice","target":"Fantine","value":2},{"source":"Simplice","target":"Javert","value":1},{"source":"Scaufflaire","target":"Valjean","value":1},{"source":"Woman1","target":"Valjean","value":2},{"source":"Woman1","target":"Javert","value":1},{"source":"Judge","target":"Valjean","value":3},{"source":"Judge","target":"Bamatabois","value":2},{"source":"Champmathieu","target":"Valjean","value":3},{"source":"Champmathieu","target":"Judge","value":3},{"source":"Champmathieu","target":"Bamatabois","value":2},{"source":"Brevet","target":"Judge","value":2},{"source":"Brevet","target":"Champmathieu","value":2},{"source":"Brevet","target":"Valjean","value":2},{"source":"Brevet","target":"Bamatabois","value":1},{"source":"Chenildieu","target":"Judge","value":2},{"source":"Chenildieu","target":"Champmathieu","value":2},{"source":"Chenildieu","target":"Brevet","value":2},{"source":"Chenildieu","target":"Valjean","value":2},{"source":"Chenildieu","target":"Bamatabois","value":1},{"source":"Cochepaille","target":"Judge","value":2},{"source":"Cochepaille","target":"Champmathieu","value":2},{"source":"Cochepaille","target":"Brevet","value":2},{"source":"Cochepaille","target":"Chenildieu","value":2},{"source":"Cochepaille","target":"Valjean","value":2},{"source":"Cochepaille","target":"Bamatabois","value":1},{"source":"Pontmercy","target":"Thenardier","value":1},{"source":"Boulatruelle","target":"Thenardier","value":1},{"source":"Eponine","target":"Mme.Thenardier","value":2},{"source":"Eponine","target":"Thenardier","value":3},{"source":"Anzelma","target":"Eponine","value":2},{"source":"Anzelma","target":"Thenardier","value":2},{"source":"Anzelma","target":"Mme.Thenardier","value":1},{"source":"Woman2","target":"Valjean","value":3},{"source":"Woman2","target":"Cosette","value":1},{"source":"Woman2","target":"Javert","value":1},{"source":"MotherInnocent","target":"Fauchelevent","value":3},{"source":"MotherInnocent","target":"Valjean","value":1},{"source":"Gribier","target":"Fauchelevent","value":2},{"source":"Mme.Burgon","target":"Jondrette","value":1},{"source":"Gavroche","target":"Mme.Burgon","value":2},{"source":"Gavroche","target":"Thenardier","value":1},{"source":"Gavroche","target":"Javert","value":1},{"source":"Gavroche","target":"Valjean","value":1},{"source":"Gillenormand","target":"Cosette","value":3},{"source":"Gillenormand","target":"Valjean","value":2},{"source":"Magnon","target":"Gillenormand","value":1},{"source":"Magnon","target":"Mme.Thenardier","value":1},{"source":"Mlle.Gillenormand","target":"Gillenormand","value":9},{"source":"Mlle.Gillenormand","target":"Cosette","value":2},{"source":"Mlle.Gillenormand","target":"Valjean","value":2},{"source":"Mme.Pontmercy","target":"Mlle.Gillenormand","value":1},{"source":"Mme.Pontmercy","target":"Pontmercy","value":1},{"source":"Mlle.Vaubois","target":"Mlle.Gillenormand","value":1},{"source":"Lt.Gillenormand","target":"Mlle.Gillenormand","value":2},{"source":"Lt.Gillenormand","target":"Gillenormand","value":1},{"source":"Lt.Gillenormand","target":"Cosette","value":1},{"source":"Marius","target":"Mlle.Gillenormand","value":6},{"source":"Marius","target":"Gillenormand","value":12},{"source":"Marius","target":"Pontmercy","value":1},{"source":"Marius","target":"Lt.Gillenormand","value":1},{"source":"Marius","target":"Cosette","value":21},{"source":"Marius","target":"Valjean","value":19},{"source":"Marius","target":"Tholomyes","value":1},{"source":"Marius","target":"Thenardier","value":2},{"source":"Marius","target":"Eponine","value":5},{"source":"Marius","target":"Gavroche","value":4},{"source":"BaronessT","target":"Gillenormand","value":1},{"source":"BaronessT","target":"Marius","value":1},{"source":"Mabeuf","target":"Marius","value":1},{"source":"Mabeuf","target":"Eponine","value":1},{"source":"Mabeuf","target":"Gavroche","value":1},{"source":"Enjolras","target":"Marius","value":7},{"source":"Enjolras","target":"Gavroche","value":7},{"source":"Enjolras","target":"Javert","value":6},{"source":"Enjolras","target":"Mabeuf","value":1},{"source":"Enjolras","target":"Valjean","value":4},{"source":"Combeferre","target":"Enjolras","value":15},{"source":"Combeferre","target":"Marius","value":5},{"source":"Combeferre","target":"Gavroche","value":6},{"source":"Combeferre","target":"Mabeuf","value":2},{"source":"Prouvaire","target":"Gavroche","value":1},{"source":"Prouvaire","target":"Enjolras","value":4},{"source":"Prouvaire","target":"Combeferre","value":2},{"source":"Feuilly","target":"Gavroche","value":2},{"source":"Feuilly","target":"Enjolras","value":6},{"source":"Feuilly","target":"Prouvaire","value":2},{"source":"Feuilly","target":"Combeferre","value":5},{"source":"Feuilly","target":"Mabeuf","value":1},{"source":"Feuilly","target":"Marius","value":1},{"source":"Courfeyrac","target":"Marius","value":9},{"source":"Courfeyrac","target":"Enjolras","value":17},{"source":"Courfeyrac","target":"Combeferre","value":13},{"source":"Courfeyrac","target":"Gavroche","value":7},{"source":"Courfeyrac","target":"Mabeuf","value":2},{"source":"Courfeyrac","target":"Eponine","value":1},{"source":"Courfeyrac","target":"Feuilly","value":6},{"source":"Courfeyrac","target":"Prouvaire","value":3},{"source":"Bahorel","target":"Combeferre","value":5},{"source":"Bahorel","target":"Gavroche","value":5},{"source":"Bahorel","target":"Courfeyrac","value":6},{"source":"Bahorel","target":"Mabeuf","value":2},{"source":"Bahorel","target":"Enjolras","value":4},{"source":"Bahorel","target":"Feuilly","value":3},{"source":"Bahorel","target":"Prouvaire","value":2},{"source":"Bahorel","target":"Marius","value":1},{"source":"Bossuet","target":"Marius","value":5},{"source":"Bossuet","target":"Courfeyrac","value":12},{"source":"Bossuet","target":"Gavroche","value":5},{"source":"Bossuet","target":"Bahorel","value":4},{"source":"Bossuet","target":"Enjolras","value":10},{"source":"Bossuet","target":"Feuilly","value":6},{"source":"Bossuet","target":"Prouvaire","value":2},{"source":"Bossuet","target":"Combeferre","value":9},{"source":"Bossuet","target":"Mabeuf","value":1},{"source":"Bossuet","target":"Valjean","value":1},{"source":"Joly","target":"Bahorel","value":5},{"source":"Joly","target":"Bossuet","value":7},{"source":"Joly","target":"Gavroche","value":3},{"source":"Joly","target":"Courfeyrac","value":5},{"source":"Joly","target":"Enjolras","value":5},{"source":"Joly","target":"Feuilly","value":5},{"source":"Joly","target":"Prouvaire","value":2},{"source":"Joly","target":"Combeferre","value":5},{"source":"Joly","target":"Mabeuf","value":1},{"source":"Joly","target":"Marius","value":2},{"source":"Grantaire","target":"Bossuet","value":3},{"source":"Grantaire","target":"Enjolras","value":3},{"source":"Grantaire","target":"Combeferre","value":1},{"source":"Grantaire","target":"Courfeyrac","value":2},{"source":"Grantaire","target":"Joly","value":2},{"source":"Grantaire","target":"Gavroche","value":1},{"source":"Grantaire","target":"Bahorel","value":1},{"source":"Grantaire","target":"Feuilly","value":1},{"source":"Grantaire","target":"Prouvaire","value":1},{"source":"MotherPlutarch","target":"Mabeuf","value":3},{"source":"Gueulemer","target":"Thenardier","value":5},{"source":"Gueulemer","target":"Valjean","value":1},{"source":"Gueulemer","target":"Mme.Thenardier","value":1},{"source":"Gueulemer","target":"Javert","value":1},{"source":"Gueulemer","target":"Gavroche","value":1},{"source":"Gueulemer","target":"Eponine","value":1},{"source":"Babet","target":"Thenardier","value":6},{"source":"Babet","target":"Gueulemer","value":6},{"source":"Babet","target":"Valjean","value":1},{"source":"Babet","target":"Mme.Thenardier","value":1},{"source":"Babet","target":"Javert","value":2},{"source":"Babet","target":"Gavroche","value":1},{"source":"Babet","target":"Eponine","value":1},{"source":"Claquesous","target":"Thenardier","value":4},{"source":"Claquesous","target":"Babet","value":4},{"source":"Claquesous","target":"Gueulemer","value":4},{"source":"Claquesous","target":"Valjean","value":1},{"source":"Claquesous","target":"Mme.Thenardier","value":1},{"source":"Claquesous","target":"Javert","value":1},{"source":"Claquesous","target":"Eponine","value":1},{"source":"Claquesous","target":"Enjolras","value":1},{"source":"Montparnasse","target":"Javert","value":1},{"source":"Montparnasse","target":"Babet","value":2},{"source":"Montparnasse","target":"Gueulemer","value":2},{"source":"Montparnasse","target":"Claquesous","value":2},{"source":"Montparnasse","target":"Valjean","value":1},{"source":"Montparnasse","target":"Gavroche","value":1},{"source":"Montparnasse","target":"Eponine","value":1},{"source":"Montparnasse","target":"Thenardier","value":1},{"source":"Toussaint","target":"Cosette","value":2},{"source":"Toussaint","target":"Javert","value":1},{"source":"Toussaint","target":"Valjean","value":1},{"source":"Child1","target":"Gavroche","value":2},{"source":"Child2","target":"Gavroche","value":2},{"source":"Child2","target":"Child1","value":3},{"source":"Brujon","target":"Babet","value":3},{"source":"Brujon","target":"Gueulemer","value":3},{"source":"Brujon","target":"Thenardier","value":3},{"source":"Brujon","target":"Gavroche","value":1},{"source":"Brujon","target":"Eponine","value":1},{"source":"Brujon","target":"Claquesous","value":1},{"source":"Brujon","target":"Montparnasse","value":1},{"source":"Mme.Hucheloup","target":"Bossuet","value":1},{"source":"Mme.Hucheloup","target":"Joly","value":1},{"source":"Mme.Hucheloup","target":"Grantaire","value":1},{"source":"Mme.Hucheloup","target":"Bahorel","value":1},{"source":"Mme.Hucheloup","target":"Courfeyrac","value":1},{"source":"Mme.Hucheloup","target":"Gavroche","value":1},{"source":"Mme.Hucheloup","target":"Enjolras","value":1}]}
body {
text-align: center;
font-family: Sans-serif;
margin: 0;
}
.graph-data {
position: absolute;
top: 0px;
right: 0px;
padding: 5px;
}
.toggle-data-btn {
cursor: pointer;
opacity: 0.85;
}
.toggle-data-btn:hover {
opacity: 1;
}
#graph-data-description {
font-size: 12px;
color: slategrey;
}