Reputation: 31
I am new to D3 and am trying to make a Chord Diagram about the relationship between countries voting at the Eurovision Song Contest. This is my code so far:
var names = ["Ukraine","Spain","Slovenia","Lithuania","Austria","Estonia","Norway","Portugal","UK","Serbia","Germany","Albania","France","Czech Republic","Denmark","Australia","Finland","Bulgaria","Moldova","Sweden","Hungary","Israel","Netherlands","Ireland","Cyprus","Italy","Armenia","Azerbaijan","Belarus","Belgium","Croatia","Macedonia","Georgia","Greece","Iceland","Latvia","Malta","Montenegro","Poland","Romania","Russia","San Marino","Switzerland"];
var opacityDefault = 0.7;
var matrix = [
[0,14,12,5,0,4,0,8,0,0,0,0,0,3,0,0,0,0,12,0,15,0,0,4,8,0,0,0,2,4,1,0,0,7,0,0,8,0,7,12,0,0,4], //Ukraine
[0,0,0,0,0,0,0,0,0,0,6,1,0,0,0,0,1,10,0,0,0,1,2,5,0,7,0,0,7,0,0,0,0,0,6,0,0,1,0,0,0,0,14], //Spain
[5,0,4,6,1,4,0,0,0,0,0,0,0,1,0,7,0,1,7,0,0,0,0,2,0,0,0,8,0,0,0,0,0,6,0,0,0,0,4,0,0,0,3], //Slovenia
[2,0,5,0,7,0,5,9,0,0,0,12,7,16,0,12,12,6,1,0,0,0,15,0,0,3,22,0,6,0,10,0,5,0,8,0,3,8,0,1,0,0,6], //Lithuania
[7,0,10,0,13,0,1,9,8,0,18,12,12,7,2,0,5,12,5,17,3,15,16,7,7,5,18,4,2,7,16,0,11,0,15,10,0,8,13,12,15,12,8], //Austria
[4,3,0,5,4,12,0,16,3,2,7,6,0,18,4,0,7,3,5,7,13,0,0,7,10,8,0,3,5,2,2,7,0,5,2,12,9,10,8,0,12,5,19], //Estonia
[0,7,18,0,4,0,4,0,3,0,8,5,10,2,0,5,0,0,0,4,7,0,0,0,12,1,6,9,5,7,0,3,7,7,0,0,5,0,0,0,0,5,0], //Norway
[0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,8,0,0,3,0,0,0,0,0,0,0,0,0,0,13,0,0,7,0,0], //Portugal
[0,0,0,1,0,0,1,0,0,0,3,0,0,2,3,2,10,0,0,0,0,0,0,3,6,6,0,0,0,0,0,0,0,2,1,0,0,0,8,0,0,0,0], //UK
[0,10,0,3,0,0,0,0,0,8,0,0,0,0,3,12,0,0,0,0,0,0,0,1,1,0,0,0,0,0,7,2,0,24,0,0,0,12,0,0,0,0,0], //Serbia
[0,5,0,14,24,3,4,7,13,16,24,3,6,3,14,3,16,8,3,14,8,7,18,8,13,12,6,10,3,5,6,2,1,0,0,1,4,18,8,11,7,4,8], //Germany
[0,12,7,0,0,18,0,4,0,9,0,7,0,0,0,5,2,0,6,10,0,2,0,0,12,0,0,1,6,0,7,17,10,20,0,0,0,7,0,7,0,5,10], //Albania
[19,0,0,0,0,0,8,4,10,0,2,0,5,10,12,6,4,0,0,9,0,11,8,0,0,0,0,0,4,9,5,5,0,0,0,9,2,0,6,3,15,2,5], //France
[14,6,11,10,6,9,8,0,14,15,6,5,3,4,1,9,7,3,0,11,6,8,4,4,0,4,5,5,13,14,11,7,8,0,8,5,2,0,12,4,8,11,0], //Czech Republic
[11,0,10,6,8,0,2,3,0,5,0,2,12,5,0,2,2,2,7,12,0,5,10,2,12,10,8,4,0,0,0,0,24,6,3,13,7,2,0,6,10,7,2], //Denmark
[2,0,2,2,0,0,9,0,0,0,12,1,8,6,0,0,0,2,0,0,7,0,6,10,0,0,0,0,0,2,0,0,7,0,7,0,5,0,7,4,0,0,0], //Australia
[0,0,0,0,0,5,0,0,0,0,0,4,9,0,0,0,0,0,3,3,0,0,0,0,0,4,12,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0], //Finland
[0,6,1,0,0,7,9,6,5,6,1,14,6,0,14,8,10,5,5,0,11,0,0,0,0,0,7,2,12,0,0,5,0,4,0,10,0,2,1,2,0,0,7], //Bulgaria
[6,11,6,9,0,1,0,3,0,0,0,4,0,7,2,8,1,19,6,0,0,0,0,6,10,7,1,6,10,11,8,11,2,8,0,0,24,0,10,0,0,6,6], //Moldova
[6,2,1,8,8,7,7,12,2,8,11,2,0,12,4,0,0,0,8,7,0,8,13,5,1,12,5,12,12,12,2,8,1,2,12,8,11,5,10,6,12,12,0], //Sweden
[1,8,2,0,2,0,0,0,0,3,0,0,0,0,0,0,0,10,2,0,2,0,0,0,0,0,3,12,4,0,5,6,0,3,2,8,0,0,3,10,2,3,0], //Hungary
[22,13,8,24,15,4,14,15,22,19,3,17,17,8,6,16,13,8,22,15,22,16,7,24,9,18,0,9,10,18,14,10,16,1,11,19,18,6,0,10,7,1,2], //Israel
[8,0,0,0,0,0,0,5,0,1,5,0,1,5,0,0,3,8,0,0,0,22,9,6,0,0,1,7,0,3,0,0,8,0,5,2,0,0,0,8,3,7,0], //Netherlands
[0,0,0,4,4,0,0,0,6,8,4,13,4,0,7,3,0,1,14,4,0,4,1,1,5,12,0,0,0,0,1,0,3,0,15,2,0,6,0,7,4,0,3], //Ireland
[4,14,15,7,11,18,22,10,20,1,6,8,16,1,20,8,17,12,8,3,13,11,7,3,8,7,12,10,0,19,15,24,7,6,9,7,11,10,2,8,7,14,5], //Cyprus
[5,5,4,12,7,6,22,5,10,10,0,0,0,6,24,10,0,6,2,0,8,6,0,10,0,0,7,14,15,3,6,9,6,12,12,10,7,8,5,5,7,10,14], //Italy
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], //Armenia
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], //Azerbaijan
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], //Belarus
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], //Belgium
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], //Croatia
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], //Macedonia
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], //Georgia
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], //Greece
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], //Iceland
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], //Latvia
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], //Malta
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], //Montenegro
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], //Poland
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], //Romania
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], //Russia
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], //San Marino
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], //Switzerland
];
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
outerRadius = Math.min(width, height) * 0.4 - 100,
innerRadius = outerRadius - 20;
var formatValue = d3.formatPrefix(",.0", 1e3);
var chord = d3.chord()
.padAngle(0.05)
.sortSubgroups(d3.descending);
var arc = d3.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var ribbon = d3.ribbon()
.radius(innerRadius);
var color = d3.scaleOrdinal()
.domain(d3.range(4))
.range(["#4B5320", "#50C878", "#98FB98", "#679267","#2E8B57","#043927", "#0B6623","#9DC183","#708238", "#C7EA46", "#3F704D","#00A86B","8F9779"]);
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(function(chords) { return chords.groups; })
.enter().append("g");
group.append("path")
.style("fill", function(d) { return color(d.index); })
.style("stroke", function(d) { return d3.rgb(color(d.index)).darker(); })
.attr("d", arc);
var outerArcs = svg.selectAll("g.group")
outerArcs.append("path")
.style("fill", function(d) { return colors(d.index); })
.attr("d", arc);
outerArcs.append("text")
.each(function(d) { d.angle = (d.startAngle + d.endAngle) / 2; })
.attr("dy", ".35em")
.attr("class", "titles")
.attr("text-anchor", function(d) { return d.angle > Math.PI ? "end" : null; })
.attr("transform", function(d) {
if (outerArcs = 0) {
width = 5.0;
}
return "rotate(" + (d.angle * 180 / Math.PI - 90) + ")"
+ "translate(" + (outerRadius + 100) + ")"
+ (d.angle > Math.PI ? "rotate(180)" : "");
})
.text(function(i) { return names[i]; });
var groupTick = group.selectAll(".group-tick")
.data(function(d) { return groupTicks(d, 1e3); })
.enter().append("g")
.attr("class", "group-tick")
.attr("transform", function(d) { return "rotate(" + (d.angle * 180 / Math.PI - 90) + ") translate(" + outerRadius + ",0)"; });
groupTick.append("line")
.attr("x2", 6);
groupTick
//.filter(function(d) { return d.names; })
.append("text")
.attr("x", 8)
.attr("dy", ".35em")
.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, i) {
console.log(d.id)
return names[d.id];
});
g.append("g")
.attr("class", "ribbons")
.selectAll("path")
.data(function(chords) { return chords; })
.enter().append("path")
.attr("d", ribbon)
.style("fill", function(d) { return color(d.target.index); })
.style("stroke", function(d) { return d3.rgb(color(d.target.index)).darker(); });
// Returns an array of tick angles and values for a given group and step.
function groupTicks(d, i) {
var k = (d.endAngle - d.startAngle) / d.value;
return d3.range(0, d.value,0.2).map(function(v, i) {
return {
angle: v * k + d.startAngle,
label: i*100 % 5 ? null : v,
id: i
};
});
}
</script>
At the moment, the countries are all appearing on top of one another and I want each country to have it's own name/label. The names of the countries that didn't participate in the final but still voted in the competition are not appearing either and need that to be fixed as well.
I'm absolutely desperate so help would be much appreciated, cheers!
Upvotes: 1
Views: 160
Reputation: 38201
You seem to have duplicated the labeling - there are two spots where you append text:
groupTick
.append("text")
...
And above with:
outerArcs.append("text")
...
The first approach is most simply fixed, so I will drop everything using the groupTick approach. If you log outerArcs.size()
, you will see your selection doesn't include any elements - there are no elements with the class group
(rather you want groups
):
var outerArcs = svg.selectAll("g.group")
Consequently, no text is added as there are no elements in the selection.
This also means that outerArcs.append("path")...
doesn't do anything - but it is duplicated above with group.append("path")...
so we can remove this
Rather than making this outerArcs
selection, we can use the already existing selection with those elements: group
.
Also, when accessing the index of the datum as you try to do here:
.text(function(i) { return names[i]; });
The parameter names are irrelevant, though convention is that index is i
, the ordering of the parameters are what sets the content, the first parameter is the datum, index is the second parameter, so we could use:
.text(function(d,i) { return names[i]; });
Here's a working example that strips out the duplicate code, uses the group
selection to append the text, and changes the naming function (I also reduced the amount added to the outer radius for spacing to 10 from 100 pixels).
Here's what it looks like:
Upvotes: 1