Moritz Matejka Moritz Matejka - 1 month ago 7
HTML Question

How can I add labels to a pie chart, when using an array without named entries

I wrote a javascript program that produces a pie chart using d3.js.

This works fine, however I am not able to add labels to the chart.

The data I am using has the following structure:

[["country", "percentage"], ["country", "percentage"],...]


or as an example:

[["A", "0.5"], ["AUS", "0.3"],....]


The graphing works fine, but I get no labels to display.

Any help would be appreciated.

here is an excerpt of the code:

var updatePie = function () {

var width = 480,
height = 480,
radius = Math.min(width, height) / 2;



var labelr = radius + 30;
var formatPercent = d3.format(",.2%");
var color = d3.scale.ordinal()
.domain(["A", "AUS", "B",
"BG", "BR", "CDN",
"CH", "CN", "CO",
"CZ", "D", "DK", "E",
"EST", "ET", "F",
"FIN", "GB", "I",
"IL", "IRL", "J",
"N", "NL", "NZ",
"RUS", "S", "UAE",
"USA", "ZA"])
.range(["#bac5ca", "#7b95a7", "#526f8b",
"#454c57", "#323540", "#a17d48",
"#5e747d", "#405666", "#2a2e34",
"#1f2127", "#5c482b", "#c7d0d4",
"#94a9b8", "#6f8aa3", "#616c7c",
"#505669", "#b49569", "#8a9ca3",
"#57768b", "#41576d", "#363c45",
"#292b33", "#7e623a", "#d5dbdf",
"#adbdca", "#90a6ba", "#848e9c",
"#747b90", "#454c57", "#c6af8c",
]), svg;
function graph(_selection) {
_selection.each(function(_data) {

var pie = d3.layout.pie()
.value(function(d) { return d[1]; })
.sort(null);

var arc = d3.svg.arc()
.innerRadius(radius - 100)
.outerRadius(radius - 50);

if (!svg){
svg = d3.select(this).append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
}
var path = svg.selectAll("path").data(pie(_data));

path.enter().append("path")
.attr("fill", function(d, i) { return color(i); })
.attr("d", arc)
.each(function(d) {this._current = d;} );


var text = svg.selectAll("text")
.data(pie(_data));

text.append('text')
.attr("fill", "black")
.attr("font-family", "sans-serif")
.attr("transform", function(d) {
var c = arc.centroid(d),
x = c[0],
y = c[1],
h = Math.sqrt(x*x + y*y);
return "translate(" + (x/h * labelr) + ',' +
(y/h * labelr) + ")";
})
.attr("text-anchor", function(d) {
// are we past the center?
return (d.endAngle + d.startAngle)/2 > Math.PI ?
"end" : "start";
})
.text(function (d) {
return d[0]+ " " + formatPercent(d[1]);
});



path.transition()
.attrTween("d", arcTween)
.duration(750);

path.exit().remove()



function arcTween(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t) {
return arc(i(t));
};
}

});

}
return graph;
}

var updateFunction = updatePie();
var container = d3.select("#chartDiv");

function update(data) {
container.datum(data).call(updateFunction);
}

var firstDataset = getChannelData("channelName1");

update(firstDataset);

document.getElementById("dropdown").addEventListener("click", reDrawChart);

function reDrawChart() {
var e = document.getElementById("dropdown");
var strUser = e.options[e.selectedIndex].innerHTML;
getChannelData("channelName2");
var secondDataset = getChannelData(strUser);
update(secondDataset);
}

Answer

As there is no fiddle provided I haven't run the code, but it would probably be helpful to use enter and exit selections when adding the labels (this also prevents duplicate labels on updates).

To do so change the bit where you add the labels:

text
  .enter()
  .append('text')
  //the rest of your test attributes

text
  .exit()
  .remove();

Now that doesn't immediately solve your problem, but next step would be logging the enter selection. if the enter selection is empty you probably have a problem with the data you are binding to text (issue with what pie(_data) returns).

If the enter selection is coming through correctly and has the labels you want to add to the DOM it must be in the way you add the labels. This looks fine however so I assume it's a problem with the data you are binding.

If you could add a console log of pie(_data) and the label enter selection I'll be happy to help further. (Or provide a fiddle with your problem).

Hope this helps.