From charlesreid1

Line 223: Line 223:
[1, 4, 9, 16, 25]
[1, 4, 9, 16, 25]
</pre>
</pre>
===Related: d3.zip===
A related function, to create arrays of arrays, is d3.zip:
https://github.com/mbostock/d3/wiki/Arrays#wiki-d3_zip

Revision as of 08:53, 7 August 2012

Loading Data

To load multiple (arbitrary number) CSV files:

var filesArray = ["myrandedata.csv","myrandndata.csv","myrandudata.csv"];                

var remaining = filesArray.length;                                                       

// from https://groups.google.com/forum/#!msg/d3-js/3Y9VHkOOdCM/YnmOPopWUxQJ             
filesArray.forEach( function(f) {                                                        
    d3.csv(f, function(data) {                                                           
        mydata[f] = data;
        if (!--remaining) doSomething();                                                 
    });                                                                                  
});                                                                                      

function doSomething() {
    filesArray.forEach( function(f) {                                                    
        console.log( mydata[f] );                                                        
    });                                                                                  
}

Things I learned about D3 while modifying Parallel example

  • Role of maps
  • Nesting functions
  • Scope of Javascript
  • How to use for loops instead of functions to avoid scope issues
  • How to load multiple files using a counter to avoid scope/asynchronous issues
  • The whole function notation
  • Loading data as CSV (associated array) or as text (plain multidimensional array)
  • Console
  • Accessing arrays using notation data[0] versus data['x1'] versus data.x1
  • Notation +p[d]


Miscellaneous Confusing Notation

Some notation I found confusing, but was able to eventually clear up:

+p[d]

Notation for Accessing Arrays

Depends on how you load the external data (see section #Loading External Data).

The following three are equivalent:

data[1]

data['x1']

data.x1


Console

Workflow with console...

Loading External Data

Two ways to load a CSV file with data:

First way is for CSV with headers, load as associative array (which allows you to access data using the keys):

Alternative method is for CSV with no headers, load as plain text into a "plain" multidimensional array:

// To parse csv as an array of arrays:
d3.text("myrandedata.csv", "text/csv", function(text) {
    var rows = d3.csv.parseRows(text);

    // Do stuff with rows here... 

    //console.log(rows.slice(1,5)); 

    var i1 = 6;
    var i2 = 12;
    rows.slice(i1,i2).forEach( function(d) {
        console.log("d1 = " + d[1] );
    });
    
    // Use map to turn a multidimensional array into a single dimensional array
    // (i.e., to grab a single column)
    thiscol = rows.slice(i1,i2).map( function(d) { return d[1]; });
    console.log( d3.max( thiscol ) );

});

D3 Function Notation

One of the most confusing things about looking at D3 code for the first time is that there are nested functions everywhere.

Functions are way of processing data inline/on the fly, without breaking up all your code.

Nesting Functions

Simple Nesting Functions Example

var abc=[1,2,3];
var def=[11,12,13];
var ghi=[21,22,23];

dummy = 1;
abc.forEach( function(x) {
    def.forEach( function(y) {
        ghi.forEach( function(z) {
            dummy = x*y*z;
            console.log( x + "*" + y + "*" + z + " = " + dummy );
        });
    });
});

results in:

1*11*21 = 231 
1*11*22 = 242 
1*11*23 = 253 
1*12*21 = 252 
1*12*22 = 264 
1*12*23 = 276 
1*13*21 = 273 
1*13*22 = 286 
1*13*23 = 299 
2*11*21 = 462 
2*11*22 = 484 
2*11*23 = 506 
2*12*21 = 504 
2*12*22 = 528 
2*12*23 = 552 
2*13*21 = 546 
2*13*22 = 572 
2*13*23 = 598 
3*11*21 = 693 
3*11*22 = 726 
3*11*23 = 759 
3*12*21 = 756 
3*12*22 = 792 
3*12*23 = 828 
3*13*21 = 819 
3*13*22 = 858 
3*13*23 = 897

Complex (Asynchronous) Nesting Functions Example

Too much nesting of functions can lead you into trouble if you're trying to modify global variables, however, as nested functions change scope.

This happens because function calls are asynchronous. When the functions are simple, as in the above example, it's no problem, but when the functions become more complicated, they are asynchronous, leading to problems if you're depending on your functions to modify a global variable. For example:

results in:


Working Around Asynchronous Functions

Multiple ways to get around them. One way is to use for loops.

Another way is to force synchronicity, with a counter triggering a call to a function.


Role of Maps

Array maps are really handy, because they create a mapping of an existing array to a new one. This can be used to transform an array (for example, you could take an array of numbers and transform it into an array of squares of those numbers) or to expand/reduce an array (for example, you could take a two-dimensional array and find the sum of each element over a particular dimension).

Expansion Example: Single Dimension to Multiple Dimension Array

var abc=[1,2,3,4,5];
def = abc.map( function(d) { return [ +d, +d + 4 ] } ); 
def.forEach( function(p) {
    console.log(p);
}

Results in:

[1, 5]
[2, 6]
[3, 7]
[4, 8]
[5, 9]

Contraction Example: Multiple Dimension to Single Dimension Array

var abc=[[1,1],[2,4],[3,9],[4,16],[5,25],[6,36]];                                        
def = abc.map( function(d) { return d[1] } );                                            
console.log(def);

Results in:

[1, 4, 9, 16, 25, 36] 

Transformation Example: Values to Squared Values

var abc=[1,2,3,4,5];
def = abc.map( function(d) { return Math.pow(+d,2) } );
console.log(def);

results in:

[1, 4, 9, 16, 25]

Related: d3.zip

A related function, to create arrays of arrays, is d3.zip:

https://github.com/mbostock/d3/wiki/Arrays#wiki-d3_zip