Chord diagram showing Spain internal migrations in 2016. Data from ine.es - Provisional data
Built with blockbuilder.org
xxxxxxxxxx
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.group-tick line {
stroke: #000;
}
.ribbons {
fill-opacity: 0.67;
}
</style>
<svg width="750" height="750"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
const svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
outerRadius = Math.min(width, height) * 0.5 - 80,
innerRadius = outerRadius - 30;
const formatValue = d3.formatPrefix(",.0", 1e3);
const chord = d3.chord()
.padAngle(0.05)
.sortSubgroups(d3.descending);
const arc = d3.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
const ribbon = d3.ribbon()
.radius(innerRadius);
//generated using https://jnnnnn.github.io/category-colors-constrained.html
var color = d3.scaleOrdinal()
.domain(d3.range(54))
.range(["#3957ff", "#d3fe14", "#c9080a", "#0b7b3e", "#0bf0e9", "#c203c8", "#fd9b39", "#888593", "#906407", "#fe6794", "#10b0ff", "#ac7bff", "#fee7c0", "#964c63", "#1da49c", "#0ad811", "#fe6cfe", "#297192", "#d1a09c", "#78579e", "#81ffad", "#739400", "#ca6949", "#d9bf01", "#646a58", "#d5097e", "#ccf6e9", "#9cb4b6", "#b6a7d4", "#9e8c62", "#6e83c8", "#01af64", "#a71afd", "#cfe589", "#d4ccd1", "#fd4109", "#bf8f0e", "#2f786e", "#4ed1a5", "#d8bb7d", "#a54509", "#6a9276", "#a4777a", "#fc12c9", "#606f15", "#3cc4d9", "#f31c4e", "#73616f", "#f097c6", "#fc8772", "#92a6fe", "#875b44"]);
d3.csv("migraciones.csv", (d) => {
let array = [];
for (let prop in d) {
array.push(Math.round(parseFloat(d[prop])));
}
return array;
}, (matrix) => {
console.log(matrix);
let columns = matrix.columns;
delete matrix.columns;
var g = svg.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
.datum(chord(matrix));
var group = g.append("g")
.attr("class", "groups")
.selectAll("g")
.data(chords => chords.groups)
.enter().append("g");
group.append("path")
.style("fill", d => color(d.index))
.style("stroke", d => d3.rgb(color(d.index)).darker())
.attr("d", arc)
.style('opacity', .1)
.on("mouseover", fade(1))
.on("mouseout", fade(.1));
group.append("text")
.each(d => {d.angle = (d.startAngle + d.endAngle) / 2; })
.attr("x", 8)
.attr("dy", ".35em")
.attr("text-anchor", d => d.angle > Math.PI ? "end" : null)
.attr("transform", d => {
let degrees = (d.angle * 180 / Math.PI);
if(degrees > 180) {
return "rotate(" + (degrees - 270) +
") translate(" + (-outerRadius - 36) + ",0)";
} else{
return "rotate(" + (degrees - 90) +
") translate(" + (outerRadius + 20) + ",0)";
}
})
// .style("text-anchor", d => d.angle > Math.PI ? "end" : null)
.text(function(d) { return columns[d.index]; });
var groupTick = group.selectAll(".group-tick")
.data(d => groupTicks(d, 1e3))
.enter().append("g")
.attr("class", "group-tick")
.attr("transform", d => "rotate(" + (d.angle * 180 / Math.PI - 90) + ") translate(" + outerRadius + ",0)");
groupTick.append("line")
.attr("x2", 6);
groupTick
.filter(d => d.value % 5e3 === 0)
.append("text")
.attr("x", 8)
.attr("dy", ".35em")
.attr("transform", d => d.angle > Math.PI ? "rotate(180) translate(-16)" : null)
.style("text-anchor", d => d.angle > Math.PI ? "end" : null)
.text(d => formatValue(d.value));
g.append("g")
.attr("class", "ribbons")
.selectAll("path")
.data(function(chords) { return chords; })
.enter().append("path")
.attr("d", ribbon)
.style("fill", d => color(d.target.index))
.style("opacity", 0.1)
.style("stroke", d => d3.rgb(color(d.target.index)).darker());
});
// Returns an array of tick angles and values for a given group and step.
function groupTicks(d, step) {
var k = (d.endAngle - d.startAngle) / d.value;
return d3.range(0, d.value, step).map(function(value) {
return {value: value, angle: value * k + d.startAngle};
});
}
function fade(opacity) {
return function(g, i) {
d3.select(this).transition().style('opacity', opacity);
svg.selectAll(".ribbons path")
.filter(function(d) {
return d.source.index == i || d.target.index == i;
})
.transition()
.style("opacity", opacity);
};
}
</script>
https://d3js.org/d3.v4.min.js