block by emeeks 9458332

Arc Diagram with Directed Edges

Full Screen

An arc diagram is another way of visualizing networks that doesn’t use force-directed principles. Instead, it draws the edge from one node to another as arcs above or below the nodes. Weight is indicated by edge thickness and directionality is indicated by the arc being above or below the nodes as well as with the edge getting wider at the source.

index.html

<html xmlns="//www.w3.org/1999/xhtml">
<head>
  <title>D3 in Action Arc Diagram</title>
  <meta charset="utf-8" />
</head>
<script src="//d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="//d3js.org/queue.v1.min.js" type="text/javascript"></script>
<style>
.tick line {
  shape-rendering: crispEdges;
  stroke: #000;
}

line.minor  {
  stroke: #777;
  stroke-dasharray: 2,2;
}

path.domain {
  fill: none;
  stroke: black;
}

</style>
<body onload="arcDiagram()">

<div id="vizcontainer">
<svg style="width:500px;height:500px;border:1px lightgray solid;" />
</div>
  <footer>
<script>
  function arcDiagram() {
    queue()
    .defer(d3.csv, "nodelist.csv")
    .defer(d3.csv, "edgelist.csv")
    .await(function(error, file1, file2) { createArcDiagram(file1, file2); });
    function createArcDiagram(nodes,edges) {
      
      expEdges = edges;
      expNodes = nodes;
      
      var nodeHash = {};
      for (x in nodes) {
        nodeHash[nodes[x].id] = nodes[x];
        nodes[x].x = parseInt(x) * 50;
      }
      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];
      }
      
      linkScale = d3.scale.linear().domain(d3.extent(edges, function (d) {return d.weight})).range([5,10])
      
      var arcG = d3.select("svg").append("g").attr("id", "arcG").attr("transform", "translate(50,250)");

      arcG.selectAll("path")
      .data(edges)
      .enter()
      .append("path")
      .style("stroke", "none")
      .style("opacity", .25)
      .style("fill", "black")
      .attr("d", shapedEdge)
      .on("mouseover", edgeOver)
      
      arcG.selectAll("circle")
      .data(nodes)
      .enter()
      .append("circle")
      .attr("r", 10)
      .style("fill", "lightgray")
      .style("stroke", "black")
      .style("stroke-width", "1px")
      .attr("cx", function (d) {return d.x})
      .on("mouseover", nodeOver)

      function shapedEdge(d,i) {
        var draw = d3.svg.line().interpolate("basis");
        var sw = linkScale(d.weight)
        var midX = (d.source.x + d.target.x) / 2;
        var midY = d.source.x - d.target.x - sw;
        var midY2 = d.source.x - d.target.x + sw;
        return draw([[d.source.x,0],[midX,midY],[d.target.x + (sw*1.5),0],[d.target.x - (sw*1.5),0],[midX,midY2],[d.source.x,0]])
      }
      
      function nodeOver(d,i) {
        d3.selectAll("circle").style("fill", function (p) {return p == d ? "red" : "lightgray"})
        d3.selectAll("path").style("fill", function (p) {return p.source == d || p.target == d ? "red" : "black"})
      }
      
      function edgeOver(d) {
        d3.selectAll("path").style("fill", function(p) {return p == d ? "red" : "black"})
        d3.selectAll("circle").style("fill", function(p) {return p == d.source ? "blue" : p == d.target ? "green" : "lightgray"})}
      
    }
  }
  </script>
  </footer>
</body>
</html>

edgelist.csv

source,target,weight
sam,tully,3
sam,pat,8
sam,kim,2
sam,pris,1
roy,pris,5
roy,sam,1
tully,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,sam,4
mo,pris,1
pat,sam,3
pat,tully,1
pat,kim,2
pat,mo,5

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