14

I have an array or objects consisting of a date and some values:

var flatData = [
    { "date": "2012-05-26", "product": "apple"  },
    { "date": "2012-07-03", "product": "orange" },
    ...
]

I am trying to use d3.nest() to get a count of these objects by year and then by month.

var nestedData = d3.nest()
    .key(function(d) { return d.date.split('-')[0]; })  // key is the year
    .sortKeys(d3.ascending)
    .key(function(d) {
        var splitDate = d.date.split('-');
        return splitDate[0] + '-' + splitDate[1]; // key is year-month
    })
    .sortKeys(d3.ascending)
    .rollup(function(d) {
        return d.length;
    })
    .entries(flatData);

This almost works, except that when there are no objects for a month, the nested data does not contain a record indicating a count of 0 for that month. Is there any trick to tell D3 to fill in these gaps?

(Of course, I can always do it the tedious way, i.e. to loop through all the nested levels and create a new data structure that fills in the gaps.)

Naresh
  • 23,937
  • 33
  • 132
  • 204
  • What do you mean by filling the gaps, i.e. what count do you want it to return if there is nothing? – Lars Kotthoff Jul 02 '13 at 08:41
  • 1
    I want it to return an object with count of 0. That way when I am using the information to draw a bar chart, there is a record for every bar and I can simply loop through the objects. The alternative approach I was thinking of is not to assume a record for every bar and adjust the chart rendering algorithm accordingly. – Naresh Jul 02 '13 at 12:04
  • There's nothing in D3 for this, but you can fill in the missing values by iterating over the nested structure afterwards. – Lars Kotthoff Jul 02 '13 at 13:03
  • Thanks for confirming. Will do exactly as you suggest. – Naresh Jul 02 '13 at 13:31
  • 1
    You could alternatively use a date range for one of your axes - there will only be bars at the dates which exist. – minikomi Aug 27 '13 at 09:01

1 Answers1

9

Try adding the missing data points after reduction:

var flatData = [
    { "date": "2012-05-26", "product": "apple"  },
    { "date": "2012-07-03", "product": "orange" }]

nestedData = d3.nest()
    .key(function(d) { return d.date.split('-')[0]; })  // key is the year
    .sortKeys(d3.ascending)
    .key(function(d) {
        var splitDate = d.date.split('-');
        return splitDate[0] + '-' + splitDate[1]; // key is year-month
    })
    .sortKeys(d3.ascending)
    .rollup(function(d) {
        return d.length;
    })
    .entries(flatData);


yMFormat = d3.time.format('%Y-%m')

makeAllKeys = function(year) {
    allKeys = [];
    for(var i = 0; i<12;i++) {  // 12 months in a year
        allKeys.push(yMFormat(new Date(year,i,1)));
    }
    return allKeys;
}

nestedData = nestedData.map(function(yearObj) {
    return {
        values: makeAllKeys(+yearObj.key).map(function(k) { 
                value = yearObj.values.filter(function(v) { return v.key == k; })[0];
                return value || ({key: k, values: 0});
            })
    };
});
homam
  • 1,945
  • 1
  • 19
  • 26