Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<pre>
_ ____ _
__ _ _ __ __ _ _ __ | |__ / ___| _ _| |__
/ _` | '__/ _` | '_ \| '_ \\___ \| | | | '_ \
_ ____ _
__ _ _ __ __ _ _ __ | |__ / ___| _ _| |__
/ _` | '__/ _` | '_ \| '_ \\___ \| | | | '_ \
| (_| | | | (_| | |_) | | | |___) | |_| | |_) |
\__, |_| \__,_| .__/|_| |_|____/ \__,_|_.__/
|___/ |_|
\__, |_| \__,_| .__/|_| |_|____/ \__,_|_.__/
|___/ |_|
</pre>

graphSub is a Javasctipt module for extracting
graphSub is a Javascript module for extracting
a subset of a larger graph defined as per the
force directed graph examples given in d3js.
137 changes: 137 additions & 0 deletions ramzaneh.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
<!DOCTYPE html>
<meta charset="utf-8">
<style>

.node {
stroke: #fff;
stroke-width: 1.5px;
}

.link {
stroke: #999;
stroke-opacity: .6;
}

</style>
<body>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script>

var width = 960,
height = 500;

var 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 buildLinksFromNodeIds = function(nodeIds, links) {
var indexById = _.reduce(nodeIds, function(m, v, i) { m[v] = i; return m; }, {})

return _.map(links, function(v) {
return {source: indexById[v.source], target: indexById[v.target]};
});
};

// Inputs:
// nodes . . [{id: ###, ..}, ..]
// links . . [{target: node.id, ..}, ..]
//
// Output:
// nodes . . <minimal subset of nodes>
// links . . [{source: i, target: j}, ..] (unique links)
var formatGraphForD3 = function(nodes, links) {
links = _.uniq(links);
var linkedNodeIds = _.chain(links)
.map(function(v) { return [v.source, v.target]; })
.flatten()
.uniq()
.value();

links = buildLinksFromNodeIds(linkedNodeIds, links);
var indexById = _.reduce(nodes, function(m, v, i) { m[v.id] = i; return m; }, {});
var linkedNodes = _.map(linkedNodeIds, function(i) {
return nodes[indexById[i]];
});

return { nodes: linkedNodes, links: links };
};

// Build out a D3-ready subgraph
//
// Inputs:
// nodes . . . [{id: ###, ..}, ..]
// links . . . [{target: node.id, ..}, ..]
// rootId . . . root node id
// distance . . number of connections to build out
//
// Output:
// nodes . . <minimal subset of nodes>
// links . . [{source: i, target: j}, ..] (unique links)
var buildSubGraph = function(nodes, links, rootId, distance) {
var sourceLinks = [{source: rootId, target: rootId}];

// A really naive algorithm: we're not yet worrying
// too much about optimising for already-visited links.
var subGraphLinks = [];
for (var i = 0; i < distance; ++i) {
var targetLinks = _.reduce(sourceLinks, function(m, v) {
m = m.concat(_.where(links, {source: v.target}));
return m;
}, []);
subGraphLinks = subGraphLinks.concat(targetLinks);
sourceLinks = targetLinks;
}

return formatGraphForD3(nodes, subGraphLinks);
};

var test = function(n, i){
console.log('Node: ' + JSON.stringify({id: n.id, label: n.label}), i);
};

d3.json("data/ramzaneh.json", function(error, graph) {
var subGraph = buildSubGraph(graph.nodes, graph.edges, '27', 3);

force
.nodes(subGraph.nodes)
.links(subGraph.links)
.start();

var link = svg.selectAll(".link")
.data(subGraph.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(d.value); });

var node = svg.selectAll(".node")
.data(subGraph.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", 5)
.style("fill", function(d) { return color(d.group); })
.on('click', test)
.call(force.drag);

node.append("title")
.text(function(d) { return d.label; });

force.on("tick", function() {
link.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });

node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
});
});

</script>
12 changes: 6 additions & 6 deletions static/js/graphSub.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ var makeSubLinksArr = function(subNodes, propname, subLinks){
var graphSub = function(datum, propname, distanceToFetch, links, nodes){
console.log(arguments);
// this function looks at the distance from the source nodes
// it expands outwards, distance times. this is equivelent
// it expands outwards, distance times. this is equivalent
// to 'distance' in graph theory.

// the algorithim here is concerned with collecting the links making up paths
Expand All @@ -74,17 +74,17 @@ var graphSub = function(datum, propname, distanceToFetch, links, nodes){
current = toVisit.pop(toVisit);

for (var i = 0; i < links.length; i++) {

if(links[i].source[propname] === current){
// dont store if present, uses underscore.js union
subLinks = _.union([links[i]], subLinks);
subLinks = _.union([links[i]], subLinks);
toVisit = _.union([links[i].target[propname]], toVisit);
visited = _.union([links[i].target[propname]], visited);
};

if(links[i].target[propname] === current){
// dont store if present, uses underscore.js union
subLinks = _.union([links[i]], subLinks);
subLinks = _.union([links[i]], subLinks);
toVisit = _.union([links[i].source[propname]], toVisit);
visited = _.union([links[i].source[propname]], visited);
};
Expand All @@ -93,10 +93,10 @@ var graphSub = function(datum, propname, distanceToFetch, links, nodes){
count = count + 1;
};

console.log('i just vistited-> ', visited);
console.log('i just visited-> ', visited);
result.nodes = makeSubNodesArr(visited, propname, nodes);
result.links = makeSubLinksArr(result.nodes, propname, subLinks)
console.log('final ', JSON.stringify(result));

return result;
};
};
104 changes: 56 additions & 48 deletions static/tests/graphSubTests.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,65 +12,65 @@
<script src="../js/underscore-min.js"></script>
<script src="../js/graphSub.js" charset="utf-8"></script>
<script>
QUnit.module("graphSub function Unit Test", {
setup: function() {
QUnit.module("graphSub function Unit Test", {
setup: function() {
// vars to be used by all tests
this.testNodes = [
{"name":"a"},
{"name":"b"},
{"name":"c"},
{"name":"d"},
{"name":"e"},
{"name":"f"},
{"name":"g"},
{"name":"h"},
{"name":"i"},
{"name":"j"},
{"name":"k"},
{"name":"l"},
{"name":"m"},
{"name":"n"}
{"name":"a"},
{"name":"b"},
{"name":"c"},
{"name":"d"},
{"name":"e"},
{"name":"f"},
{"name":"g"},
{"name":"h"},
{"name":"i"},
{"name":"j"},
{"name":"k"},
{"name":"l"},
{"name":"m"},
{"name":"n"}
];

this.testLinks = [
{"source":0,"target":1,"value":1},
{"source":2,"target":3,"value":1},
{"source":4,"target":5,"value":1},
{"source":7,"target":8,"value":1},
{"source":9,"target":10,"value":1},
{"source":11,"target":12,"value":1},
{"source":0,"target":5,"value":1},
{"source":1,"target":5,"value":1},
{"source":0,"target":6,"value":1},
{"source":1,"target":6,"value":1},
{"source":0,"target":7,"value":1},
{"source":1,"target":7,"value":1},
{"source":2,"target":8,"value":1},
{"source":3,"target":8,"value":1},
{"source":2,"target":9,"value":1},
{"source":3,"target":9,"value":1},
{"source":4,"target":11,"value":1},
{"source":5,"target":11,"value":1},
{"source":9,"target":12,"value":1},
{"source":10,"target":12,"value":1},
{"source":11,"target":13,"value":1},
{"source":12,"target":13,"value":1}
];
{"source":0,"target":1,"value":1},
{"source":2,"target":3,"value":1},
{"source":4,"target":5,"value":1},
{"source":7,"target":8,"value":1},
{"source":9,"target":10,"value":1},
{"source":11,"target":12,"value":1},
{"source":0,"target":5,"value":1},
{"source":1,"target":5,"value":1},
{"source":0,"target":6,"value":1},
{"source":1,"target":6,"value":1},
{"source":0,"target":7,"value":1},
{"source":1,"target":7,"value":1},
{"source":2,"target":8,"value":1},
{"source":3,"target":8,"value":1},
{"source":2,"target":9,"value":1},
{"source":3,"target":9,"value":1},
{"source":4,"target":11,"value":1},
{"source":5,"target":11,"value":1},
{"source":9,"target":12,"value":1},
{"source":10,"target":12,"value":1},
{"source":11,"target":13,"value":1},
{"source":12,"target":13,"value":1}
];
}
});

QUnit.test( "# of generations is 0", function( assert ) {
QUnit.test( "# of generations is 0", function( assert ) {
//var fixture = $( "#qunit-fixture" );
var n;
var actual,
expected,
message;
/*

actual = graphSub(this.testNodes[0], "name", n, this.testLinks, this.testNodes);
expected = {nodes: [{'name': 'a'}], links: []};
message = 'sub network from a when n = 0';
assert.deepEqual(actual, expected, message);
/*

actual = graphSub(this.testNodes[1], "name", n, this.testLinks, this.testNodes);
expected = {nodes: [{'name': 'b'}], links: []};
message = 'sub network from b when n = 0';
Expand All @@ -80,17 +80,25 @@
expected = {nodes: [{'name': 'c'}], links: []};
message = 'sub network from c when n = 0';
assert.deepEqual(actual, expected, message);
*/
///*
});

QUnit.test( "# of generations is 1", function( assert ) {
n = 1;

actual = graphSub(this.testNodes[0], "name", n, this.testLinks, this.testNodes);
expected = {"nodes":[{"name":"h"},{"name":"g"},{"name":"f"},{"name":"b"},{"name":"a"}],"links":[{"source":4,"target":0,"value":1},{"source":4,"target":1,"value":1},{"source":4,"target":2,"value":1},{"source":4,"target":3,"value":1}]};
expected = {
"nodes": [{"name":"h"},{"name":"g"},{"name":"f"},{"name":"b"},{"name":"a"}],
"links": [
{"source":4,"target":0,"value":1},
{"source":4,"target":1,"value":1},
{"source":4,"target":2,"value":1},
{"source":4,"target":3,"value":1}
]
};
message = 'sub network from a when n = 1';
assert.deepEqual(actual, expected, message);
//*/
});

</script>
</body>
</html>
</html>