0

I'm trying to get data parsed from CSVs in D3 -- parse once and store the arrays into variable(s) for multiple functions to have access to. I'm working inside a namespace module where the parent vars should make it possible, alas, no luck. Here is a simplified example:

var namespace = namespace || {};

namespace.module = function() {
  var dataItems;                   <== want to be accessible to all functions inside module

  function getData() {
    d3.csv('data.csv', function(d) { 
      dataItems = d; 
    });
  }

  function drawChartA() {
    // want to have access to parsed CSV data here
    console.log(dataItems);         <== "error: undefined"
  }

  return {
    getData:    getData,
    drawChartA: drawChartA
  }
}();

// run code 
$(document).ready(function() {
  namespace.module.getData();
  namespace.module.drawChartA();
});

The only way I seem to have access the parsed arrays is within the scope the getData() function, but not outside. I even tried calling getData() from inside the drawChartA method, first thing, same result. Another post was suggesting to store the vars under the Window object but shouldn't there be a way to handle it all inside the namespace module? Still learning about all that.. please advise! :)

pete
  • 2,739
  • 4
  • 32
  • 46

2 Answers2

3

One way is to call the function from inside the d3.csv call like this:

d3.csv('data.csv', function(error, data) {
    drawChartA(data);
}

Or you could enclose everything inside your drawChartA function like:

function drawChartA() {
    d3.csv('data.csv', function(error, data) {
        //Do chart A stuff
    }
}();

And here's a link to a post by Mike Bostock on a very similar subject.

Community
  • 1
  • 1
user1614080
  • 2,854
  • 1
  • 19
  • 22
  • Yes, I referenced that post when attempting to store the result in the global namespace var. I even tried Mike's recommendation: window.dataItems = d; but I still get undefined. I think it's something to do with the 'async' but I don't know how to get around it (yet). I'd hate to be loading & parsing the CSVs every time I need to get at the data.. – pete Sep 16 '13 at 14:54
  • If you call the drawChartA function from outside of the d3.csv you shouldn't reload your csv. Note that I've edited the post slighlty and added data to the drawChartA. If you want to avoid the appending a variable to the global space you could wrap everything up in a function and create a top level variable. – user1614080 Sep 16 '13 at 15:25
2

The second parameter of d3.csv is an async callback. It will hit server to load data.csv file. If you call drawChartA right away, you get null because the request has not returned.

You will need a callback in your getData function:

function getData(file, callback) {
  d3.csv(file, function(d) { 
    callback(d);
  });
}

Then you call drawing code in callback:

namespace.module.getData(function(data) {
  namespace.module.drawChartA();
});

For multiple CSVs load:

// files = ['data1.csv', 'data2.csv', 'data3.csv'];
function getAllData(files, callback) {
  var loadedCount = 0;
  for (var i = 0; i < files; i++) {
    getData(files[i], function(data) {
      dataItems = dataItems.concat(data);
      loadedCount++;
      if (loadedCount === files.length) {
        callback(dataItems);
      }
    }
  }
}

You can use it like this:

// display loading wheel
namespace.module.getAllData(['data1.csv', 'data2.csv', 'data3.csv'],
  function(dataItems) {
    // process data
    // hide loading wheel
    namespace.module.drawChartA();
});
Phuoc Do
  • 1,344
  • 10
  • 14
  • Thanks, I don't think it will work. Basically, I have a number of CSV files that I need loaded so that I can prepare different types of dataset arrays from them, and only then I would invoke D3 charting. These callbacks seem to limit me to one CSV per scope? I was hoping for a simple way to load the data into the global space var arrays.. – pete Sep 16 '13 at 18:09
  • Is there a way for my other functions to wait until the global space vars are loaded? Or some other way to pre-load a number of CSV files? – pete Sep 16 '13 at 18:15
  • Javascript request nature is async. It takes time to go to server and get data. You can have a function to load all your data, prepare data, then callback. I can add a function for loading multiple CSVs. While your data is loading, you can display loading status. Another approach is to return all data from web server when page is loaded. Your data is loaded in template. – Phuoc Do Sep 16 '13 at 19:44
  • Another approach is to use setTimeout to wait for data. But I would not recommend it. – Phuoc Do Sep 16 '13 at 19:53