Search code examples
d3.jslegendpie-chart

legend not visible in d3.js pie chart


I am trying to add legend to pie chart. I can see the legend element added in the inspect element but I am not able to see it. Could it be due to background color ? I looked into other questions but I am not able to solve the problem.

Can somebody explain what is wrong with my code ?

I also pasted the image below showing that the legend is attached to the svg.

Here is the code snippet

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>barchart</title>
  <script type="text/javascript" src="https://d3js.org/d3.v5.min.js"></script>
</head>

<body>
  <div id="piechart">

  </div>
  <script>
    //chart dimensions

    var width = 300;
    var height = 300;
    var radius = Math.min(width, height) / 2;
    var labelHeight = 18;
    var data = {
      2011: 9,
      2012: 12,
      2013: 10,
      2014: 8,
      2015: 12,
      2016: 20
    }

    //color scale
    var color = d3.scaleOrdinal().range(["#126608", "#049a0d", "#587b08", "#048440", "#177c0a", "#4a8d36", "#3b712b", "#4a8b00", "#426b07", "#4b940b"]);

    //arc

    var arc = d3.arc()
      .outerRadius(radius - 10)
      .innerRadius(0);

    var pie = d3.pie()
      .value(function(d) {
        return d.value;
      })

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


    var pie_data = pie(d3.entries(data))
    console.log(pie_data)

    //svg.selectAll("path").remove()

    var g = svg.selectAll("path")
      .data(pie_data)
      .enter().append("g")
      .attr("class", "arc");

    g.append("path")
      .attr("d", arc)
      .style("fill", function(d) {
        return color(d.data.key)
      });

    g.append("text")
      .attr("transform", function(d) {
        return "translate(" + arc.centroid(d) + ")";
      })
      .attr("dy", ".35em")
      .style("text-anchor", "middle")
      .attr("fill", "white")
      .text(function(d) {
        return d.data.key
      });

    var legend = svg.append("g")
      .attr("class", "legend")
      .attr("font-family", "sans-serif")
      .attr("font-size", 20)
      .attr("text-anchor", "start")
      .selectAll("g")
      .data(pie_data)
      .enter().append("g")
      .attr("transform", function(d, i) {
        return "translate(0," + i * 30 + ")";
      });

    legend.append("text")
      .attr("x", radius + 30)
      .attr("y", 9.5)
      .attr("dy", "0.32em")
      .text(function(d) {
        return d.data.key;
      });

    legend.append("rect")
      .attr("x", radius + 10)
      .attr("width", 19)
      .attr("height", 19)
      .attr("fill", function(d) {
        return color(d.data.key);
      });
  </script>
</body>

</html>

the legend element attached to svg


Solution

  • You simply missed to set a proper with for the content, but what you have to actually do is to implement margin convention for your chart:

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>barchart</title>
      <script type="text/javascript" src="https://d3js.org/d3.v5.min.js"></script>
    </head>
    
    <body>
      <div id="piechart">
    
      </div>
      <script>
        //chart dimensions
    
        var width = 500;
        var height = 300;
        var radius = Math.min(width, height) / 2;
        var labelHeight = 18;
        var data = {
          2011: 9,
          2012: 12,
          2013: 10,
          2014: 8,
          2015: 12,
          2016: 20
        }
    
        //color scale
        var color = d3.scaleOrdinal().range(["#126608", "#049a0d", "#587b08", "#048440", "#177c0a", "#4a8d36", "#3b712b", "#4a8b00", "#426b07", "#4b940b"]);
    
        //arc
    
        var arc = d3.arc()
          .outerRadius(radius - 10)
          .innerRadius(0);
    
        var pie = d3.pie()
          .value(function(d) {
            return d.value;
          })
    
        var svg = d3.select("#piechart").append("svg")
          .attr("width", width)
          .attr("height", height)
          .append("g")
          .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
    
    
        var pie_data = pie(d3.entries(data))
    
        //svg.selectAll("path").remove()
    
        var g = svg.selectAll("path")
          .data(pie_data)
          .enter().append("g")
          .attr("class", "arc");
    
        g.append("path")
          .attr("d", arc)
          .style("fill", function(d) {
            return color(d.data.key)
          });
    
        g.append("text")
          .attr("transform", function(d) {
            return "translate(" + arc.centroid(d) + ")";
          })
          .attr("dy", ".35em")
          .style("text-anchor", "middle")
          .attr("fill", "white")
          .text(function(d) {
            return d.data.key
          });
    
        var legend = svg.append("g")
          .attr("class", "legend")
          .attr("font-family", "sans-serif")
          .attr("font-size", 20)
          .attr("text-anchor", "start")
          .selectAll("g")
          .data(pie_data)
          .enter().append("g")
          .attr("transform", function(d, i) {
            return "translate(0," + i * 30 + ")";
          });
    
        legend.append("text")
          .attr("x", radius + 30)
          .attr("y", 9.5)
          .attr("dy", "0.32em")
          .text(function(d) {
            return d.data.key;
          });
    
        legend.append("rect")
          .attr("x", radius + 10)
          .attr("width", 19)
          .attr("height", 19)
          .attr("fill", function(d) {
            return color(d.data.key);
          });
      </script>
    </body>
    
    </html>