D3.js Legend Labels

11,415

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.

Share:
11,415
TFischer
Author by

TFischer

I am a senior software developer who specializes in JavaScript, TypeScript, React, NodeJS, and C#

Updated on June 09, 2022

Comments

  • TFischer
    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; });
    })
    

    JSFIDDLE

    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!