D3.js Legend Labels
To get the labels right, pass in the same data you use for the pie chart to the legend:
var legend = d3.select("#chart").append("svg")
.attr("class", "legend")
.attr("width", r)
.attr("height", r * 2)
.selectAll("g")
.data(data)
.enter().append("g")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("width", 18)
.attr("height", 18)
.style("fill", function(d, i) { return color(i); });
legend.append("text")
.attr("x", 24)
.attr("y", 9)
.attr("dy", ".35em")
.text(function(d) { return d.label; });
Jsfiddle here.
TFischer
I am a senior software developer who specializes in JavaScript, TypeScript, React, NodeJS, and C#
Updated on June 09, 2022Comments
-
TFischer almost 2 years
I have a pie graph, with a legend, that I made in D3.js. A PHP file parses JSON, and then that data is used to fill the chart. Everything works the way that I want it to, except that I cannot get the legend labels to match up with the right colour. Here is my code
var w = 490, h = 400, r = 180, inner = 70, color = d3.scale.category20c(); d3.json("script.php", function (data) { var max = d3.max(data, function(d) { return d.value; }); var sum = d3.sum(data, function(d) { return d.value; }); var vis = d3.select("#chart") .append("svg:svg") .data([data]) .attr("width", w) .attr("height", h) .append("svg:g") .attr("transform", "translate(" + r * 1.5 + "," + (r + 10) + ")") var arc = d3.svg.arc() .innerRadius(inner) .outerRadius(r); var arcOver = d3.svg.arc() .innerRadius(inner + 5) .outerRadius(r + 5); var arcLine = d3.svg.arc() .innerRadius(inner) .outerRadius(inner + 5); var pie = d3.layout.pie() .value(function(d) { return d.value; }); var textTop = vis.append("text") .attr("dy", ".35em") .style("text-anchor", "middle") .attr("class", "textTop") .text( "TOTAL" ) .attr("y", -10), textBottom = vis.append("text") .attr("dy", ".35em") .style("text-anchor", "middle") .attr("class", "textBottom") .text(sum.toFixed(2) + "m") .attr("y", 10); var arcs = vis.selectAll("g.slice") .data(pie) .enter() .append("svg:g") .attr("class", "slice") .on("mouseover", function(d) { d3.select(this).select("path").transition() .duration(100) .attr("d", arcOver) textTop.text( d3.select(this).datum().data.label ) textBottom.text( d3.select(this).datum().data.value.toFixed(2) + "m") }) .on("mouseout", function(d) { d3.select(this).select("path").transition() .duration(100) .attr("d", arc); textTop.text( "TOTAL" ) textBottom.text(sum.toFixed(2) + "m"); }); arcs.append("svg:path") .attr("fill", function(d, i) { return color(i); } ) .attr("d", arc); var legend = d3.select("#chart").append("svg") .attr("class", "legend") .attr("width", 100) .attr("height", 350) .selectAll("g") .data(color.domain().slice().reverse()) .enter().append("g") .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; }) legend.append("rect") .attr("width", 18) .attr("height", 18) .style("fill", color); legend.append("text") .attr("x", 24) .attr("y", 9) .attr("dy", ".35em") .text(function(d) { return d; }); })
I think I narrowed the problem down to
.text(function(d) { return d; });
. Right now, I'm assuming it returns the index number. If I change this line to.text(function(d, i) { return data[i].label; });
, the labels do not match up properly with the colours. I got this legend from here. I've looked at other examples as well (I can't link them because my reputation is not high enough), and I couldn't integrate them properly.Can someone help me figure out what is wrong? Thanks!