Skip to content

Instantly share code, notes, and snippets.

@mayblue9
Forked from epmoyer/.block
Created July 17, 2016 10:20
Show Gist options
  • Save mayblue9/dcc49ef6e3888f37f755177c4a248f2c to your computer and use it in GitHub Desktop.
Save mayblue9/dcc49ef6e3888f37f755177c4a248f2c to your computer and use it in GitHub Desktop.
Arc Diagram

Source: The Stanford GraphBase

This Arc Diagram visualizes character co-occurrences in Victor Hugo’s Les Misérables. Each character is represented by a circle, and the thickness connecting arcs represent the number co-occurrences with another character in a chapter. Each circle's size represents the sum of all that character's co-occurrences.

Compare this display to a force layout and a matrix diagram.

Many thanks to Stanford's "A Tour through the Visialization Zoo". This visualization is based upon the arc diagram which appears there.

<!DOCTYPE html>
<!-- Port Arc Diagram visualization from http://homes.cs.washington.edu/~jheer/files/zoo/ex/networks/arc.html to D3.js -->
<meta charset="utf-8">
<style>
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
width: 960px;
height: 500px;
position: relative;
}
path {
fill: #505050;
fill-opacity: 0.2;
}
circle{
stroke-width: 1;
}
</style>
<body>Order:
<select id="selectSort">
<option value="Group">by Cluster</option>
<option value="Frequency">by Frequency</option>
<option value="Name">by Name</option>
</select>
</body>
<script src="miserables.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
<script>
var i,
width = 960,
height = 500,
transitionTime = 2500,
spacing = 11,
margin = 20,
nodeY = 380,
nodes = miserables.nodes,
links = miserables.links,
colors = d3.scale.category20(),
τ = 2 * Math.PI; // http://tauday.com/tau-manifesto
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
function mapRange(value, inMin, inMax, outMin, outMax){
var inVal = Math.min(Math.max(value, inMin), inMax);
return outMin + (outMax-outMin)*((inVal - inMin)/(inMax-inMin));
}
// Set each node's value to the sum of all incoming and outgoing link values
var nodeValMin = 100000000,
nodeValMax = 0;
for(i=0; i<nodes.length; i++){
nodes[i].value = 0;
nodes[i].displayOrder = i;
}
for(i=0; i<links.length; i++){
var link = links[i];
value = link.value;
nodes[link.source].value += link.value;
nodes[link.target].value += link.value;
}
for(i=0; i<nodes.length; i++){
nodeValMin = Math.min(nodeValMin, nodes[i].value);
nodeValMax = Math.max(nodeValMax, nodes[i].value);
}
var arcBuilder = d3.svg.arc()
.startAngle(-τ/4)
.endAngle(τ/4);
arcBuilder.setRadii = function(d){
var arcHeight = 0.5 * Math.abs(d.x2-d.x1);
this
.innerRadius(arcHeight - d.thickness/2)
.outerRadius(arcHeight + d.thickness/2);
};
function arcTranslation(d){
return "translate(" + (d.x1 + d.x2)/2 + "," + nodeY + ")";
}
function nodeDisplayX(node){
return node.displayOrder * spacing + margin;
}
var path;
function update(){
// DATA JOIN
path = svg.selectAll("path")
.data(links);
// UPDATE
path.transition()
.duration(transitionTime)
.call(pathTween, null);
// ENTER
path.enter()
.append("path")
.attr("transform", function(d,i){
d.x1 = nodeDisplayX(nodes[d.target]);
d.x2 = nodeDisplayX(nodes[d.source]);
return arcTranslation(d);
})
.attr("d", function(d,i){
d.thickness = 1 + d.value;
arcBuilder.setRadii(d);
return arcBuilder();
});
// DATA JOIN
var circle = svg.selectAll("circle")
.data(nodes);
// UPDATE
circle.transition()
.duration(transitionTime)
.attr("cx", function(d,i) {return nodeDisplayX(d);});
// ENTER
circle.enter()
.append("circle")
.attr("cy", nodeY)
.attr("cx", function(d,i) {return nodeDisplayX(d);})
.attr("r", function(d,i) {return mapRange(d.value, nodeValMin, nodeValMax, 2.5, 13);})
.attr("fill", function(d,i) {return colors(d.group);})
.attr("stroke", function(d,i) {return d3.rgb(colors(d.group)).darker(1);});
function textTransform(node){
return ("rotate(90 " + (nodeDisplayX(node) - 5) + " " + (nodeY + 12) + ")");
}
// DATA JOIN
var text = svg.selectAll("text")
.data(nodes);
// UPDATE
text.transition()
.duration(transitionTime)
.attr("x", function(d,i) {return nodeDisplayX(d) - 5;})
.attr("transform", function(d,i) { return textTransform(d); });
// ENTER
text.enter()
.append("text")
.attr("y", nodeY + 12)
.attr("x", function(d,i) {return nodeDisplayX(d) - 5;})
.attr("transform", function(d,i) { return textTransform(d); })
.attr("font-size", "10px")
.text(function(d,i) {return d.nodeName;});
}
doSort(0);
update();
function pathTween(transition, dummy){
transition.attrTween("d", function(d){
var interpolateX1 = d3.interpolate(d.x1, nodeDisplayX(nodes[d.target]));
var interpolateX2 = d3.interpolate(d.x2, nodeDisplayX(nodes[d.source]));
return function(t){
d.x1 = interpolateX1(t);
d.x2 = interpolateX2(t);
arcBuilder.setRadii(d);
return arcBuilder();
};
});
transition.attrTween("transform", function(d){
var interpolateX1 = d3.interpolate(d.x1, nodeDisplayX(nodes[d.target]));
var interpolateX2 = d3.interpolate(d.x2, nodeDisplayX(nodes[d.source]));
return function(t){
d.x1 = interpolateX1(t);
d.x2 = interpolateX2(t);
return arcTranslation(d);
};
});
}
d3.select("#selectSort").on("change", function() {
doSort(this.selectedIndex);
update();
});
function doSort(sortMethod){
var nodeMap = [],
sortFunciton;
for(i=0; i<nodes.length; i++){
var node = $.extend({index:i}, nodes[i]); // Shallow copy
nodeMap.push(node);
}
if (sortMethod == 0){
// GROUP
sortFunction = function(a, b){
return b.group - a.group;
};
}
else if (sortMethod == 1){
// FREQUENCY
sortFunction = function(a, b){
return b.value - a.value;
};
}
else if(sortMethod == 2){
// ALPHABETICAL
sortFunction = function(a, b){
return a.nodeName.localeCompare(b.nodeName)
};
}
nodeMap.sort(sortFunction);
for(i=0; i<nodeMap.length; i++){
nodes[nodeMap[i].index].displayOrder = i;
}
}
</script>
// This file contains the weighted network of coappearances of characters in
// Victor Hugo's novel "Les Miserables". Nodes represent characters as indicated
// by the labels, and edges connect any pair of characters that appear in the
// same chapter of the book. The values on the edges are the number of such
// coappearances. The data on coappearances were taken from D. E. Knuth, The
// Stanford GraphBase: A Platform for Combinatorial Computing, Addison-Wesley,
// Reading, MA (1993).
//
// The group labels were transcribed from "Finding and evaluating community
// structure in networks" by M. E. J. Newman and M. Girvan.
var miserables = {
nodes:[
{nodeName:"Myriel", group:1},
{nodeName:"Napoleon", group:1},
{nodeName:"Mlle. Baptistine", group:1},
{nodeName:"Mme. Magloire", group:1},
{nodeName:"Countess de Lo", group:1},
{nodeName:"Geborand", group:1},
{nodeName:"Champtercier", group:1},
{nodeName:"Cravatte", group:1},
{nodeName:"Count", group:1},
{nodeName:"Old Man", group:1},
{nodeName:"Labarre", group:2},
{nodeName:"Valjean", group:2},
{nodeName:"Marguerite", group:3},
{nodeName:"Mme. de R", group:2},
{nodeName:"Isabeau", group:2},
{nodeName:"Gervais", group:2},
{nodeName:"Tholomyes", group:3},
{nodeName:"Listolier", group:3},
{nodeName:"Fameuil", group:3},
{nodeName:"Blacheville", group:3},
{nodeName:"Favourite", group:3},
{nodeName:"Dahlia", group:3},
{nodeName:"Zephine", group:3},
{nodeName:"Fantine", group:3},
{nodeName:"Mme. Thenardier", group:4},
{nodeName:"Thenardier", group:4},
{nodeName:"Cosette", group:5},
{nodeName:"Javert", group:4},
{nodeName:"Fauchelevent", group:0},
{nodeName:"Bamatabois", group:2},
{nodeName:"Perpetue", group:3},
{nodeName:"Simplice", group:2},
{nodeName:"Scaufflaire", group:2},
{nodeName:"Woman 1", group:2},
{nodeName:"Judge", group:2},
{nodeName:"Champmathieu", group:2},
{nodeName:"Brevet", group:2},
{nodeName:"Chenildieu", group:2},
{nodeName:"Cochepaille", group:2},
{nodeName:"Pontmercy", group:4},
{nodeName:"Boulatruelle", group:6},
{nodeName:"Eponine", group:4},
{nodeName:"Anzelma", group:4},
{nodeName:"Woman 2", group:5},
{nodeName:"Mother Innocent", group:0},
{nodeName:"Gribier", group:0},
{nodeName:"Jondrette", group:7},
{nodeName:"Mme. Burgon", group:7},
{nodeName:"Gavroche", group:8},
{nodeName:"Gillenormand", group:5},
{nodeName:"Magnon", group:5},
{nodeName:"Mlle. Gillenormand", group:5},
{nodeName:"Mme. Pontmercy", group:5},
{nodeName:"Mlle. Vaubois", group:5},
{nodeName:"Lt. Gillenormand", group:5},
{nodeName:"Marius", group:8},
{nodeName:"Baroness T", group:5},
{nodeName:"Mabeuf", group:8},
{nodeName:"Enjolras", group:8},
{nodeName:"Combeferre", group:8},
{nodeName:"Prouvaire", group:8},
{nodeName:"Feuilly", group:8},
{nodeName:"Courfeyrac", group:8},
{nodeName:"Bahorel", group:8},
{nodeName:"Bossuet", group:8},
{nodeName:"Joly", group:8},
{nodeName:"Grantaire", group:8},
{nodeName:"Mother Plutarch", group:9},
{nodeName:"Gueulemer", group:4},
{nodeName:"Babet", group:4},
{nodeName:"Claquesous", group:4},
{nodeName:"Montparnasse", group:4},
{nodeName:"Toussaint", group:5},
{nodeName:"Child 1", group:10},
{nodeName:"Child 2", group:10},
{nodeName:"Brujon", group:4},
{nodeName:"Mme. Hucheloup", group:8}
],
links:[
{source:1, target:0, value:1},
{source:2, target:0, value:8},
{source:3, target:0, value:10},
{source:3, target:2, value:6},
{source:4, target:0, value:1},
{source:5, target:0, value:1},
{source:6, target:0, value:1},
{source:7, target:0, value:1},
{source:8, target:0, value:2},
{source:9, target:0, value:1},
{source:11, target:10, value:1},
{source:11, target:3, value:3},
{source:11, target:2, value:3},
{source:11, target:0, value:5},
{source:12, target:11, value:1},
{source:13, target:11, value:1},
{source:14, target:11, value:1},
{source:15, target:11, value:1},
{source:17, target:16, value:4},
{source:18, target:16, value:4},
{source:18, target:17, value:4},
{source:19, target:16, value:4},
{source:19, target:17, value:4},
{source:19, target:18, value:4},
{source:20, target:16, value:3},
{source:20, target:17, value:3},
{source:20, target:18, value:3},
{source:20, target:19, value:4},
{source:21, target:16, value:3},
{source:21, target:17, value:3},
{source:21, target:18, value:3},
{source:21, target:19, value:3},
{source:21, target:20, value:5},
{source:22, target:16, value:3},
{source:22, target:17, value:3},
{source:22, target:18, value:3},
{source:22, target:19, value:3},
{source:22, target:20, value:4},
{source:22, target:21, value:4},
{source:23, target:16, value:3},
{source:23, target:17, value:3},
{source:23, target:18, value:3},
{source:23, target:19, value:3},
{source:23, target:20, value:4},
{source:23, target:21, value:4},
{source:23, target:22, value:4},
{source:23, target:12, value:2},
{source:23, target:11, value:9},
{source:24, target:23, value:2},
{source:24, target:11, value:7},
{source:25, target:24, value:13},
{source:25, target:23, value:1},
{source:25, target:11, value:12},
{source:26, target:24, value:4},
{source:26, target:11, value:31},
{source:26, target:16, value:1},
{source:26, target:25, value:1},
{source:27, target:11, value:17},
{source:27, target:23, value:5},
{source:27, target:25, value:5},
{source:27, target:24, value:1},
{source:27, target:26, value:1},
{source:28, target:11, value:8},
{source:28, target:27, value:1},
{source:29, target:23, value:1},
{source:29, target:27, value:1},
{source:29, target:11, value:2},
{source:30, target:23, value:1},
{source:31, target:30, value:2},
{source:31, target:11, value:3},
{source:31, target:23, value:2},
{source:31, target:27, value:1},
{source:32, target:11, value:1},
{source:33, target:11, value:2},
{source:33, target:27, value:1},
{source:34, target:11, value:3},
{source:34, target:29, value:2},
{source:35, target:11, value:3},
{source:35, target:34, value:3},
{source:35, target:29, value:2},
{source:36, target:34, value:2},
{source:36, target:35, value:2},
{source:36, target:11, value:2},
{source:36, target:29, value:1},
{source:37, target:34, value:2},
{source:37, target:35, value:2},
{source:37, target:36, value:2},
{source:37, target:11, value:2},
{source:37, target:29, value:1},
{source:38, target:34, value:2},
{source:38, target:35, value:2},
{source:38, target:36, value:2},
{source:38, target:37, value:2},
{source:38, target:11, value:2},
{source:38, target:29, value:1},
{source:39, target:25, value:1},
{source:40, target:25, value:1},
{source:41, target:24, value:2},
{source:41, target:25, value:3},
{source:42, target:41, value:2},
{source:42, target:25, value:2},
{source:42, target:24, value:1},
{source:43, target:11, value:3},
{source:43, target:26, value:1},
{source:43, target:27, value:1},
{source:44, target:28, value:3},
{source:44, target:11, value:1},
{source:45, target:28, value:2},
{source:47, target:46, value:1},
{source:48, target:47, value:2},
{source:48, target:25, value:1},
{source:48, target:27, value:1},
{source:48, target:11, value:1},
{source:49, target:26, value:3},
{source:49, target:11, value:2},
{source:50, target:49, value:1},
{source:50, target:24, value:1},
{source:51, target:49, value:9},
{source:51, target:26, value:2},
{source:51, target:11, value:2},
{source:52, target:51, value:1},
{source:52, target:39, value:1},
{source:53, target:51, value:1},
{source:54, target:51, value:2},
{source:54, target:49, value:1},
{source:54, target:26, value:1},
{source:55, target:51, value:6},
{source:55, target:49, value:12},
{source:55, target:39, value:1},
{source:55, target:54, value:1},
{source:55, target:26, value:21},
{source:55, target:11, value:19},
{source:55, target:16, value:1},
{source:55, target:25, value:2},
{source:55, target:41, value:5},
{source:55, target:48, value:4},
{source:56, target:49, value:1},
{source:56, target:55, value:1},
{source:57, target:55, value:1},
{source:57, target:41, value:1},
{source:57, target:48, value:1},
{source:58, target:55, value:7},
{source:58, target:48, value:7},
{source:58, target:27, value:6},
{source:58, target:57, value:1},
{source:58, target:11, value:4},
{source:59, target:58, value:15},
{source:59, target:55, value:5},
{source:59, target:48, value:6},
{source:59, target:57, value:2},
{source:60, target:48, value:1},
{source:60, target:58, value:4},
{source:60, target:59, value:2},
{source:61, target:48, value:2},
{source:61, target:58, value:6},
{source:61, target:60, value:2},
{source:61, target:59, value:5},
{source:61, target:57, value:1},
{source:61, target:55, value:1},
{source:62, target:55, value:9},
{source:62, target:58, value:17},
{source:62, target:59, value:13},
{source:62, target:48, value:7},
{source:62, target:57, value:2},
{source:62, target:41, value:1},
{source:62, target:61, value:6},
{source:62, target:60, value:3},
{source:63, target:59, value:5},
{source:63, target:48, value:5},
{source:63, target:62, value:6},
{source:63, target:57, value:2},
{source:63, target:58, value:4},
{source:63, target:61, value:3},
{source:63, target:60, value:2},
{source:63, target:55, value:1},
{source:64, target:55, value:5},
{source:64, target:62, value:12},
{source:64, target:48, value:5},
{source:64, target:63, value:4},
{source:64, target:58, value:10},
{source:64, target:61, value:6},
{source:64, target:60, value:2},
{source:64, target:59, value:9},
{source:64, target:57, value:1},
{source:64, target:11, value:1},
{source:65, target:63, value:5},
{source:65, target:64, value:7},
{source:65, target:48, value:3},
{source:65, target:62, value:5},
{source:65, target:58, value:5},
{source:65, target:61, value:5},
{source:65, target:60, value:2},
{source:65, target:59, value:5},
{source:65, target:57, value:1},
{source:65, target:55, value:2},
{source:66, target:64, value:3},
{source:66, target:58, value:3},
{source:66, target:59, value:1},
{source:66, target:62, value:2},
{source:66, target:65, value:2},
{source:66, target:48, value:1},
{source:66, target:63, value:1},
{source:66, target:61, value:1},
{source:66, target:60, value:1},
{source:67, target:57, value:3},
{source:68, target:25, value:5},
{source:68, target:11, value:1},
{source:68, target:24, value:1},
{source:68, target:27, value:1},
{source:68, target:48, value:1},
{source:68, target:41, value:1},
{source:69, target:25, value:6},
{source:69, target:68, value:6},
{source:69, target:11, value:1},
{source:69, target:24, value:1},
{source:69, target:27, value:2},
{source:69, target:48, value:1},
{source:69, target:41, value:1},
{source:70, target:25, value:4},
{source:70, target:69, value:4},
{source:70, target:68, value:4},
{source:70, target:11, value:1},
{source:70, target:24, value:1},
{source:70, target:27, value:1},
{source:70, target:41, value:1},
{source:70, target:58, value:1},
{source:71, target:27, value:1},
{source:71, target:69, value:2},
{source:71, target:68, value:2},
{source:71, target:70, value:2},
{source:71, target:11, value:1},
{source:71, target:48, value:1},
{source:71, target:41, value:1},
{source:71, target:25, value:1},
{source:72, target:26, value:2},
{source:72, target:27, value:1},
{source:72, target:11, value:1},
{source:73, target:48, value:2},
{source:74, target:48, value:2},
{source:74, target:73, value:3},
{source:75, target:69, value:3},
{source:75, target:68, value:3},
{source:75, target:25, value:3},
{source:75, target:48, value:1},
{source:75, target:41, value:1},
{source:75, target:70, value:1},
{source:75, target:71, value:1},
{source:76, target:64, value:1},
{source:76, target:65, value:1},
{source:76, target:66, value:1},
{source:76, target:63, value:1},
{source:76, target:62, value:1},
{source:76, target:48, value:1},
{source:76, target:58, value:1}
]
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment