Richard
Richard

Reputation: 65600

How to simplify this D3 code?

I've got some CSV data that looks like this, showing pass rates by organisation by year:

org,org_cat,2004_passed,2004_total,2005_passed,2005_total,2006_passed,2006_total
GSK,industry,35,100,45,100,55,100

I'm working in D3, and I'd like to end up with a dictionary of organisations like this:

data = {
 'GSK': {
     'org_cat': 'industry',
     'data': [
        { 'year': 2004, 'passed': 35, 'total': 100 },
        { 'year': 2005, 'passed': 45, 'total': 100 },
        { 'year': 2006, 'passed': 55, 'total': 100 }
     ]
  ]
}

Most of this is straightforward, but I've got very messy code for the year columns:

var data = {};
allData.forEach(function(d) {
  data[d.org] = {
    'category': d.org_cat,
    'data': []
  };
  for (var k in d) {
    var temp = {};
    for (var k in d) {
      if (patt.test(k)) {
        var res = k.split("_");
        if (res[0] in temp) {
          temp[res[0]][res[1]] = +d[k];
        } else {
          temp[res[0]] = {};
          temp[res[0]][res[1]] = +d[k];
        }
      }
    }
    var tempArr = [];
    for (var y in temp) {
      var tempDict = {};
      tempDict.year = y;
      tempDict.passed = temp[y].passed;
      tempDict.total = temp[y].total;
      tempArr.push(tempDict);
    }
    // TODO: sort by year in case the keys got shuffled
    data[d.org].data = tempArr;
  }
});

Is there a way to simplify this horrid code?

It's safe to assume that each row is a unique organisation.

Upvotes: 0

Views: 55

Answers (1)

thatOneGuy
thatOneGuy

Reputation: 10642

I don't see why you need D3 to do this. You're code doesn't use it either. Here's how I would do it, I'm sure there's another simpler way but it may help you either way :

Jsfiddle : https://jsfiddle.net/thatOneGuy/dnvheznk/1/

I converted the data to JSON to use with JSFiddle, but you already know how to loop through CSV so just overwrite line 14 :

for (var i = 0; i < data.length; i++) { //loop through data array (this is so you can use this on a bigger sized array) 

To your loop :

allData.forEach(function(d, i) { //but add the 'i' to index

Here is full commented code with converted JSON data :

var data = [{ //data set converted to JSON for easier use
  "org": "GSK",
  "org_cat": "industry",
  "2004_passed": 35,
  "2004_total": 100,
  "2005_passed": 45,
  "2005_total": 100,
  "2006_passed": 55,
  "2006_total": 100
}];

var newData = {}; //new data container

for (var i = 0; i < data.length; i++) { //loop through data array (this is so you can use this on a bigger sized array)
  var thisObj = {}; //create empty object
  thisObj.org_cat = data[i].org_cat; //set org_cat
  thisObj.data = []; //set data to empty array to populate later

  for (var key in data[i]) { //loop through data[i]
    if (key != 'org' && key != 'org_cat') { //check this key is not org or org_cat
      var thisData = {}; //create empty data object
      var thisYear = key.toString().substring(0, 4); //get year by using substring

      thisData.year = thisYear; //set year
      thisData.passed = data[i][thisYear + '_passed']; //set passed at this year
      thisData.total = data[i][thisYear + '_total']; //set total at this year

      thisObj.data.push(thisData); //push this data to data array
    }
  }
  var uniqueDates = []; //set empty array to use to remove duplicate items in data array
  for (var j = 0; j < thisObj.data.length; j++) { //loop through data array created earlier
    if (uniqueDates.indexOf(thisObj.data[j].year) < 0) { //if this year doesn't exist in unique array above, push it in
      uniqueDates.push(thisObj.data[j].year); //push it in
    } else {
      thisObj.data.splice(j--, 1); //remove duplicate data
    }
  }
  newData[data[i].org] = thisObj; //set data @ current org to be object created above
}
console.log('newData', newData) //log new data

Upvotes: 2

Related Questions