j.doezer j.doezer - 1 month ago 10
Javascript Question

Adding a legend to a D3.js pie chart

I have a d3.js pie chart
enter image description here

This is the code

<!DOCTYPE html>
<meta charset="utf-8">

<script src="https://d3js.org/d3.v3.min.js"></script>
<script>

var piecolors = d3.scale.category20c();

var w = 600,
h = 460,
r = (Math.min(w, h) - 50) / 2;


var dataFile = ".\\temp\\" + "<%=justOutFile.toString() %>";
d3.csv(dataFile, function(error, data) {

var svgPie = d3.select("#chart").append("svg")
.attr("width", w)
.attr("height", h)
.append("g")
.attr("transform", "translate(" + w / 2 + "," + h / 2 + ")");

var arc = d3.svg.arc()
.outerRadius(r)
.innerRadius(2);

var labelArc = d3.svg.arc()
.outerRadius(r-100)
.innerRadius(r-5);

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

var pie = svgPie.selectAll(".arc")
.data(pie(data))
.enter().append("g")
.attr("class", "arc");

pie.append("path")
.attr("d", arc)
.attr("data-legend", function(d){return d.data.BUSINESS_UNIT_GROUP})
.style("fill", function(d) { return piecolors(d.data.BUSINESS_UNIT_GROUP); });

pie.append("text")
.attr("transform", function(d) {
var midAngle = d.endAngle < Math.PI ? d.startAngle/2 + d.endAngle/2 : d.startAngle/2 + d.endAngle/2 + Math.PI ;
return "translate(" + labelArc.centroid(d)[0] + "," + labelArc.centroid(d)[1] + ") rotate(-90) rotate(" + (midAngle * 180/Math.PI) + ")"; })
.attr("dy", ".35em")
.attr('text-anchor','middle')
.style("font-size", "12px")
.style("font-weight", "900")
.style("font", "sans-serif")
.text(function(d) { return d.data.Distinct_Count + " " + d.data.BUSINESS_UNIT_GROUP + " " + d.data.PERCENTAGE + "%"; });

legend = svgPie.append("g")
.attr("class", "legend")
.attr("transform", "translate(50,30)")
.style("font-size", "12px")
.call(d3.legend)
});

</script>

<style>
.legend rect {
fill:white;
stroke:black;
opacity:0.8; }


body {
font: 10px 'Open sans', sans-serif;
}

.line {
fill: none;
stroke: black;
stroke-width: 1.2px;
}

div#chart {width: 100%;}

</style>

<body>
<div id="chart"></div>
</body>


What I am trying to do is, add in a legend to either side of my pie chart
all the examples I tried so far, I didn't understand. Can someone please help me create a legend. I am not sure if I have built the pie chart using best practices, if that is the case, please let me know.

Answer

d3 doesn't come with a method called legend. Therefore your line .call(d3.legend) will fail.

However, you can build d3.legend yourself. Here's an example from GitHub user ZJONSSON. Don't forget to credit him, if you use his code.

In case you have no luck with his code, you can easily do it yourself:

var legend = svg.selectAll('.legend-entry').data(data)
  .enter().append('g')
    .attr('class', 'legend-entry')

legend.append('rect')
  .attr('class', 'legend-rect')
  .attr('x', 0)
  .attr('y', function (d, i) { return i * 20 })
  .attr('width', 10)
  .attr('height', 10)
  .attr('fill', function (d) {
    return piecolors(d.data.BUSINESS_UNIT_GROUP)
   })

legend.append('text')
  .attr('class', 'legend-text')
  .attr('x', 25)
  .attr('y', function (d, i) { return i * 20 })
  .text(function (d) {
    return d.data.BUSINESS_UNIT_GROUP
  })

Add some styling, and you have a pretty decent legend. If you add some click handlers on each element, you can also implement a filter function.

Comments