I’m trying to update some older D3js code that relies on d3.nest
to the newest version (v7). This is an example of the raw data (from a csv) and the desired nested Object that I’m trying to achieve. Previously, this step relied on d3.nest
import * as d3 from "https://cdn.jsdelivr.net/npm/[email protected]/+esm";
var dummy;
var desired;
// example data from csv
dummy = [
{ variant: "0", year: "1950", mw: "m", pop: "31962", pop_0_4: "540" },
{ variant: "0", year: "1950", mw: "w", pop: "32052", pop_0_4: "545" },
{ variant: "0", year: "1951", mw: "m", pop: "31453", pop_0_4: "520" },
{ variant: "0", year: "1951", mw: "w", pop: "35444", pop_0_4: "526" },
{ variant: "1", year: "1950", mw: "m", pop: "41253", pop_0_4: "510" },
{ variant: "1", year: "1950", mw: "w", pop: "42356", pop_0_4: "515" },
{ variant: "1", year: "1951", mw: "m", pop: "45633", pop_0_4: "500" },
{ variant: "1", year: "1951", mw: "w", pop: "49500", pop_0_4: "501" },
];
console.log(dummy);
// desired format is an object I can reference using eg desired[1950].m[0][0]["pop_0_4"]
desired = {
1950: {
m: {
0: [
{ variant: "0", year: "1950", mw: "m", pop: "31962", pop_0_4: "540" },
],
},
w: {
0: [
{ variant: "0", year: "1950", mw: "m", pop: "32052", pop_0_4: "545" },
],
},
},
1951: {
m: {
0: [
{ variant: "0", year: "1951", mw: "m", pop: "31453", pop_0_4: "520" },
],
},
w: {
0: [
{ variant: "0", year: "1951", mw: "m", pop: "35444", pop_0_4: "526" },
],
},
},
1950: {
m: {
0: [
{ variant: "1", year: "1950", mw: "m", pop: "41253", pop_0_4: "510" },
],
},
w: {
0: [
{ variant: "1", year: "1950", mw: "m", pop: "42356", pop_0_4: "515" },
],
},
},
1951: {
m: {
0: [
{ variant: "1", year: "1951", mw: "m", pop: "45633", pop_0_4: "500" },
],
},
w: {
0: [
{ variant: "1", year: "1951", mw: "m", pop: "49500", pop_0_4: "501" },
],
},
},
};
console.log(desired);
console.log(desired[1950].m[0][0]["pop_0_4"]);
// In the old code this was done using
d3
.nest()
.key(function (d) {
return d.year;
})
.key(function (d) {
return d.mw;
})
.key(function (d) {
return d.variant;
})
.map(csv)
This is where I’ve got to using d3.groups
and js reduce
but I can’t work out how to convert the remaining nested arrays to objects. I want to be able to reference values in the final object as eg desired[1950].m[0][0]["pop_0_4"]
// my attempt - I can get close using d3.groups and reduce
// but I can't work out how to convert the remaining nested arrays to objects
var test;
test = d3
.groups(
dummy,
(d) => d.year,
(d) => d.mw,
(d) => d.variant
)
.reduce((acc, curr) => {
let obj = {};
curr[1].forEach((item) => (obj[item[0]] = item[1]));
acc[curr[0]] = obj;
return acc;
}, {});
console.log(test);
2
Answers
I recommend that you use
d3.group
, rather thand3.groups
, which returns nested Map objects, rather than nested arrays. As explained in this section of the MDN documentation, Maps are very much like Objects but often preferable in the context of data storage and access.Thus, you might try
You could then access the data like so:
Better yet, you could use
d3.rollup
, which is a lot liked3.group
but provides a reducer to the final result. That would allow you to remove the superfluous[0]
in your accessor. Thus:Then,
You can use vanilla to reach your goal too.