Skip to content

Instantly share code, notes, and snippets.

@ngopal
Created December 1, 2014 05:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ngopal/f552b61685c02763141e to your computer and use it in GitHub Desktop.
Save ngopal/f552b61685c02763141e to your computer and use it in GitHub Desktop.
Degree Centrality based force-layout // source http://jsbin.com/fijefe
<!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>
.node {
stroke: #fff;
stroke-width: 1px;
}
.link {
stroke: #999;
stroke-opacity: .6;
}
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