Skip to content

Instantly share code, notes, and snippets.

@emeeks
Last active March 18, 2016 03:31
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 emeeks/91e3737e8e6c02cd31f2 to your computer and use it in GitHub Desktop.
Save emeeks/91e3737e8e6c02cd31f2 to your computer and use it in GitHub Desktop.
Ch. 6, Fig. 21 - D3.js in Action

This is the code for Chapter 6, Figure 21 from D3.js in Action exposing a variety of useful network visualization functions explored throughout the chapter here assigned to a series of buttons.

source target weight
sam pris 1
roy pris 5
roy sam 1
tully pris 5
tully kim 3
tully pat 1
tully mo 3
kim pat 2
kim mo 1
mo tully 7
mo pat 1
mo pris 1
pat tully 1
pat kim 2
pat mo 5
lee al 3
<html>
<head>
<title>D3 in Action Chapter 6 - Example 4</title>
<meta charset="utf-8" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script src="https://d3js.org/queue.v1.min.js" type="text/JavaScript"></script>
</head>
<style>
svg {
height: 500px;
width: 500px;
border: 1px solid gray;
}
</style>
<body>
<div id="controls"></div>
<div id="viz">
<svg>
</svg>
</div>
</body>
<footer>
<script>
var marker = d3.select("svg").append('defs')
.append('marker')
.attr("id", "Triangle")
.attr("refX", 12)
.attr("refY", 6)
.attr("markerUnits", 'userSpaceOnUse')
.attr("markerWidth", 12)
.attr("markerHeight", 18)
.attr("orient", 'auto')
.append('path')
.attr("d", 'M 0 0 12 6 0 12 3 6');
queue()
.defer(d3.csv, "nodelist.csv")
.defer(d3.csv, "edgelist.csv")
.await(function(error, file1, file2) { createForceLayout(file1, file2); });
function createForceLayout(nodes,edges) {
var nodeHash = {};
for (x in nodes) {
nodeHash[nodes[x].id] = nodes[x];
}
for (x in edges) {
edges[x].weight = parseInt(edges[x].weight);
edges[x].source = nodeHash[edges[x].source];
edges[x].target = nodeHash[edges[x].target];
}
// chargeScale = d3.scale.linear().domain(d3.extent(nodes, function(d) {return d.followers})).range([-500,-2000])
// nodeSize = d3.scale.linear().domain(d3.extent(nodes, function(d) {return d.followers})).range([5,20])
var weightScale = d3.scale.linear().domain(d3.extent(edges, function(d) {return d.weight})).range([.1,1])
force = d3.layout.force()
// .charge(-1000)
.charge(function (d) {return d.weight * -500})
.gravity(.3)
// .linkDistance(50)
// .linkStrength(function (d) {return weightScale(d.weight)})
.size([500,500]).nodes(nodes)
.links(edges).on("tick", forceTick);
d3.select("svg").selectAll("line.link").data(edges, function (d) {return d.source.id + "-" + d.target.id}).enter()
.append("line")
.attr("class", "link")
.style("stroke", "black")
.style("opacity", .5)
.style("stroke-width", function(d) {return d.weight});
var nodeEnter = d3.select("svg").selectAll("g.node").data(nodes, function (d) {return d.id}).enter()
.append("g")
.attr("class", "node")
.call(force.drag())
.on("click", fixNode);
function fixNode(d) {
d3.select(this).select("circle").style("stroke-width", 4);
d.fixed = true;
}
nodeEnter.append("circle")
.attr("r", 5)
.style("fill", "lightgray")
.style("stroke", "black")
.style("stroke-width", "1px");
nodeEnter.append("text")
.style("text-anchor", "middle")
.attr("y", 15)
.text(function(d) {return d.id})
d3.selectAll("line").attr("marker-end", "url(#Triangle)");
force.start();
function forceTick() {
d3.selectAll("line.link")
.attr("x1", function (d) {return d.source.x})
.attr("x2", function (d) {return d.target.x})
.attr("y1", function (d) {return d.source.y})
.attr("y2", function (d) {return d.target.y});
d3.selectAll("g.node")
.attr("transform", function (d) {return "translate("+d.x+","+d.y+")"})
}
}
d3.select("#controls").append("button").on("click", sizeByDegree).html("Degree Size");
d3.select("#controls").append("button").on("click", filterNetwork).html("Filter Network");
d3.select("#controls").append("button").on("click", addEdge).html("Add Edge");
d3.select("#controls").append("button").on("click", addNodesAndEdges).html("Add Nodes & Edges");
d3.select("#controls").append("button").on("click", moveNodes).html("Scatterplot");
function sizeByDegree() {
force.stop();
d3.selectAll("circle")
.attr("r", function(d) {return d.weight * 2})
}
function filterNetwork() {
force.stop()
originalNodes = force.nodes();
originalLinks = force.links();
influentialNodes = originalNodes.filter(function (d) {return d.followers > 20});
influentialLinks = originalLinks.filter(function (d) {return influentialNodes.indexOf(d.source) > -1 && influentialNodes.indexOf(d.target) > -1});
d3.selectAll("g.node")
.data(influentialNodes, function (d) {return d.id})
.exit()
.transition()
.duration(12000)
.style("opacity", 0)
.remove();
d3.selectAll("line.link")
.data(influentialLinks, function (d) {return d.source.id + "-" + d.target.id})
.exit()
.transition()
.duration(9000)
.style("opacity", 0)
.remove();
force
.nodes(influentialNodes)
.links(influentialLinks)
force.start()
}
function addEdge() {
force.stop();
var oldEdges = force.links();
var nodes = force.nodes();
newEdge = {source: nodes[0], target: nodes[8], weight: 5};
oldEdges.push(newEdge);
force.links(oldEdges);
d3.select("svg").selectAll("line.link")
.data(oldEdges, function(d) {return d.source.id + "-" + d.target.id})
.enter()
.insert("line", "g.node")
.attr("class", "link")
.style("stroke", "red")
.style("stroke-width", 5)
.attr("marker-end", "url(#Triangle)");
force.start();
}
function addNodesAndEdges() {
force.stop();
var oldEdges = force.links();
var oldNodes = force.nodes();
newNode1 = {id: "raj", followers: 100, following: 67};
newNode2 = {id: "wu", followers: 50, following: 33};
newEdge1 = {source: oldNodes[0], target: newNode1, weight: 5};
newEdge2 = {source: oldNodes[0], target: newNode2, weight: 5};
oldEdges.push(newEdge1,newEdge2);
oldNodes.push(newNode1,newNode2);
force.links(oldEdges).nodes(oldNodes);
d3.select("svg").selectAll("line.link")
.data(oldEdges, function(d) {return d.source.id + "-" + d.target.id})
.enter()
.insert("line", "g.node")
.attr("class", "link")
.style("stroke", "red")
.style("stroke-width", 5)
.attr("marker-end", "url(#Triangle)");
var nodeEnter = d3.select("svg").selectAll("g.node").data(oldNodes, function (d) {return d.id}).enter()
.append("g")
.attr("class", "node")
.call(force.drag())
nodeEnter.append("circle")
.attr("r", 5)
.style("fill", "red")
.style("stroke", "darkred")
.style("stroke-width", "2px");
nodeEnter.append("text")
.style("text-anchor", "middle")
.attr("y", 15)
.text(function(d) {return d.id})
force.start();
}
function moveNodes() {
var xExtent = d3.extent(force.nodes(), function(d) {return parseInt(d.followers)})
var yExtent = d3.extent(force.nodes(), function(d) {return parseInt(d.following)})
var xScale = d3.scale.linear().domain(xExtent).range([50,450])
var yScale = d3.scale.linear().domain(yExtent).range([450,50])
force.stop();
d3.selectAll("g.node")
.transition()
.duration(1000)
.attr("transform", function(d) {return "translate("+ xScale(d.followers) +","+yScale(d.following) +")"})
d3.selectAll("line.link")
.transition()
.duration(1000)
.attr("x1", function(d) {return xScale(d.source.followers)})
.attr("y1", function(d) {return yScale(d.source.following)})
.attr("x2", function(d) {return xScale(d.target.followers)})
.attr("y2", function(d) {return yScale(d.target.following)})
xAxis = d3.svg.axis().scale(xScale).orient("bottom").tickSize(4);
yAxis = d3.svg.axis().scale(yScale).orient("right").tickSize(4);
d3.select("svg").append("g").attr("transform", "translate(0,460)").call(xAxis);
d3.select("svg").append("g").attr("transform", "translate(460,0)").call(yAxis);
d3.selectAll("g.node").each(function(d){
d.x = xScale(d.followers);
d.px = xScale(d.followers);
d.y = yScale(d.following);
d.py = yScale(d.following);
})
}
</script>
</footer>
</html>
id followers following
sam 17 500
roy 83 80
pris 904 15
tully 7 5
kim 11 50
mo 80 85
pat 150 300
lee 38 7
al 12 12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment