d3 - creating lookup with nest/group

Viewed 115

Using the d3.js library, I wanted to create a lookup like so:

var lookup = d3.nest()
  .key((d: any) => d.day)
  .rollup((leaves: any) => {
    return d3.sum(leaves, (d: any) => { return parseInt(d.count); }) as any;
  })
  .object(dateData);

So I can use it later:

rect.filter(function (d) { return d in lookup; })
  .style("fill", function (d) { return d3.interpolatePuBu(scale(lookup[d])); })
  .select("title")
  .text((d) => this.titleFormat(new Date(d)) + ":  " + lookup[d]);

Unfortunately this has been throwing a:

"export 'nest' (imported as 'd3') was not found in 'd3'

After much search I found out that in v4 of d3, which I am using nest was replaced with group. Now I can't find anything in the documentation and I was trying to achieve similar with:

var lookup = d3.group(data, (d: any) => d.day)
  .rollup((leaves: any) => {
    return d3.sum(leaves, (d: any) => { return parseInt(d.count); }) as any;
  })
  .object(dateData);

But this doesn't seem to even compile. How would I go around achieving what I am trying to do?

1 Answers

So your question is how to get a result similar to the one below, but in d3 v4.

var dateData = [
  { day: 1, count: 2 },
  { day: 1, count: 3 },
  { day: 1, count: 4 },
  { day: 2, count: 2 },
  { day: 4, count: 1 },
  { day: 5, count: 0 },
];
var lookup = d3.nest()
  .key((d) => d.day)
  .rollup((leaves) => d3.sum(leaves, (d) => parseInt(d.count)))
  .entries(dateData);
console.log(lookup);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>


Note that there is a perfectly fine ES6 only solution:

var dateData = [
  { day: 1, count: 2 },
  { day: 1, count: 3 },
  { day: 1, count: 4 },
  { day: 2, count: 2 },
  { day: 4, count: 1 },
  { day: 5, count: 0 },
];

// First, map it to a { [day]: [sum counts] } structure
// { "1": 9, "2": 2, "4": 1, "5": 0 }
var lookup = dateData.reduce((obj, { day, count }) => {
    // || 0 means that if the value is undefined, it will use 0 instead
    obj[day] = (obj[day] || 0) + parseInt(count);
    return obj;
  }, {});

// Secondly (if you want), map it to a the same structure as the v3 example
lookup = Object.entries(lookup)
  .map(([key, values]) => ({ key, values }));

console.log(lookup);

Related