D3.js - how can I iterate through subarrays in my dataset

d3.js

Solution

There are a few things going wrong here that are all adding up to get a nice pie chart that isn't the chart you're trying to draw.

For starters, when you do the data join to your svg selection:

var svg = d3.select("body").selectAll("svg")
    .data([datad])

You are nesting your data array inside a new array (the square brackets), of which your data array is the only element. So you only get one `<svg>` from your `enter()` statement, not three. Change it to

var svg = d3.select("body").selectAll("svg")
    .data(datad)

And you get three `<svg>` elements, as you intended. But none of them have pie charts, because your pie chart function is failing to find the data values you told it to look for:

 var pie = d3.layout.pie()    
        .value(function(d, i) { return d.s[i]; });   

svg.selectAll("path")
    .data(pie)
  .enter().append("svg:path")

The pie chart function expects to be passed an array of data, and it will call the specified `value` function on each element of the array. You're telling it that each element of the array has an `s` property that is an array, and it should access an element from that array. That was working (sort of) when your pie function was being passed your entire original data array, but not now that we've split up the original data array into different SVG elements. Now the pie function is being passed a data object of the form `{s:[ 1, 1, 20], l:[ 30,300 ]}`, and doesn't know what to do with it.

So you need to change two things: you need to make sure that the pie function only gets passed the array of values it is supposed to use, and you need to tell it how to access the value from each element of that array. Except you don't actually have to do that second part, since the values are just raw numbers and the default value function will work:

 var pie = d3.layout.pie() 
       // .value(function(d, i) { return d; });  //default, not required

svg.selectAll("path")
      .data( function(d) { return pie(d.s); })
  .enter().append("svg:path")

The `d` value in the data join function is the data object attached to each `<svg>` element; the anonymous function extracts the sub-array and calls the pie function on it, to return the array of data for each of the `<path>` elements in that SVG.

Working fiddle: http://jsfiddle.net/H2SKt/706/

Problem

I'm trying to get d3 to iterate through sub-arrays in my data and generate multiple pie charts. Here is the complete code (hacked from https://gist.github.com/mbostock/1305111 and https://gist.github.com/enjalot/1203641): ``` <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>D3 Page Test</title> <script type="text/javascript" src="http://mbostock.github.com/d3/d3.js"></script> <style type="text/css"> body { text-align: center; } </style> </head> <body> <script type="text/javascript"> // Define the data as a two-dimensional array of numbers. If you had other // data to associate with each number, replace each number with an object, e.g., // `{key: "value"}`. var datad = [ {s:[ 20, 1, 1], l:[10,100]}, {s:[ 1, 20, 1], l:[ 20, 200]}, {s:[ 1, 1, 20], l:[ 30,300 ]} ]; // Define the margin, radius, and color scale. The color scale will be // assigned by index, but if you define your data using objects, you could pass // in a named field from the data object instead, such as `d.name`. Colors // are assigned lazily, so if you want deterministic behavior, define a domain // for the color scale. var m = 10, r = 100, z = d3.scale.category20c(); // Insert an svg:svg element (with margin) for each row in our dataset. A // child svg:g element translates the origin to the pie center. var svg = d3.select("body").selectAll("svg") .data([datad]) .enter().append("svg:svg") .attr("width", (r + m) * 2) .attr("height", (r + m) * 2) .append("svg:g") .attr("transform", "translate(" + (r + m) + "," + (r + m) + ")"); var pie = d3.layout.pie() //this will create arc data for us given a list of values .value(function(d, i) { return d.s[i]; }); //we must tell it out to access the value of each element in our data array // The data for each svg:svg element is a row of numbers (an array). We pass // that to d3.layout.pie to compute the angles for each arc. These start and end // angles are passed to d3.svg.arc to draw arcs! Note that the arc radius is // specified on the arc, not the layout. svg.selectAll("path") .data(pie) .enter().append("svg:path") .attr("d", d3.svg.arc() .innerRadius(0) .outerRadius(r + 2)) .style("fill", function(d, i) { return z(i); }); </script> </body> </html> ``` I am getting a single pie chart, and it is comprised of the value of "20" from each of my "s" arrays in my data set. The first pie piece is drawn from datad[0][0], the second from datad[1][1], and the third pie piece is drawn from datad[2][2]. I'm expecting three pie charts (one for each "s" array in my data). I think my problem is in: ``` var pie = d3.layout.pie() //this will create arc data for us given a list of values .value(function(d, i) { return d.s[i]; }); //we must tell it out to access the value of each element in our data array ``` How can I tell it to iterate over each s array, instead of iterating over both the datad and s array at the same time. That is, I want to iterate datad[0]s[0], datad[0]s[1], datad[0]s[2] ... datad[2]s[0], datad[2]s[1] (etc) instead of datad[0]s[0], datad[1]s[1], datad[2]s[2] Tips or pointers appreciated! Edit: here is the fiddle: jsfiddle.net/H2SKt/701/

Original source