Xnn04
Xnn04

Reputation: 91

D3 nesting - inconsistent number of levels

I’m trying to nest my JSON data in such a way that I can easily make a d3 tree out of it. I’ve got this code:

d3.json("dbdata/getdata", function(error, data) {


var nestedData = {
    "key":"root",
    "values":
       d3.nest()
            .key(function(d){return d.category1})
            .key(function(d){return d.category2})
            .key(function(d){return d.category3})
            .key(function(d){return d.category4})
            .entries(data) }

The problem I’m having is that not all of the entries in my data have all four categories assigned to them. Some of them have only category1 and category2, so in such a case I would like to have only two nodes on that one link (on the tree graph). But what happens here, is that all links get a four-level structure, even if they don’t have all the categories assigned. If I have a set with only two categories (category1 and category2), I get the category1 in the right place, the category 2 ends up at the end, and two levels of empty data are created in between them.

Is there a way in which I could specify what to ignore in the nesting process (in my data set empty categories are assigned “0”)? I’ve tried something like this:

.key(function(d){if(d.category2 !=="0")return d.category3})

But it only changes “0s” to “undefined” and doesn’t alter the structure.

Or maybe there is a way to change the d3 code so I it will ignore those empty levels? I’m new to d3 and my code is based entirely on this example: http://mbostock.github.io/d3/talk/20111018/tree.html

EDIT:

Given the data structure looking like this:

   elements = [
{name: 'johny', 
    category1: 'cat1',
    category2: 'cat2a'
},
{name: 'cindy', 
    category1: 'cat1',
    category2: 'cat2b',
    category3: 'cat3'

}]; 

I would like the d3 tree to look like this:

        cat2a - johny
        /       
   cat1
        \
        cat2b - cat3 - cindy

And currently I'm getting this:

        cat2a - undefined - johny
        /       
   cat1
        \
        cat2b - cat3 - cindy

Upvotes: 0

Views: 93

Answers (1)

Jamil R Khan
Jamil R Khan

Reputation: 406

EDIT:

You may not be able to accomplish this with d3.nest(), but you should be able to build an appropriate structure by iterating over each category of each element and building the children arrays. Here's a jsfiddle: https://jsfiddle.net/b1s65ydL/8/

var root, element, key, child, j, i, catHash;
var categoryPropertyNames = [
    'category4',
    'category3', 
    'category2', 
    'category1'
]; //in descending order
var nodeByName = Object.create(null); //dictionary to hold category nodes

root = {name: 'root', children: []};
for ( j = 0; j < elements.length; j++ ) {
    element = elements[j];
    child = element;
    for ( i = 0; i < categoryPropertyNames.length; i++ ) {
        key = categoryPropertyNames[i];
        if ( !element.hasOwnProperty(key) ) {
           continue;
        }
        catHash = element[key] + '-' + key;
        if ( nodeByName[catHash] === undefined ) {
            nodeByName[catHash] = {name: element[key], children: []}; 
        }
        var node = nodeByName[catHash];
        //add child to the array if is not already there
        if ( node.children.indexOf(child) == -1 ) {
            node.children.push(child);
        }
        child = node;
    }
    //child is now either the first category, or the element itself
    if ( root.children.indexOf(child) == -1 ) {
        root.children.push(child);
    }
}    

//d3 should be able to take it from here
var nodes = tree.nodes(root).reverse();    

I also found: http://learnjsdata.com/group_data.html to be helpful.

Upvotes: 1

Related Questions