Reputation: 25
I am trying to rewrite an example provided by d3.js. The original code had a function like this:
function interpolateValues(values, year) {
var i = bisect.left(values, year, 0, values.length - 1),
a = values[i];
if (i > 0) {
var b = values[i - 1],
t = (year - a[0]) / (b[0] - a[0]);
return a[1] * (1 - t) + b[1] * t;
}
return a[1];
}
where 'values' is an array which looked like this:
"income":[[1800,359.93],[1820,359.93],[1913,556.12],[1950,3363.02], etc.
however, we store data in a different manner. Unlike the "name":[[year,value]],... format, our data is stored in a different manner, much like a Database (sample data to follow):
{"region":"A","income":1178.0,"lifeExpectancy":788.0,"year":1800.0,"population":1292.0,"country":"Angola"},
{"region":"B","income":847.0,"lifeExpectancy":1183.0,"year":1800.0,"population":803.0,"country":"Benin"},
{"region":"A","income":798.0,"lifeExpectancy":765.0,"year":1801.0,"population":967.0,"country":"Angola"},
{"region":"B","income":1293.0,"lifeExpectancy":1497.0,"year":1801.0,"population":792.0,"country":"Benin"},
I am looking to replace the interpolateValues() function with a different one that goes something like this:
SELECT income FROM dataset WHERE year = 1980
I know this is SQL, I'm just using it to try and get the idea across. Basically you have an array with data, an array with years and I am looking for a function that returns data for a specific year.
The interpolation feature would be nice to have, but it isn't too critical, for now. The problem is that I am just learning to use js, and whatever I tried so far, failed bigtime.
Thanks for your help!
Edit: Some extra information for clarification:
I have this function, which works:
function provideData(year) {
return nations.map(function(d) {
return {
name: d.country,
region: d.region,
income: d.income,
population: d.population,
lifeExpectancy: d.lifeExpectancy
};
});
}
But, as you would expect it returns the full arrays resulting in an output of well over a hundred years' data. Now if only there was a way to return d.income if d.year == year..
Upvotes: 0
Views: 259
Reputation: 4107
You can do it with Alasql JavaScript SQL library.
This is an example:
var data = [ {"region":"A","income":1178.0,"lifeExpectancy":788.0,"year":1800.0,"population":1292.0,"country":"Angola"},
{"region":"B","income":847.0,"lifeExpectancy":1183.0,"year":1800,"population":803.0,"country":"Benin"},
{"region":"A","income":798.0,"lifeExpectancy":765.0,"year":1801,"population":967.0,"country":"Angola"},
{"region":"B","income":1293.0,"lifeExpectancy":1497.0,"year":1801,"population":792.0,"country":"Benin"}];
var res = alasql('SELECT MATRIX year, SUM(income) FROM ? GROUP BY year',[data]);
Try this example in jsFiddle.
Alasql uses standard SQL with some JavaScript extensions, so you can construct any expression
Upvotes: 0
Reputation: 7687
If you don't want to use underscore, this should be doable with a for loop.
var plotData = []
for(var i = 0; i < data.length; i++){
if(data[i].year == targetYear){
plotData.push(data[i]);
}
}
I believe that underscore uses a loop as well, so not much of a loss in efficiency. You can improve the efficiency of the for loop if you know that your data is ordered by breaking the for loop once your year exceeds your target year, with something like this:
function getData(data){
var plotData = []
for(var i = 0; i < data.length; i++){
if(data[i].year == targetYear){
plotData.push(data[i]);
} else if(data[i].year > targetYear){
return 0;
}
}
return 0;
}
To use interpolate, you can either build an array inside your for loop that matches the expected array, or call a.year
and a.value
instead of a[0]
and a[1]
.
Upvotes: 1
Reputation: 7746
You can try Underscore.js Find
and take a look at the answer: Filtering through a multidimensional array using underscore.js
Upvotes: 1