Created
December 1, 2014 05:41
-
-
Save ngopal/f552b61685c02763141e to your computer and use it in GitHub Desktop.
Degree Centrality based force-layout // source http://jsbin.com/fijefe
This file contains 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 characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta name="description" content="Degree Centrality based force-layout" /> | |
<script src="http://code.jquery.com/jquery-2.1.0.min.js"></script> | |
<meta charset="utf-8"> | |
<title>JS Bin</title> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
<script src="http://jsbin.com/xiyehe/1.js"></script> | |
<style id="jsbin-css"> | |
.node { | |
stroke: #fff; | |
stroke-width: 1px; | |
} | |
.link { | |
stroke: #999; | |
stroke-opacity: .6; | |
} | |
</style> | |
</head> | |
<body> | |
<script id="jsbin-javascript"> | |
var color, doit, force, height, svg, width; | |
width = 660; | |
height = 500; | |
color = d3.scale.category20(); | |
var force = d3.layout.force() | |
.charge(-120) | |
.linkDistance(30) | |
.size([width, height]); | |
var svg = d3.select("body") | |
.append("svg") | |
.attr("width", width) | |
.attr("height", height); | |
var degreeCent = function(g) { | |
var counts; | |
var total = 0; | |
counts = {}; | |
// Figure out which nodes have most links | |
g.links.forEach(function(i) { | |
if (counts[i["source"]]) { | |
counts[i["source"]] += 1; | |
} | |
else { | |
counts[i["source"]] = 1; | |
} | |
if (counts[i["target"]]) { | |
counts[i["target"]] += 1; | |
} | |
else { | |
counts[i["target"]] = 1; | |
} | |
total += 1; | |
}); | |
return counts; | |
}; | |
//Median | |
//https://gist.github.com/caseyjustus/1166258 | |
function median(values) { | |
values.sort( function(a,b) { | |
return a - b; | |
} ); | |
var half = Math.floor(values.length/2); | |
if(values.length % 2) { | |
return values[half]; | |
} | |
else { | |
return (values[half-1] + values[half]); | |
} | |
} | |
// Returns a function to compute the interquartile range. | |
function iqr(k) { | |
return function(d, i) { | |
var q1 = d.quartiles[0], | |
q3 = d.quartiles[2], | |
iqr = (q3 - q1) * k, | |
i = -1, | |
j = d.length; | |
while (d[++i] < q1 - iqr); | |
while (d[--j] > q3 + iqr); | |
return [i, j]; | |
}; | |
} | |
function iqqr(k) { | |
var medival = median(k); | |
var q1 = k.filter(function(d) { | |
return d < medival; | |
}); | |
var q3 = k.filter(function(d) { | |
return d > medival; | |
}); | |
var q1vals = median(q1); | |
var q3vals = median(q3); | |
var iqrange = q3vals - q1vals; | |
return [q1vals, medival, q3vals]; | |
} | |
function determineSpace(gn) { | |
console.log(gn.length); | |
console.log(width); | |
var dist = (width) / gn.length; | |
var spaces = []; | |
var current = 0; | |
for (var i = 0; i < gn.length;i++) { | |
spaces.push([current,current+dist]); | |
current = current+dist; | |
} | |
return spaces; | |
} | |
function createXranges(thing,space) { | |
var indexToRange = {} | |
// create sorted list of tuples | |
//http://stackoverflow.com/questions/1069666/sorting-javascript-object-by-property-value | |
var sortable = []; | |
for (var vehicle in thing) { | |
sortable.push([vehicle,thing[vehicle]]); | |
} | |
sortable.sort(function(a, b) { | |
return a[1] - b[1]; | |
}); | |
for (var k = 0; k < sortable.length;k++) { | |
indexToRange[+sortable[k][0]] = space[k]; | |
} | |
return indexToRange; | |
} | |
function boundNodes(num,range) { | |
if (range === undefined) { | |
return num; | |
} | |
if (num >= range[0]) { | |
if (num <= range[1]) { | |
return num; | |
} | |
else { | |
return range[1]; | |
} | |
} | |
else { | |
return range[0]; | |
} | |
} | |
d3.json("http://jsbin.com/hejef/3.js", function(error, graph) { | |
console.log(graph.nodes); | |
console.log(graph.nodes.length); | |
var link, node; | |
var degs = degreeCent(graph); | |
console.log(degs); | |
var degvalues = []; | |
for(var i = 0; i < graph.nodes.length;i++) { | |
if (!(degs[i] === undefined)) { | |
degvalues.push(degs[i]); | |
} | |
} | |
var xranges = createXranges(degs, determineSpace(graph.nodes)); | |
console.log(xranges); | |
console.log(degvalues.sort()); | |
var med = median(degvalues); | |
force.nodes(graph.nodes).links(graph.links).start(); | |
link = svg.selectAll(".link") | |
.data(graph.links) | |
.enter() | |
.append("line") | |
.attr("class", "link") | |
.style("stroke-width", function(d) { | |
return Math.sqrt(d.value); | |
}); | |
node = svg.selectAll(".node") | |
.data(graph.nodes) | |
.enter() | |
.append("circle") | |
.attr("class", "node") | |
.attr("r", 5) | |
.style("fill", function(d) { | |
if (degs[d.index] < med) { | |
return color(1); | |
} | |
else if (degs[d.index] > med) { | |
return color(3); | |
} | |
else if (degs[d.index] == med) { | |
return color(2); | |
} | |
else { | |
return color(4); | |
} | |
}).call(force.drag); | |
node.append("title").text(function(d) { | |
return d.name; | |
}); | |
return force.on("tick", function() { | |
link.attr("x1", function(d) { | |
d.source.x = boundNodes(d.source.x, xranges[d.source.index]); | |
return d.source.x; | |
}).attr("y1", function(d) { | |
return d.source.y; | |
}).attr("x2", function(d) { | |
d.target.x = boundNodes(d.target.x, xranges[d.target.index]); | |
return d.target.x; | |
}).attr("y2", function(d) { | |
return d.target.y; | |
}); | |
return node.attr("cx", function(d) { | |
d.x = boundNodes(d.x,xranges[d.index]); | |
return d.x; | |
}).attr("cy", function(d) { | |
return d.y; | |
}); | |
}); | |
}); | |
// Ideas: | |
// Could scale the x-axis to the range of values in the centrality scores list. | |
// Could use discrete number of edges as ticks on the x-axis | |
// | |
// | |
</script> | |
<script id="jsbin-source-css" type="text/css"> | |
.node { | |
stroke: #fff; | |
stroke-width: 1px; | |
} | |
.link { | |
stroke: #999; | |
stroke-opacity: .6; | |
} | |
</script> | |
<script id="jsbin-source-javascript" type="text/javascript">var color, doit, force, height, svg, width; | |
width = 660; | |
height = 500; | |
color = d3.scale.category20(); | |
var force = d3.layout.force() | |
.charge(-120) | |
.linkDistance(30) | |
.size([width, height]); | |
var svg = d3.select("body") | |
.append("svg") | |
.attr("width", width) | |
.attr("height", height); | |
var degreeCent = function(g) { | |
var counts; | |
var total = 0; | |
counts = {}; | |
// Figure out which nodes have most links | |
g.links.forEach(function(i) { | |
if (counts[i["source"]]) { | |
counts[i["source"]] += 1; | |
} | |
else { | |
counts[i["source"]] = 1; | |
} | |
if (counts[i["target"]]) { | |
counts[i["target"]] += 1; | |
} | |
else { | |
counts[i["target"]] = 1; | |
} | |
total += 1; | |
}); | |
return counts; | |
}; | |
//Median | |
//https://gist.github.com/caseyjustus/1166258 | |
function median(values) { | |
values.sort( function(a,b) { | |
return a - b; | |
} ); | |
var half = Math.floor(values.length/2); | |
if(values.length % 2) { | |
return values[half]; | |
} | |
else { | |
return (values[half-1] + values[half]); | |
} | |
} | |
// Returns a function to compute the interquartile range. | |
function iqr(k) { | |
return function(d, i) { | |
var q1 = d.quartiles[0], | |
q3 = d.quartiles[2], | |
iqr = (q3 - q1) * k, | |
i = -1, | |
j = d.length; | |
while (d[++i] < q1 - iqr); | |
while (d[--j] > q3 + iqr); | |
return [i, j]; | |
}; | |
} | |
function iqqr(k) { | |
var medival = median(k); | |
var q1 = k.filter(function(d) { | |
return d < medival; | |
}); | |
var q3 = k.filter(function(d) { | |
return d > medival; | |
}); | |
var q1vals = median(q1); | |
var q3vals = median(q3); | |
var iqrange = q3vals - q1vals; | |
return [q1vals, medival, q3vals]; | |
} | |
function determineSpace(gn) { | |
console.log(gn.length); | |
console.log(width); | |
var dist = (width) / gn.length; | |
var spaces = []; | |
var current = 0; | |
for (var i = 0; i < gn.length;i++) { | |
spaces.push([current,current+dist]); | |
current = current+dist; | |
} | |
return spaces; | |
} | |
function createXranges(thing,space) { | |
var indexToRange = {} | |
// create sorted list of tuples | |
//http://stackoverflow.com/questions/1069666/sorting-javascript-object-by-property-value | |
var sortable = []; | |
for (var vehicle in thing) { | |
sortable.push([vehicle,thing[vehicle]]); | |
} | |
sortable.sort(function(a, b) { | |
return a[1] - b[1]; | |
}); | |
for (var k = 0; k < sortable.length;k++) { | |
indexToRange[+sortable[k][0]] = space[k]; | |
} | |
return indexToRange; | |
} | |
function boundNodes(num,range) { | |
if (range === undefined) { | |
return num; | |
} | |
if (num >= range[0]) { | |
if (num <= range[1]) { | |
return num; | |
} | |
else { | |
return range[1]; | |
} | |
} | |
else { | |
return range[0]; | |
} | |
} | |
d3.json("http://jsbin.com/hejef/3.js", function(error, graph) { | |
console.log(graph.nodes); | |
console.log(graph.nodes.length); | |
var link, node; | |
var degs = degreeCent(graph); | |
console.log(degs); | |
var degvalues = []; | |
for(var i = 0; i < graph.nodes.length;i++) { | |
if (!(degs[i] === undefined)) { | |
degvalues.push(degs[i]); | |
} | |
} | |
var xranges = createXranges(degs, determineSpace(graph.nodes)); | |
console.log(xranges); | |
console.log(degvalues.sort()); | |
var med = median(degvalues); | |
force.nodes(graph.nodes).links(graph.links).start(); | |
link = svg.selectAll(".link") | |
.data(graph.links) | |
.enter() | |
.append("line") | |
.attr("class", "link") | |
.style("stroke-width", function(d) { | |
return Math.sqrt(d.value); | |
}); | |
node = svg.selectAll(".node") | |
.data(graph.nodes) | |
.enter() | |
.append("circle") | |
.attr("class", "node") | |
.attr("r", 5) | |
.style("fill", function(d) { | |
if (degs[d.index] < med) { | |
return color(1); | |
} | |
else if (degs[d.index] > med) { | |
return color(3); | |
} | |
else if (degs[d.index] == med) { | |
return color(2); | |
} | |
else { | |
return color(4); | |
} | |
}).call(force.drag); | |
node.append("title").text(function(d) { | |
return d.name; | |
}); | |
return force.on("tick", function() { | |
link.attr("x1", function(d) { | |
d.source.x = boundNodes(d.source.x, xranges[d.source.index]); | |
return d.source.x; | |
}).attr("y1", function(d) { | |
return d.source.y; | |
}).attr("x2", function(d) { | |
d.target.x = boundNodes(d.target.x, xranges[d.target.index]); | |
return d.target.x; | |
}).attr("y2", function(d) { | |
return d.target.y; | |
}); | |
return node.attr("cx", function(d) { | |
d.x = boundNodes(d.x,xranges[d.index]); | |
return d.x; | |
}).attr("cy", function(d) { | |
return d.y; | |
}); | |
}); | |
}); | |
// Ideas: | |
// Could scale the x-axis to the range of values in the centrality scores list. | |
// Could use discrete number of edges as ticks on the x-axis | |
// | |
// | |
</script></body> | |
</html> |
This file contains 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 characters
.node { | |
stroke: #fff; | |
stroke-width: 1px; | |
} | |
.link { | |
stroke: #999; | |
stroke-opacity: .6; | |
} |
This file contains 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 characters
var color, doit, force, height, svg, width; | |
width = 660; | |
height = 500; | |
color = d3.scale.category20(); | |
var force = d3.layout.force() | |
.charge(-120) | |
.linkDistance(30) | |
.size([width, height]); | |
var svg = d3.select("body") | |
.append("svg") | |
.attr("width", width) | |
.attr("height", height); | |
var degreeCent = function(g) { | |
var counts; | |
var total = 0; | |
counts = {}; | |
// Figure out which nodes have most links | |
g.links.forEach(function(i) { | |
if (counts[i["source"]]) { | |
counts[i["source"]] += 1; | |
} | |
else { | |
counts[i["source"]] = 1; | |
} | |
if (counts[i["target"]]) { | |
counts[i["target"]] += 1; | |
} | |
else { | |
counts[i["target"]] = 1; | |
} | |
total += 1; | |
}); | |
return counts; | |
}; | |
//Median | |
//https://gist.github.com/caseyjustus/1166258 | |
function median(values) { | |
values.sort( function(a,b) { | |
return a - b; | |
} ); | |
var half = Math.floor(values.length/2); | |
if(values.length % 2) { | |
return values[half]; | |
} | |
else { | |
return (values[half-1] + values[half]); | |
} | |
} | |
// Returns a function to compute the interquartile range. | |
function iqr(k) { | |
return function(d, i) { | |
var q1 = d.quartiles[0], | |
q3 = d.quartiles[2], | |
iqr = (q3 - q1) * k, | |
i = -1, | |
j = d.length; | |
while (d[++i] < q1 - iqr); | |
while (d[--j] > q3 + iqr); | |
return [i, j]; | |
}; | |
} | |
function iqqr(k) { | |
var medival = median(k); | |
var q1 = k.filter(function(d) { | |
return d < medival; | |
}); | |
var q3 = k.filter(function(d) { | |
return d > medival; | |
}); | |
var q1vals = median(q1); | |
var q3vals = median(q3); | |
var iqrange = q3vals - q1vals; | |
return [q1vals, medival, q3vals]; | |
} | |
function determineSpace(gn) { | |
console.log(gn.length); | |
console.log(width); | |
var dist = (width) / gn.length; | |
var spaces = []; | |
var current = 0; | |
for (var i = 0; i < gn.length;i++) { | |
spaces.push([current,current+dist]); | |
current = current+dist; | |
} | |
return spaces; | |
} | |
function createXranges(thing,space) { | |
var indexToRange = {} | |
// create sorted list of tuples | |
//http://stackoverflow.com/questions/1069666/sorting-javascript-object-by-property-value | |
var sortable = []; | |
for (var vehicle in thing) { | |
sortable.push([vehicle,thing[vehicle]]); | |
} | |
sortable.sort(function(a, b) { | |
return a[1] - b[1]; | |
}); | |
for (var k = 0; k < sortable.length;k++) { | |
indexToRange[+sortable[k][0]] = space[k]; | |
} | |
return indexToRange; | |
} | |
function boundNodes(num,range) { | |
if (range === undefined) { | |
return num; | |
} | |
if (num >= range[0]) { | |
if (num <= range[1]) { | |
return num; | |
} | |
else { | |
return range[1]; | |
} | |
} | |
else { | |
return range[0]; | |
} | |
} | |
d3.json("http://jsbin.com/hejef/3.js", function(error, graph) { | |
console.log(graph.nodes); | |
console.log(graph.nodes.length); | |
var link, node; | |
var degs = degreeCent(graph); | |
console.log(degs); | |
var degvalues = []; | |
for(var i = 0; i < graph.nodes.length;i++) { | |
if (!(degs[i] === undefined)) { | |
degvalues.push(degs[i]); | |
} | |
} | |
var xranges = createXranges(degs, determineSpace(graph.nodes)); | |
console.log(xranges); | |
console.log(degvalues.sort()); | |
var med = median(degvalues); | |
force.nodes(graph.nodes).links(graph.links).start(); | |
link = svg.selectAll(".link") | |
.data(graph.links) | |
.enter() | |
.append("line") | |
.attr("class", "link") | |
.style("stroke-width", function(d) { | |
return Math.sqrt(d.value); | |
}); | |
node = svg.selectAll(".node") | |
.data(graph.nodes) | |
.enter() | |
.append("circle") | |
.attr("class", "node") | |
.attr("r", 5) | |
.style("fill", function(d) { | |
if (degs[d.index] < med) { | |
return color(1); | |
} | |
else if (degs[d.index] > med) { | |
return color(3); | |
} | |
else if (degs[d.index] == med) { | |
return color(2); | |
} | |
else { | |
return color(4); | |
} | |
}).call(force.drag); | |
node.append("title").text(function(d) { | |
return d.name; | |
}); | |
return force.on("tick", function() { | |
link.attr("x1", function(d) { | |
d.source.x = boundNodes(d.source.x, xranges[d.source.index]); | |
return d.source.x; | |
}).attr("y1", function(d) { | |
return d.source.y; | |
}).attr("x2", function(d) { | |
d.target.x = boundNodes(d.target.x, xranges[d.target.index]); | |
return d.target.x; | |
}).attr("y2", function(d) { | |
return d.target.y; | |
}); | |
return node.attr("cx", function(d) { | |
d.x = boundNodes(d.x,xranges[d.index]); | |
return d.x; | |
}).attr("cy", function(d) { | |
return d.y; | |
}); | |
}); | |
}); | |
// Ideas: | |
// Could scale the x-axis to the range of values in the centrality scores list. | |
// Could use discrete number of edges as ticks on the x-axis | |
// | |
// | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment