Last active
June 6, 2019 10:58
-
-
Save emeeks/625641430adead4bd7dbc9c1ab3f5102 to your computer and use it in GitHub Desktop.
Revisions
-
emeeks revised this gist
Mar 3, 2017 . 1 changed file with 1 addition and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -17,7 +17,6 @@ background-color: white; font-family: 'Lato'; overflow: visible; } line { @@ -84,7 +83,7 @@ </style> </head> <body> <svg width=1000 height=650></svg> <script src="https://d3js.org/d3.v4.js"></script> <script src="bboxCollide.js"></script> <script src="https://cdn.rawgit.com/susielu/d3-annotation/master/d3-annotation.js"></script> -
emeeks revised this gist
Mar 3, 2017 . No changes.There are no files selected for viewing
-
Elijah Meeks created this gist
Mar 3, 2017 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,5 @@ ## Using collision detection with network visualization labels This demonstrates how to use [d3-annotation()](https://github.com/susielu/d3-annotation/) with `bboxCollide` to procedurally place node labels. After using the nodes data to create a network visualization of the Les Miserables play, we filter the nodes to leave out the side characters and pass that array to `d3-annotation`. We then create a second `forceSimulation`, this time using the size of the notes as the property in our bounding box collision detection, to move the labels out of each others' way. `d3-annotation` by [Susie Lu](https://twitter.com/datatoviz). This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,178 @@ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-quadtree')) : typeof define === 'function' && define.amd ? define(['exports', 'd3-quadtree'], factory) : (factory((global.d3 = global.d3 || {}),global.d3)); }(this, function (exports,d3Quadtree) { 'use strict'; function bboxCollide (bbox) { function x (d) { return d.x + d.vx; } function y (d) { return d.y + d.vy; } function constant (x) { return function () { return x; }; } var nodes, boundingBoxes, strength = 1, iterations = 1; if (typeof bbox !== "function") { bbox = constant(bbox === null ? [[0,0][1,1]] : bbox) } function force () { var i, tree, node, xi, yi, bbi, nx1, ny1, nx2, ny2 var cornerNodes = [] nodes.forEach(function (d, i) { cornerNodes.push({node: d, vx: d.vx, vy: d.vy, x: d.x + (boundingBoxes[i][1][0] + boundingBoxes[i][0][0]) / 2, y: d.y + (boundingBoxes[i][0][1] + boundingBoxes[i][1][1]) / 2}) cornerNodes.push({node: d, vx: d.vx, vy: d.vy, x: d.x + boundingBoxes[i][0][0], y: d.y + boundingBoxes[i][0][1]}) cornerNodes.push({node: d, vx: d.vx, vy: d.vy, x: d.x + boundingBoxes[i][0][0], y: d.y + boundingBoxes[i][1][1]}) cornerNodes.push({node: d, vx: d.vx, vy: d.vy, x: d.x + boundingBoxes[i][1][0], y: d.y + boundingBoxes[i][0][1]}) cornerNodes.push({node: d, vx: d.vx, vy: d.vy, x: d.x + boundingBoxes[i][1][0], y: d.y + boundingBoxes[i][1][1]}) }) var cn = cornerNodes.length for (var k = 0; k < iterations; ++k) { tree = d3Quadtree.quadtree(cornerNodes, x, y).visitAfter(prepareCorners); for (i = 0; i < cn; ++i) { var nodeI = ~~(i / 5); node = nodes[nodeI] bbi = boundingBoxes[nodeI] xi = node.x + node.vx yi = node.y + node.vy nx1 = xi + bbi[0][0] ny1 = yi + bbi[0][1] nx2 = xi + bbi[1][0] ny2 = yi + bbi[1][1] tree.visit(apply); } } function apply (quad, x0, y0, x1, y1) { var data = quad.data if (data) { var bWidth = bbLength(bbi, 0), bHeight = bbLength(bbi, 1); if (data.node.index !== nodeI) { var dataNode = data.node var bbj = boundingBoxes[dataNode.index], dnx1 = dataNode.x + dataNode.vx + bbj[0][0], dny1 = dataNode.y + dataNode.vy + bbj[0][1], dnx2 = dataNode.x + dataNode.vx + bbj[1][0], dny2 = dataNode.y + dataNode.vy + bbj[1][1], dWidth = bbLength(bbj, 0), dHeight = bbLength(bbj, 1) if (nx1 <= dnx2 && dnx1 <= nx2 && ny1 <= dny2 && dny1 <= ny2) { var xSize = [Math.min.apply(null, [dnx1, dnx2, nx1, nx2]), Math.max.apply(null, [dnx1, dnx2, nx1, nx2])] var ySize = [Math.min.apply(null, [dny1, dny2, ny1, ny2]), Math.max.apply(null, [dny1, dny2, ny1, ny2])] var xOverlap = bWidth + dWidth - (xSize[1] - xSize[0]) var yOverlap = bHeight + dHeight - (ySize[1] - ySize[0]) var xBPush = xOverlap * strength * (yOverlap / bHeight) var yBPush = yOverlap * strength * (xOverlap / bWidth) var xDPush = xOverlap * strength * (yOverlap / dHeight) var yDPush = yOverlap * strength * (xOverlap / dWidth) if ((nx1 + nx2) / 2 < (dnx1 + dnx2) / 2) { node.vx -= xBPush dataNode.vx += xDPush } else { node.vx += xBPush dataNode.vx -= xDPush } if ((ny1 + ny2) / 2 < (dny1 + dny2) / 2) { node.vy -= yBPush dataNode.vy += yDPush } else { node.vy += yBPush dataNode.vy -= yDPush } } } return; } return x0 > nx2 || x1 < nx1 || y0 > ny2 || y1 < ny1; } } function prepareCorners (quad) { if (quad.data) { return quad.bb = boundingBoxes[quad.data.node.index] } quad.bb = [[0,0],[0,0]] for (var i = 0; i < 4; ++i) { if (quad[i] && quad[i].bb[0][0] < quad.bb[0][0]) { quad.bb[0][0] = quad[i].bb[0][0] } if (quad[i] && quad[i].bb[0][1] < quad.bb[0][1]) { quad.bb[0][1] = quad[i].bb[0][1] } if (quad[i] && quad[i].bb[1][0] > quad.bb[1][0]) { quad.bb[1][0] = quad[i].bb[1][0] } if (quad[i] && quad[i].bb[1][1] > quad.bb[1][1]) { quad.bb[1][1] = quad[i].bb[1][1] } } } function bbLength (bbox, heightWidth) { return bbox[1][heightWidth] - bbox[0][heightWidth] } force.initialize = function (_) { var i, n = (nodes = _).length; boundingBoxes = new Array(n); for (i = 0; i < n; ++i) boundingBoxes[i] = bbox(nodes[i], i, nodes); }; force.iterations = function (_) { return arguments.length ? (iterations = +_, force) : iterations; }; force.strength = function (_) { return arguments.length ? (strength = +_, force) : strength; }; force.bbox = function (_) { return arguments.length ? (bbox = typeof _ === "function" ? _ : constant(+_), force) : bbox; }; return force; } exports.bboxCollide = bboxCollide; Object.defineProperty(exports, '__esModule', { value: true }); })); This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,207 @@ <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <link href='https://fonts.googleapis.com/css?family=Lato:300,900' rel='stylesheet' type='text/css'> <style> :root { --annotation-color: #e91e56; } body{ background-color: whitesmoke; } svg { background-color: white; font-family: 'Lato'; overflow: visible; margin-top: 100px; } line { stroke:#e3e3e3; } .editable .annotation-subject, .editable .annotation-textbox { cursor: move; } .line { fill: none; stroke: black; stroke-width: 1px; } .annotation path { stroke: var(--annotation-color); fill: rgba(0,0,0,0); } .annotation path.connector-arrow{ fill: var(--annotation-color); } .annotation text { fill: var(--annotation-color); } .annotation-title { font-weight: bold; } .annotation .annotation-subject circle.handle { display: none; } .annotation-note-bg { fill: rgba(255, 255, 255, 0); } circle.handle { stroke-dasharray: 5; stroke: grey; fill: rgba(255, 255, 255, 0); cursor: move; stroke-opacity: .4; } circle.handle.highlight { stroke-opacity: 1; } .annotation.major { font-weight: 900; font-size: 1em; } .annotation-note-label tspan { text-anchor: middle; } </style> </head> <body> <svg width=960 height=960></svg> <script src="https://d3js.org/d3.v4.js"></script> <script src="bboxCollide.js"></script> <script src="https://cdn.rawgit.com/susielu/d3-annotation/master/d3-annotation.js"></script> <script> var svg = d3.select("svg"), width = +svg.attr("width"), height = +svg.attr("height"); var color = d3.scaleOrdinal(d3.schemeCategory20) .range(["#e91e56", "#00965f", "#00bcd4", "#3f51b5", "#9c27b0", "#ff5722", "#cddc39", "#607d8b", "#8bc34a"]); var simulation = d3.forceSimulation() .force("link", d3.forceLink().id( d => d.id )) .force("charge", d3.forceManyBody().strength(-80)) .force("center", d3.forceCenter(width / 2, height / 2)); d3.json("miserables.json", function(error, graph) { if (error) throw error; var link = svg.append("g") .attr("class", "links") .selectAll("line") .data(graph.links) .enter().append("line") .attr("stroke-width", d => Math.sqrt(d.value)); var node = svg.append("g") .attr("class", "nodes") .selectAll("circle") .data(graph.nodes) .enter().append("circle") .attr("r", d => d.type === "major" ? 9 : 3) .style("fill", d => d3.hsl(color(d.group)).darker()) .style("fill-opacity", d => d.type === "other" ? 0.5 : 1) node.append("title") .text(d => d.id); window.collide = d3.bboxCollide((a) => { return [[a.offsetCornerX - 5, a.offsetCornerY - 10],[a.offsetCornerX + a.width + 5, a.offsetCornerY + a.height+ 5]] }) .strength(0.5) .iterations(1) window.yScale = d3.scaleLinear() simulation .nodes(graph.nodes) .on("tick", ticked) .on("end", function() { const noteBoxes = makeAnnotations.collection().noteNodes window.labelForce = d3.forceSimulation(noteBoxes) .force("x", d3.forceX(a => a.positionX).strength(a => Math.max(0.25, Math.min(3, Math.abs(a.x - a.positionX) / 20)))) .force("y", d3.forceY(a => a.positionY).strength(a => Math.max(0.25, Math.min(3, Math.abs(a.x - a.positionX) / 20)))) .force("collision", window.collide) .alpha(0.5) .on('tick', d => { makeAnnotations.annotations() .forEach((d, i) => { const match = noteBoxes[i] d.dx = match.x - match.positionX d.dy = match.y - match.positionY }) makeAnnotations.update() }) }) const nonOtherNodes = graph.nodes .filter(d => d.type !== "other") simulation.force("link") .links(graph.links); function ticked() { link .attr("x1", d => d.source.x) .attr("y1", d => d.source.y) .attr("x2", d => d.target.x) .attr("y2", d => d.target.y); node .attr("cx", d => d.x) .attr("cy", d => d.y); makeAnnotations.annotations() .forEach((d, i) => { d.position = nonOtherNodes[i] }) } window.makeAnnotations = d3.annotation() .type(d3.annotationLabel) .annotations(nonOtherNodes .map((d,i) => { return { data: {x: d.x, y: d.y, group: d.group}, note: { label: d.id, align: "middle", orientation: "fixed" }, connector: { type: "elbow"}, className: d.type } })) .accessors({ x: d => d.x , y: d => d.y}) svg.append("g") .attr("class", "annotation-test") .call(makeAnnotations) svg.selectAll(".annotation-note text") .style("fill", d => color(d.data.group)) svg.selectAll(".annotation-connector > path") .style("stroke", (d,i) => color(d.data.group)) }); </script> </body> </html> This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,337 @@ { "nodes": [ { "type": "minor", "id": "Myriel", "group": 1}, { "type": "other", "id": "Napoleon", "group": 1}, { "type": "other", "id": "Mlle.Baptistine", "group": 1}, { "type": "other", "id": "Mme.Magloire", "group": 1}, { "type": "other", "id": "CountessdeLo", "group": 1}, { "type": "other", "id": "Geborand", "group": 1}, { "type": "other", "id": "Champtercier", "group": 1}, { "type": "other", "id": "Cravatte", "group": 1}, { "type": "other", "id": "Count", "group": 1}, { "type": "other", "id": "OldMan", "group": 1}, { "type": "other", "id": "Labarre", "group": 2}, { "type": "major", "id": "Valjean", "group": 2}, { "type": "other", "id": "Marguerite", "group": 3}, { "type": "other", "id": "Mme.deR", "group": 2}, { "type": "other", "id": "Isabeau", "group": 2}, { "type": "other", "id": "Gervais", "group": 2}, { "type": "minor", "id": "Tholomyes", "group": 3}, { "type": "other", "id": "Listolier", "group": 3}, { "type": "other", "id": "Fameuil", "group": 3}, { "type": "other", "id": "Blacheville", "group": 3}, { "type": "other", "id": "Favourite", "group": 3}, { "type": "other", "id": "Dahlia", "group": 3}, { "type": "other", "id": "Zephine", "group": 3}, { "type": "major", "id": "Fantine", "group": 3}, { "type": "major", "id": "Mme.Thenardier", "group": 4}, { "type": "major", "id": "Thenardier", "group": 4}, { "type": "major", "id": "Cosette", "group": 5}, { "type": "major", "id": "Javert", "group": 4}, { "type": "minor", "id": "Fauchelevent", "group": 0}, { "type": "minor", "id": "Bamatabois", "group": 2}, { "type": "other", "id": "Perpetue", "group": 3}, { "type": "minor", "id": "Simplice", "group": 2}, { "type": "other", "id": "Scaufflaire", "group": 2}, { "type": "other", "id": "Woman1", "group": 2}, { "type": "other", "id": "Judge", "group": 2}, { "type": "minor", "id": "Champmathieu", "group": 2}, { "type": "minor", "id": "Brevet", "group": 2}, { "type": "minor", "id": "Chenildieu", "group": 2}, { "type": "minor", "id": "Cochepaille", "group": 2}, { "type": "minor", "id": "Pontmercy", "group": 4}, { "type": "other", "id": "Boulatruelle", "group": 6}, { "type": "major", "id": "Eponine", "group": 4}, { "type": "other", "id": "Anzelma", "group": 4}, { "type": "other", "id": "Woman2", "group": 5}, { "type": "minor", "id": "MotherInnocent", "group": 0}, { "type": "other", "id": "Gribier", "group": 0}, { "type": "other", "id": "Jondrette", "group": 7}, { "type": "other", "id": "Mme.Burgon", "group": 7}, { "type": "major", "id": "Gavroche", "group": 8}, { "type": "minor", "id": "Gillenormand", "group": 5}, { "type": "minor", "id": "Magnon", "group": 5}, { "type": "minor", "id": "Mlle.Gillenormand", "group": 5}, { "type": "other", "id": "Mme.Pontmercy", "group": 5}, { "type": "other", "id": "Mlle.Vaubois", "group": 5}, { "type": "other", "id": "Lt.Gillenormand", "group": 5}, { "type": "major", "id": "Marius", "group": 8}, { "type": "other", "id": "BaronessT", "group": 5}, { "type": "minor", "id": "Mabeuf", "group": 8}, { "type": "abc", "id": "Enjolras", "group": 8}, { "type": "abc", "id": "Combeferre", "group": 8}, { "type": "abc", "id": "Prouvaire", "group": 8}, { "type": "abc", "id": "Feuilly", "group": 8}, { "type": "abc", "id": "Courfeyrac", "group": 8}, { "type": "other", "id": "Bahorel", "group": 8}, { "type": "other", "id": "Bossuet", "group": 8}, { "type": "abc", "id": "Joly", "group": 8}, { "type": "abc", "id": "Grantaire", "group": 8}, { "type": "other", "id": "MotherPlutarch", "group": 9}, { "type": "other", "id": "Gueulemer", "group": 4}, { "type": "other", "id": "Babet", "group": 4}, { "type": "other", "id": "Claquesous", "group": 4}, { "type": "other", "id": "Montparnasse", "group": 4}, { "type": "minor", "id": "Toussaint", "group": 5}, { "type": "other", "id": "Child1", "group": 10}, { "type": "other", "id": "Child2", "group": 10}, { "type": "minor", "id": "Brujon", "group": 4}, { "type": "other", "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} ] } LoadingSorry, something went wrong. Reload?Sorry, we cannot display this file.Sorry, this file is invalid so it cannot be displayed.