block by emeeks 91e3737e8e6c02cd31f2

Ch. 6, Fig. 21 - D3.js in Action

Full Screen

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.

index.html

<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>

edgelist.csv

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

nodelist.csv

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