Chord Diagram
Layout inspired by Martin Krzywinski’s beautiful work on Circos.
Source Code
1 // From http://mkweb.bcgsc.ca/circos/guide/tables/
2 var chord = d3.layout.chord()
3 .padding(.05)
4 .sortSubgroups(d3.descending)
5 .matrix([
6 [11975, 5871, 8916, 2868],
7 [ 1951, 10048, 2060, 6171],
8 [ 8010, 16145, 8090, 8045],
9 [ 1013, 990, 940, 6907]
10 ]);
11
12 var w = 600,
13 h = 600,
14 r0 = Math.min(w, h) * .41,
15 r1 = r0 * 1.1;
16
17 var fill = d3.scale.ordinal()
18 .domain(d3.range(4))
19 .range(["#000000", "#FFDD89", "#957244", "#F26223"]);
20
21 var svg = d3.select("#chart")
22 .append("svg:svg")
23 .attr("width", w)
24 .attr("height", h)
25 .append("svg:g")
26 .attr("transform", "translate(" + w / 2 + "," + h / 2 + ")");
27
28 svg.append("svg:g")
29 .selectAll("path")
30 .data(chord.groups)
31 .enter().append("svg:path")
32 .style("fill", function(d) { return fill(d.index); })
33 .style("stroke", function(d) { return fill(d.index); })
34 .attr("d", d3.svg.arc().innerRadius(r0).outerRadius(r1))
35 .on("mouseover", fade(.1))
36 .on("mouseout", fade(1));
37
38 var ticks = svg.append("svg:g")
39 .selectAll("g")
40 .data(chord.groups)
41 .enter().append("svg:g")
42 .selectAll("g")
43 .data(groupTicks)
44 .enter().append("svg:g")
45 .attr("transform", function(d) {
46 return "rotate(" + (d.angle * 180 / Math.PI - 90) + ")"
47 + "translate(" + r1 + ",0)";
48 });
49
50 ticks.append("svg:line")
51 .attr("x1", 1)
52 .attr("y1", 0)
53 .attr("x2", 5)
54 .attr("y2", 0)
55 .style("stroke", "#000");
56
57 ticks.append("svg:text")
58 .attr("x", 8)
59 .attr("dy", ".35em")
60 .attr("text-anchor", function(d) {
61 return d.angle > Math.PI ? "end" : null;
62 })
63 .attr("transform", function(d) {
64 return d.angle > Math.PI ? "rotate(180)translate(-16)" : null;
65 })
66 .text(function(d) { return d.label; });
67
68 svg.append("svg:g")
69 .attr("class", "chord")
70 .selectAll("path")
71 .data(chord.chords)
72 .enter().append("svg:path")
73 .style("fill", function(d) { return fill(d.target.index); })
74 .attr("d", d3.svg.chord().radius(r0))
75 .style("opacity", 1);
76
77 /** Returns an array of tick angles and labels, given a group. */
78 function groupTicks(d) {
79 var k = (d.endAngle - d.startAngle) / d.value;
80 return d3.range(0, d.value, 1000).map(function(v, i) {
81 return {
82 angle: v * k + d.startAngle,
83 label: i % 5 ? null : v / 1000 + "k"
84 };
85 });
86 }
87
88 /** Returns an event handler for fading a given chord group. */
89 function fade(opacity) {
90 return function(g, i) {
91 svg.selectAll("g.chord path")
92 .filter(function(d) {
93 return d.source.index != i && d.target.index != i;
94 })
95 .transition()
96 .style("opacity", opacity);
97 };
98 }