rinatoptimus
rinatoptimus

Reputation: 421

How to add legend to a pie chart D3.js?

I've looked through similar questions but still can't implement code correctly.

var width = 960,
height = 500,
radius = Math.min(width, height) / 2;
var color = d3.scale.ordinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);

var percentageFormat = d3.format("%");

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

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

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

d3.json("staff.json", function(error, json_data) {

var data = d3.nest()
.key(function(d) {
  return d.Position;
})
.rollup(function(d) {
  return d.length;
}).entries(json_data);

data.forEach(function(d) {
d.percentage = d.values / json_data.length;
});

console.log("data variable", data);
console.log("pie(data)", pie(data));

var g = svg.selectAll(".arc")
.data(pie(data))
.enter().append("g")
.attr("class", "arc")
.on('mouseover', function() {
  var current = this;  
  var others = svg.selectAll(".arc").filter(function(el) {
    return this != current
  });
  others.selectAll("path").style('opacity', 0.8);
})
.on('mouseout', function() {
  var current = this;
  d3.select(this)
    .style('opacity', 1);
  var others = svg.selectAll(".arc").filter(function(el) {
    return this != current
  });
  others.selectAll("path").style('opacity', 1);
});


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

g.append("text")
.attr("transform", function(d) {
  return "translate(" + arc.centroid(d) + ")";
})
.attr("dy", ".35em")
.style("text-anchor", "middle")
.text(function(d) {
  console.log("d is", d);
  return percentageFormat(d.data.percentage);
});

Here's a JSON-file:

[{
"Position" : "Programmer",
    "Name" : "Giacomo Gulizzoni",
     "Age" : 37,
     "Sex" : "Male",
 "Project" : "SmartFactory"
}, {
"Position" : "Tester",
    "Name" : "Marko Botton",
     "Age" : 34,
     "Sex" : "Male",
 "Project" : "SmartFactory"
}, {
"Position" : "Tester",
    "Name" : "Mariah Maclachian",
     "Age" : 37,
     "Sex" : "Female",
 "Project" : "SmartFactory"
}, {
"Position" : "Tester",
    "Name" : "Valerie Liberty",
     "Age" : 25,
     "Sex" : "Female",
 "Project" : "SmartProject"
}, {
"Position" : "Programmer",
   "Name " : "Guido Jack Gulizzoni",
     "Age" : 22,
     "Sex" : "Male",
 "Project" : "SmartProject"
}]

Actually, legends are just rectangles that are bound to data if I'm not mistaken. But in my case items in JSON file are not numerical values. Have look at my plunk for the results of my experiments.

Upvotes: 1

Views: 1796

Answers (2)

saikiran.vsk
saikiran.vsk

Reputation: 1796

Actually it was in your code,

var legend = svg.selectAll('.legend')                     // NEW
          .data(pie(data))                                   // NEW
          .enter()                                                // NEW
          .append('g')                                            // NEW
          .attr('class', 'legend')                                // NEW
          .attr('transform', function(d, i) {                     // NEW
            var height = legendRectSize + legendSpacing;          // NEW
            var offset =  height * pie(data).length / 2;     // NEW
            var horz = -2 * legendRectSize;                       // NEW
            var vert = i * height - offset;                       // NEW
            return 'translate(' + horz + ',' + vert + ')';        // NEW
          }); 
        legend.append('rect')                                     // NEW
          .attr('width', legendRectSize)                          // NEW
          .attr('height', legendRectSize)                         // NEW
          .style('fill', function(d,i){return color(i);})                                   // NEW
          .style('stroke', function(d,i){return color(i);});                                // NEW

        legend.append('text')                                     // NEW
          .attr('x', legendRectSize + legendSpacing)              // NEW
          .attr('y', legendRectSize - legendSpacing)              // NEW
          .text(function(d) { console.log("text: ");console.log(d);return d.data.key; }); 

I've un commented and did little changes. You can observe the code.

Upvotes: 0

Cyril Cherian
Cyril Cherian

Reputation: 32327

In your code:

You are setting the data in the legend selection wrong

  var legend = ...
  .data(pie(data))//this is wrong
  .enter().append("g")

You need to do like this

      var legend = d3.select("body").append("svg")
      .attr("class", "legend")
      .selectAll("g")
      .data(data)//setting the data as we know there are only two set of data[programmar/tester] as per the nest function you have written
      .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(d.key);
});

  legend.append("text")
      .attr("x", 24)
      .attr("y", 9)
      .attr("dy", ".35em")
      .text(function(d) { return d.key; });

Working code here

Hope this helps!

Upvotes: 2

Related Questions