define([], function () {
return function UDC(){
This module implements the Universal Data Cube client. Curran Kelleher 3/30/2014
define([], function () {
return function UDC(){
The index of data sources.
source
objects withdataSet
objects withdimensions
an object withdimension
objects withcolumn
the name of the column in the data tablecodeList
the name of the UDC CodeList used in the tabledomain
the set of codes actually present in the data tablemeasures
an object withmeasure
objects withcolumn
the name of the column in the data tablescale
the multiplication factor used in the tabletable
the data table from the CSV fileindex
the index mapping cells to values, an object with var sources = {};
return {
TODO handle failures, bogus URLs TODO write proper docs callback is optional
load: function (url, callback) {
d3.json(url + '.json', function (dataSet) {
var dimensionNames = _.keys(dataSet.dimensions).sort(),
measureNames = _.keys(dataSet.measures);
TODO validate config TODO var source = getSource(config.source); TODO test for multiple data sets
var source = sources[dataSet.source] = {};
source[dataSet.name] = dataSet;
d3.csv(url + '.csv', function (table) {
dataSet.table = table;
Compute dimension domains
dimensionNames.forEach(function (dimensionName) {
var dimension = dataSet.dimensions[dimensionName];
dimension.domain = domain(table, dimension.column);
});
Build the index
dataSet.index = {};
table.forEach(function (row) {
var cell = {}, values = {};
dimensionNames.forEach(function (dimensionName) {
var dimension = dataSet.dimensions[dimensionName];
cell[dimensionName] = {
code: row[dimension.column],
codeList: dimension.codeList
};
});
measureNames.forEach(function (measureName) {
var measure = dataSet.measures[measureName];
values[measureName] = parseFloat(row[measure.column]);
});
dataSet.index[key(cell)] = values;
});
if(callback && typeof callback === 'function') {
callback();
}
});
});
},
listSources: function () { return _.keys(sources); },
listDataSets: function (source) { return _.keys(sources[source]); },
listDimensions: function (source, dataSet) {
return _.keys(sources[source][dataSet].dimensions);
},
listMeasures: function (source, dataSet) {
return _.keys(sources[source][dataSet].measures);
},
getDomain: function (source, dataSet, dimension) {
return sources[source][dataSet].dimensions[dimension].domain;
},
getCodeList: function (source, dataSet, dimension) {
return sources[source][dataSet].dimensions[dimension].codeList;
},
getValue: function (source, dataSet, cell, measure) {
var scale = sources[source][dataSet].measures[measure].scale;
return sources[source][dataSet].index[key(cell)][measure] * scale;
},
waitFor: function waitFor(source, dataSet, callback) {
var exists = sources[source] && sources[source][dataSet],
loaded = exists && sources[source][dataSet].table;
if(loaded){
callback();
} else {
setTimeout(function () {
waitFor(source, dataSet, callback);
}, 10);
}
}
};
};
cell
is an object with
code
the code representing a dimension membercodeList
the name of the codeList used function key(cell){
var dimensionNames = _.keys(cell).sort();
var key = dimensionNames.map(function (dimensionName) {
var member = cell[dimensionName];
TODO compute and use canonical code based on loaded concordance tables. TODO write a unit test for this with simple data
return member.code;
}).join('|');
return key;
}
Computes the set of unique codes for a given dimension.
function domain(table, column){
var set = {};
table.forEach(function (row) { set[row[column]] = true; });
return _.keys(set);
}
});