Boat
Boat

Reputation: 529

d3.nest return sum of values for each row

I have a csv like that:

name,na,profile,one,two,three,four,
uni1,eng,impact,4,5,3,1
uni1,eng,overall,10,5,3,1
uni1,fr,impact,4,5,7,1
uni1,fr,overall,20,5,7,1
uni1,ger,impact,4,5,3,1
uni1,ger,overall,18,5,18,1
uni1,eng,impact,4,5,3,1
uni2,eng,overall,4,5,3,1
uni2,fr,impact,4,5,3,30
uni2,fr,overall,4,5,3,1
uni2,ger,impact,4,5,3,1
uni2,ger,overall,4,21,3,1
uni2,spain,impact,4,5,3,1
uni2,spain,overall,4,5,3,1
uni2,spain,impact,4,20,3,1
uni2,lat,overall,4,19,3,1
uni2,lat,impact,4,5,17,1

I would like to compute a d3 nest that will returned me for each uni and na the sum of the the one two three four value when profile === overall.

I woul like to have an array of object like :

array[object0{uni1{
                  eng{
                  value:230}]

I succed to get all the line with the overall value but I do not know how to return such things...

var nestedData = d3.nest()
            .key(function(d){return (d.profile=== "Overall").forEach(d.name);})
            //.rollup(function (v) { return d3.sum(v,function(d){return (d.four*4,d.three*3,d.two*2,d.one)/100 });})
            .sortKeys(d3.ascending)
            .entries(filteredData());

        console.log("Ranked :data",nestedData);

        return nestedData;

Upvotes: 0

Views: 412

Answers (1)

Gerardo Furtado
Gerardo Furtado

Reputation: 102174

Your desired outcome is not exactly clear because you didn't show us how do you want to position the inner array for different eng in the same uni.

Therefore, here is an solution (out of many), check the console to see the array's structure:

var csv = `name,na,profile,one,two,three,four,
uni1,eng,impact,4,5,3,1
uni1,eng,overall,10,5,3,1
uni1,fr,impact,4,5,7,1
uni1,fr,overall,20,5,7,1
uni1,ger,impact,4,5,3,1
uni1,ger,overall,18,5,18,1
uni1,eng,impact,4,5,3,1
uni2,eng,overall,4,5,3,1
uni2,fr,impact,4,5,3,30
uni2,fr,overall,4,5,3,1
uni2,ger,impact,4,5,3,1
uni2,ger,overall,4,21,3,1
uni2,spain,impact,4,5,3,1
uni2,spain,overall,4,5,3,1
uni2,spain,impact,4,20,3,1
uni2,lat,overall,4,19,3,1
uni2,lat,impact,4,5,17,1`;

var data = d3.csvParse(csv, function(d) {
  d.one = +d.one;
  d.two = +d.two;
  d.three = +d.three;
  d.four = +d.four;
  return d;
});

var filteredData = data.filter(function(d) {
  return d.profile === "overall"
});

var nestedData = d3.nest()
  .key(function(d) {
    return d.name;
  })
  .sortKeys(d3.ascending)
  .key(function(d) {
    return d.na
  })
  .rollup(function(v) {
    return v[0].one + v[0].two + v[0].three + v[0].four
  })
  .entries(filteredData);

console.log(nestedData)
<script src="https://d3js.org/d3.v4.min.js"></script>

PS: I know it's just me, but I was never a great fan of d3.nest(). I prefer to manipulate the data array the way I want with plain JavaScript functions... it's more versatile and you can structure the outcome exactly as you need.

EDIT: answering the Friday-challenge, this is the vanilla JavaScript to create the outcome described by OP (almost, because the inner objects have to be inside an array):

var finalArray = [];

[...new Set(filteredData.map(function(d) {
    return d.name
}))].forEach(function(d) {
    var tempObj = {
        [d]: []
    };
    filteredData.filter(function(e) {
        return e.name === d;
    }).forEach(function(e) {
        tempObj[d].push({
            [e.na]: e.one + e.two + e.three + e.four
        })
    });
    finalArray.push(tempObj)
});

Here is the demo:

var csv = `name,na,profile,one,two,three,four,
uni1,eng,impact,4,5,3,1
uni1,eng,overall,10,5,3,1
uni1,fr,impact,4,5,7,1
uni1,fr,overall,20,5,7,1
uni1,ger,impact,4,5,3,1
uni1,ger,overall,18,5,18,1
uni1,eng,impact,4,5,3,1
uni2,eng,overall,4,5,3,1
uni2,fr,impact,4,5,3,30
uni2,fr,overall,4,5,3,1
uni2,ger,impact,4,5,3,1
uni2,ger,overall,4,21,3,1
uni2,spain,impact,4,5,3,1
uni2,spain,overall,4,5,3,1
uni2,spain,impact,4,20,3,1
uni2,lat,overall,4,19,3,1
uni2,lat,impact,4,5,17,1`;

var data = d3.csvParse(csv, function(d) {
  d.one = +d.one;
  d.two = +d.two;
  d.three = +d.three;
  d.four = +d.four;
  return d;
});

var filteredData = data.filter(function(d) {
  return d.profile === "overall"
});

var finalArray = [];

[...new Set(filteredData.map(function(d) {
  return d.name
}))].forEach(function(d) {
  var tempObj = {
    [d]: []
  };
  filteredData.filter(function(e) {
    return e.name === d;
  }).forEach(function(e) {
    tempObj[d].push({
      [e.na]: e.one + e.two + e.three + e.four
    })
  });
  finalArray.push(tempObj)
});

console.log(finalArray)
<script src="https://d3js.org/d3.v4.min.js"></script>

Upvotes: 1

Related Questions