|
<!DOCTYPE html> |
|
<meta charset="utf-8"> |
|
<head> |
|
<title> 20 chords </title> |
|
<script src="http://d3js.org/d3.v3.min.js"></script> |
|
<script> |
|
function main() { |
|
d3.text("matrix.tsv",function(data){ |
|
var matrix = d3.tsv.parseRows(data, function(row) { |
|
return row.map(function(e) { |
|
return parseFloat(e); |
|
}); |
|
}); |
|
|
|
var letters = "ACDEFGHIKLMNPQRSTVWY".split(""); |
|
|
|
var chord = d3.layout.chord() |
|
.padding(.05) |
|
.sortSubgroups(d3.descending) |
|
.matrix(matrix); |
|
|
|
var width = 1000, |
|
height = 1000, |
|
innerRadius = Math.min(width, height) * .41, |
|
outerRadius = innerRadius * 1.1; |
|
|
|
|
|
var fill = d3.scale.category20(); |
|
|
|
var svg = d3.select("body").append("svg") |
|
.attr("width", width) |
|
.attr("height", height) |
|
.attr("id","chart") |
|
.append("g") |
|
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"); |
|
|
|
svg.append("g").selectAll("path") |
|
.data(chord.groups) |
|
.enter().append("path") |
|
.style("fill", function(d) { return fill(d.index); }) |
|
.style("stroke", function(d) { return fill(d.index); }) |
|
.attr("d", d3.svg.arc().innerRadius(innerRadius).outerRadius(outerRadius)) |
|
.on("mouseover", fade(.1)) |
|
.on("mouseout", fade(1)); |
|
|
|
var ticks = svg.append("g").selectAll("g") |
|
.data(chord.groups) |
|
.enter().append("g").selectAll("g") |
|
.data(groupTicks) |
|
.enter().append("g") |
|
.attr("opacity",.7) |
|
.attr("stroke","black") |
|
.attr("stroke-width",0.5) |
|
.attr("transform", function(d) { |
|
return "rotate(" + (d.angle * 180 / Math.PI - 90) + ")" |
|
+ "translate(" + outerRadius + ",0)"; |
|
}); |
|
|
|
ticks.append("text") |
|
.attr("x", 8) |
|
.attr("dy", ".35em") |
|
.attr("font-family","sans-serif") |
|
.attr("font-size",10) |
|
.attr("transform", function(d) { return d.angle > Math.PI ? "rotate(180)translate(-16)" : null; }) |
|
.style("text-anchor", function(d) { return d.angle > Math.PI ? "end" : null; }) |
|
.text(function(d) { return d.label; }); |
|
|
|
svg.append("g") |
|
.attr("class", "chord") |
|
.selectAll("path") |
|
.data(chord.chords) |
|
.enter().append("path") |
|
.attr("d", d3.svg.chord().radius(innerRadius)) |
|
.style("fill", function(d) { return fill(d.target.index); }) |
|
.style("opacity", .7) |
|
.attr("stroke","black") |
|
.attr("stroke-width",0.5); |
|
|
|
// Returns an array of tick angles and labels, given a group. |
|
function groupTicks(d) { |
|
var k = (d.endAngle - d.startAngle) / d.value; |
|
return d3.range(0, d.value, 1000).map(function(v, i) { |
|
return { |
|
angle: v * k + d.startAngle, |
|
label: letters[d.index] |
|
}; |
|
}); |
|
} |
|
|
|
// Returns an event handler for fading a given chord group. |
|
function fade(opacity) { |
|
return function(g, i) { |
|
svg.selectAll(".chord path") |
|
.filter(function(d) { return d.source.index != i && d.target.index != i; }) |
|
.transition() |
|
.style("opacity", opacity); |
|
}; |
|
} |
|
|
|
}); |
|
} |
|
|
|
//download the SVG of the figure |
|
function download() { |
|
var svg = document.getElementById("chart"); |
|
var serializer = new XMLSerializer(); |
|
var source = serializer.serializeToString(svg); |
|
source = '<?xml version="1.0" standalone="no"?>\r\n' + source; |
|
|
|
var pom = document.createElement("a"); |
|
pom.setAttribute("href","data:image/svg+xml;charset=utf-8," + encodeURIComponent(source)); |
|
pom.setAttribute("download","chords.svg"); |
|
|
|
if (document.createEvent) { |
|
var event = document.createEvent("MouseEvents"); |
|
event.initEvent("click",true,true); |
|
pom.dispatchEvent(event); |
|
} else { |
|
pom.click(); |
|
} |
|
|
|
} |
|
|
|
function keyboardHandler(e) { |
|
var c = String.fromCharCode(e.which); |
|
if (c === "s") { |
|
download(); |
|
} |
|
} |
|
|
|
</script> |
|
</head> |
|
|
|
<body onload="main()" onkeypress="keyboardHandler(event)"> |
|
</body> |