David
David

Reputation: 569

nested pie chart with d3.v4

I'm trying to draw pie chart. I've found the working example which was available in d3.v3. I've updated the d3 version to d3.v4 since then, chart is not working.

Tried to figure it out, but couldn't get the solution. Can any please suggest here what's wrong with this code

<!DOCTYPE html>
<html>
<head>
  <title>Pie</title>
  <script type="text/javascript" src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>

</body>
</html>

<script type="text/javascript">
  var dataset = {
  apples: [53245, 28479, 19697, 24037, 40245, 34234],
  oranges: [53245, 28479, 19697, 24037, 40245, 34234],
  lemons: [53245, 28479, 19697, 24037, 40245, 34234],
  pears: [53245, 28479, 19697, 24037, 40245, 34234],
  banana: [53245, 28479, 19697, 24037, 40245, 34234],
  pineapples: [53245, 28479, 19697, 24037, 40245, 34234],
};

var width = 460,
    height = 300,
    cwidth = 25;


// d3.v3
/* 
var color = d3.scale.category20();
var pie = d3.layout.pie().sort(null);
var arc = d3.svg.arc();
*/

// d3.v4
var color = d3.scaleOrdinal(d3.schemeCategory10);
var pie = d3.pie().sort(null);
var arc = d3.arc();

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

var gs = svg.selectAll("g").data(d3.values(dataset)).enter().append("g");
var path = gs.selectAll("path")
    .data(function(d) { return pie(d); })
    .enter().append("path")
    .attr("fill", function(d, i) { return color(i); })
    .attr("d", function(d, i, j) { return arc.innerRadius(10+cwidth*j).outerRadius(cwidth*(j+1))(d); });

</script>

Upvotes: 1

Views: 1289

Answers (1)

Mikhail Shabrikov
Mikhail Shabrikov

Reputation: 8509

You use third argument (j) here:

function(d, i, j) { return arc.innerRadius(10 + cwidth * j) ....

In d3v3 this argument is the index of the parent dataset, but in d3v4 it is the set (array) of dom-nodes. So you should store parent index somewhere. Rewrite your path variable this way:

var path = gs.selectAll("path")
    .data(function(d, i) {
      return pie(d).map(function(item) {
        return { data: item, parentIndex: i }; // save parent dataset index in parenIndex property
      });
    })
    .enter().append("path")
    .attr("fill", function(d, i) { return color(i); })
    .attr("d", function(d, i) { 
      return arc
        .innerRadius(10+cwidth*d.parentIndex)
        .outerRadius(cwidth*(d.parentIndex+1))(d.data);
    });

Check working example:

var dataset = {
  apples: [53245, 28479, 19697, 24037, 40245, 34234],
  oranges: [53245, 28479, 19697, 24037, 40245, 34234],
  lemons: [53245, 28479, 19697, 24037, 40245, 34234],
  pears: [53245, 28479, 19697, 24037, 40245, 34234],
  banana: [53245, 28479, 19697, 24037, 40245, 34234],
  pineapples: [53245, 28479, 19697, 24037, 40245, 34234],
};

var width = 460,
    height = 300,
    cwidth = 25;


// d3.v3
/* 
var color = d3.scale.category20();
var pie = d3.layout.pie().sort(null);
var arc = d3.svg.arc();
*/

// d3.v4
var color = d3.scaleOrdinal(d3.schemeCategory10);
var pie = d3.pie().sort(null);
var arc = d3.arc();

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

var gs = svg.selectAll("g").data(d3.values(dataset)).enter().append("g");
var path = gs.selectAll("path")
		.data(function(d, i) {
      return pie(d).map(function(item) {
        return { data: item, parentIndex: i };
      });
    })
    .enter().append("path")
    .attr("fill", function(d, i) { return color(i); })
    .attr("d", function(d, i) { 
      return arc
        .innerRadius(10+cwidth*d.parentIndex)
        .outerRadius(cwidth*(d.parentIndex+1))(d.data);
    });
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.12.0/d3.min.js"></script>

Upvotes: 2

Related Questions