12

The following example shows a donut chart in D3.js, is it possible to add more than one ring to the chart?

var dataset = {
  apples: [53245, 28479, 19697, 24037, 40245],
};

var width = 460,
    height = 300,
    radius = Math.min(width, height) / 2;

var color = d3.scale.category20();

var pie = d3.layout.pie()
    .sort(null);

var arc = d3.svg.arc()
    .innerRadius(radius - 100)
    .outerRadius(radius - 50);

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

var path = svg.selectAll("path")
    .data(pie(dataset.apples))
  .enter().append("path")
    .attr("fill", function(d, i) { return color(i); })
    .attr("d", arc);

Example: http://jsfiddle.net/gregfedorov/Qh9X5/9/

So in my data set I want something like the following:

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

What I want is to have 5 rings in total all around the same central point, is this possible and does anyone have an example?

nikoshr
  • 32,926
  • 33
  • 91
  • 105
CLiown
  • 13,665
  • 48
  • 124
  • 205

2 Answers2

17

Yes, you can do this quite easily. The key is to use nested selections. That is, you pass in your top level list of lists and create a container element for each list. Then you do the nested selection and draw the actual elements. In this particular case, you also need to adjust the radii of the arcs so that they don't overlap.

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

Updated jsfiddle here.

Lars Kotthoff
  • 107,425
  • 16
  • 204
  • 204
  • How can I specify a class based on the data set for each path that gets created? I want to be able to style the rings with css? – CLiown Jul 06 '13 at 23:52
  • 1
    In the same way as the other attributes, e.g. `.attr("class", function(d) { return "class" + d; })`. – Lars Kotthoff Aug 13 '13 at 10:12
  • @LarsKotthoff I have this radial chart in v3: https://jsfiddle.net/minnie_mouse/033jrrz8/ I've tried to implement it in v4 here: https://jsfiddle.net/minnie_mouse/758s1upm/ I've changed the method names to the v4 equivalent and fixed all other differences that I'm aware of between v3 and v4. But it's still giving errors and I dont know what else I have to fix. Do you have any ideas? I would really appreciate your help! Thanks so much! – PrincessBelle May 06 '17 at 09:06
  • @PrincessBelle [here](https://bl.ocks.org/mbostock/c150b717e18d387e1b98) is a similar chart with version 4. – Lars Kotthoff May 07 '17 at 17:18
  • @LarsKotthoff thanks, yes i've seen that and tried to do the same in https://jsfiddle.net/minnie_mouse/758s1upm/. but its not working and im unsure of what I'm doing wrong :( – PrincessBelle May 07 '17 at 23:31
2

Using the fiddle you posted, there is an "arc" defined in the fiddle here:

var arc = d3.svg.arc()
    .innerRadius(radius - 100)
    .outerRadius(radius - 50);

That arc is what's used to build the ring graph here:

var path = svg.selectAll("path")
    .data(pie(dataset.apples))
  .enter().append("path")
    .attr("fill", function(d, i) { return color(i); })
    .attr("d", arc);

So if you just made a different arc for each of your data sets with a variety of radii, you would have additional rings in your chart.

Randolpho
  • 55,384
  • 17
  • 145
  • 179
  • How to append multiple rings on the fly...I mean if we click on first ring then second ring will be appended...I need this because of the sub menu requirement for single area in arc...Please help me in this I stucked badly in it. – JS Rocker Jul 14 '14 at 10:38