سؤال

I'm building a d3.js chart that has some levels of nesting in the data, and I'm having trouble with specifying the key for lines when applying the data() function. Here's a simple look at the relevant bits.

My data is of this form:

[
    {
        name: 'United States',
        values: [ {year:1960, imports:12, exports:13}, etc... ]
    },
    {
        name: 'China',
        values: [ {year:1960, imports:10, exports:11}, etc... ]
    }
]

And I create the basic graph like this:

var svg = d3.select(this).selectAll('svg').data([data]);
var g = svg.enter().append('svg').append('g').attr('class', 'main');
g = svg.select('g.main')

That all seems fine. For each country in the data I'm drawing two lines, and so I group these together (as described in this answer).

var lines_g = g.selectAll("g.lines")
                  .data(function(d) { return d; },
                        function(d) { console.log(d.name); return d.name; });
lines_g.enter().append("g").attr("class", "lines");

That also seems to work fine - the console displays 'China' and 'United States' from the key part of the data() call.

But I'm struggling with adding a key to the lines within each lines_g group. For example, doing this:

lines_g.selectAll('path.line.imports')
         .data(function(d) { return [d.values]; },
               function(d) { console.log(d); return d.name; })
         .enter().append('path')
           .attr('class', 'line imports');

The console displays the array that I would have expected from logging d.values rather than just d:

[ {year:1960, imports:12, exports:13}, etc... ]

Why can't I access d, and therefore d.name, at that point? And, would it be correct to give lines within a group the same key as its group?

هل كانت مفيدة؟

المحلول

You are dealing with nested selections here. That is, you have a top-level selection for each country and for each one of those a sub-selection of only the values -- this is what you're doing when you say

.data(function(d) { return [d.values]; })

After that point, you have direct access only to what is in d.values. The key function that you're logging d from, is given the elements of the array you specify before -- [d.values].

If you need to access the name of the parent data element, I would recommend putting this information into the child elements as well. That is, each {year: 1960, ...} also has a name: 'China' member. You can achieve this with code like the following:

data.forEach(function(d) {
  d.values.forEach(function(e) {
    e.name = d.name;
  });
});

This duplicates a lot of information though and may not be necessary in your case. As you have only one data element per country, you could pass in [d] directly instead of [d.values]. This would require only a small change in the way the line generator is called and also give you access to the name of the country in your key function.

I've modified the jsfiddle from the other question to do that here.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top