Skip to content

Instantly share code, notes, and snippets.

@KevinRourke
Created December 10, 2015 09:26
Show Gist options
  • Save KevinRourke/777224f2150bb740a14c to your computer and use it in GitHub Desktop.
Save KevinRourke/777224f2150bb740a14c to your computer and use it in GitHub Desktop.
Chord diagram showing co-occurrences.
<!DOCTYPE html>
<meta charset="utf-8">
<!-- affinity group data, circle rotation, auto-resize svg image, chord function, configuration -->
<title>Open Chord Shared Ad Blocks</title>
<script src="http://d3js.org/d3.v3.min.js"></script>
<style>
#visual {
font: 14px sans-serif;
}
.chord path {
fill-opacity: .67;
stroke: #000;
stroke-width: .5px;
}
@media only screen and (min-device-width: 320px) and (max-device-width: 568px) {
#visual {
-webkit-user-select: none;
font-size: 1.2em;
}
}
@media only screen and (min-device-width: 768px) and (max-device-width: 1024px) {
#visual {
-webkit-user-select: none;
}
}
</style>
<body>
<script>
var visual = document.getElementById("visual");
// shared ad blocks between 7-Up, A&W, Coke, Dr Pepper, Pepsi brands
var matrix = [
[ 5, 0, 1, 1, 3 ],
[ 0, 0, 0, 1, 0 ],
[ 1, 0, 1, 1, 0 ],
[ 1, 1, 1, 2, 0 ],
[ 3, 0, 0, 0, 3 ]
];
var array = [ "7-Up", "A&W", "Coke", "Dr Pepper", "Pepsi" ];
var rotation = -0.7;
var chord_options = {
"gnames": array,
"rotation": rotation,
"colors": ["#034e7b","#feb24c","#b10026","#238443","#fdbb84","#ffffb2","#fed976"]
};
function Chord(container, options, matrix) {
// initialize the chord configuration variables
var config = {
width: 640,
height: 560,
rotation: 0,
textgap: 26,
colors: ["#7fc97f", "#beaed4", "#fdc086", "#ffff99", "#386cb0", "#f0027f", "#bf5b17", "#666666"]
};
// add options to the chord configuration object
if (options) {
extend(config, options);
}
// set chord visualization variables from the configuration object
var offset = Math.PI * config.rotation,
width = config.width,
height = config.height,
textgap = config.textgap,
colors = config.colors;
// set viewBox and aspect ratio to enable a resize of the visual dimensions
var viewBoxDimensions = "0 0 " + width + " " + height,
aspect = width / height;
if (config.gnames) {
gnames = config.gnames;
} else {
// make a list of names
gnames = [];
for (var i=97; i<matrix.length; i++) {
gnames.push(String.fromCharCode(i));
}
}
// start the d3 magic
var chord = d3.layout.chord()
.padding(.05)
.sortSubgroups(d3.descending)
.matrix(matrix);
var innerRadius = Math.min(width, height) * .31,
outerRadius = innerRadius * 1.1;
var fill = d3.scale.ordinal()
.domain(d3.range(matrix.length-1))
.range(colors);
var svg = d3.select("body").append("svg")
.attr("id", "visual")
.attr("viewBox", viewBoxDimensions)
.attr("preserveAspectRatio", "xMinYMid") // add viewBox and preserveAspectRatio
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var g = svg.selectAll("g.group")
.data(chord.groups)
.enter().append("svg:g")
.attr("class", "group");
g.append("svg:path")
.style("fill", function(d) { return fill(d.index); })
.style("stroke", function(d) { return fill(d.index); })
.attr("id", function(d, i) { return "group" + d.index; })
.attr("d", d3.svg.arc().innerRadius(innerRadius).outerRadius(outerRadius).startAngle(startAngle).endAngle(endAngle))
.on("mouseover", fade(.1))
.on("mouseout", fade(1));
g.append("svg:text")
.each(function(d) {d.angle = ((d.startAngle + d.endAngle) / 2) + offset; })
.attr("dy", ".35em")
.attr("text-anchor", function(d) { return d.angle > Math.PI ? "end" : null; })
.attr("transform", function(d) {
return "rotate(" + (d.angle * 180 / Math.PI - 90) + ")"
+ "translate(" + (outerRadius + textgap) + ")"
+ (d.angle > Math.PI ? "rotate(180)" : "");
})
.text(function(d) { return gnames[d.index]; });
svg.append("g")
.attr("class", "chord")
.selectAll("path")
.data(chord.chords)
.enter().append("path")
.attr("d", d3.svg.chord().radius(innerRadius).startAngle(startAngle).endAngle(endAngle))
.style("fill", function(d) { return fill(d.source.index); })
.style("opacity", 1)
.append("svg:title")
.text(function(d) {
return d.source.value + " " + gnames[d.source.index] + " shared with " + gnames[d.target.index];
});
// helper functions start here
function startAngle(d) {
return d.startAngle + offset;
}
function endAngle(d) {
return d.endAngle + offset;
}
function extend(a, b) {
for( var i in b ) {
a[ i ] = b[ i ];
}
}
// 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);
};
}
window.onresize = function() {
var targetWidth = (window.innerWidth < width)? window.innerWidth : width;
var svg = d3.select("#visual")
.attr("width", targetWidth)
.attr("height", targetWidth / aspect);
}
}
window.onload = function() {
Chord(visual, chord_options, matrix);
}
d3.select(self.frameElement).style("height", "600px");
</script>
<h1>Shared Ad Blocks by Brand</h1>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment