How do I produce an interpolation function given n data points? - javascript

I am faced with the problem of trying to interpolate values between points on a series plot i.e. my data looks like the following (please assume random x,y coordinates)
[[x0,y0], [1,1] ,[2,2], [2,3],.....[x,y]]
and from the interpolator, I would like to give it 1.5 and the interpolator function should return 1.5 for this case. In other cases where data is random, it should find a best fit for the given set of points and return the y value for the given x value
Is this possible using d3 interpolate*** functions?
Thanks

Although you could do this with d3 interpolators, it would probably be easier to use a muli-part linear scale.
Usually, linear scales have a two-value domain and a two-value range, and all other values are calculated from the straight line between the start and end points of domain and range. However, you can set both domain and range to an array of many values (so long as both arrays are the same length), and the scale will act as a series of straight-line relationships for each section of the domain.
In other words, if you use your array of x-values as the scale's domain, and your array of y-values as the range, then you can input any x value and the scale will return the linear interpolation between adjacent y values. For values outside your points, it will extrapolate the initial or final linear relationship:
var points = [
[0,10],
[1,32],
[2,14],
[3,15]
];
var multiLine = d3.scale.linear()
.domain(
points.map(function(p){return p[0];})
)
.range (
points.map(function(p){return p[1];})
);
document.body.innerHTML =
"Line at 0.0: " + multiLine(0) + "<br/>" +
"Line at 1.0: " + multiLine(1) + "<br/>" +
"Line at 1.5: " + multiLine(1.5) + "<br/>" +
"Line at 2.3: " + multiLine(2.3) + "<br/>" +
"Line at 3.0: " + multiLine(3) + "<br/>" +
"Line at 4.0: " + multiLine(4) ;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
Note that you'll need to make sure that your points are sorted by x-value in order for this to work as expected.

Related

Output/Generate a set of points from individual equations - Python, JS, Matlab

I began with a set of coordinates, which I then approximated a function to represent them (Fourier series). The function produced is a sum of sin and cos waves:
0.3sin(2x) + 1.7(sin5x) + 1.8(sin43x)...
I would like to take this new function that I generated and produce a new set of coordinates. How can I generate points for every [INTEGER X Value] say from 0-400?
Note: I have 2 complex (2D) functions.
GOAL: Take a function --> Generate Points from this function for every whole integer.
This uses a function handle and (:) to force a column vector ((:).' forces a row vector).
The code simply uses the given equation (summing sines and cosines) to calculate a corresponding y coordinate for each given x coordinate.
% MATLAB R2018b
X = 0:400; % x = 0, 1, 2, ..., 400
fh = #(x) 0.3*sin(2*x) + 1.7*sin(5*x) + 1.8*sin(43*x);
Y = fh(X);
P = [X(:) Y(:)];
Note that size(P) returns 401 x 2. You'll see Y takes on whatever size X is, which is a row vector. X can be declared as as column vector with X = (0:400).' using .' which performs a transpose.
Recommend taking a look at MATLAB's documentation, specifically the Getting Started and Language Fundamentals.
Relevant MATLAB functions: sin, cos.
Matlab Code
X = 0:400;
fh = #(x) 0.3*sin(2*x) + 1.7*sin(5*x) + 1.8*sin(43*x);
Y = fh(X);
P = [X, Y]

Loop through attributes but only output certain ones - javascript

I dont know much of js but I have a code that with a little modification, will do exactly what I want. So here is a part of it that Im stuck. I have some visual objects that have several attributes, most of these attributes are needed for drawing them on the map so I cant just comment them out. I also have a function that prints all the attributes of the object on("mouseover"). I want it to only display the attributes I want, not all.
.on("mouseover", function(d) {
var out = "";
out += d.name + "<br /><br />";
for (v in d) {
out += (!Number.isNaN(Number(d[v])) ? v + ": " + Number(d[v]) + "<br />" : "");
}
document.getElementById("detail").innerHTML = out;
}
I understand what this code does, but what is the most elegant way to constraint the for loop or the out to only include the attributes I want?
The current outcome
obj name
attrIwant1: value
attrIwant2: value
attrIwant3: value
attrIwant4: value
w: blah
x: blah
y: blah
z: blah
I only want to display up until w:blah.
Put the attributes you care about in a set, then when you loop, see if d[v] belongs to the set.
const set1 = new Set(['attrIWant1', 'attrIWant2']); // add the attributes here
for (v in d) {
if (set1.has(d[v])) {
// this is one we care about
}
}
Read more about sets here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
If you always expect the same number of attributes, you can terminate the loop early when out has a certain number of <br />'s in it.
In your example you want to stop when you have 4 attributes, so you would terminate the loop when out contains 6 <br />'s. Your new for loop would be this:
for (v in d) {
out += (!Number.isNaN(Number(d[v])) ? v + ": " + Number(d[v]) + "<br />" : "");
if (out.match(/<br \/>/g).length === 6) break;
}
It is not "elegant", but it's probably the best you'll get without telling me what d is :^)

d3.min / d3.max - getting values with related date

I'm using d3.js for displaying some line-graphs based on a csv-file which holds the SERP-rankings for different keywords for each day.
The structure of the csv-file looks like this:
Keyword,Date,Google
Keyword1,2015/5/24,6
Keyword1,2015/5/25,6
Keyword1,2015/5/26,6
Keyword1,2015/5/27,6
Keyword1,2015/5/28,6
Keyword1,2015/5/29,6
Keyword1,2015/5/30,6
Keyword1,2015/5/31,6
Keyword1,2015/6/1,6
Keyword1,2015/6/2,6
Keyword1,2015/6/3,6
Keyword1,2015/6/4,6
Keyword1,2015/6/6,6
Keyword1,2015/6/7,6
Keyword1,2015/6/8,6
Keyword1,2015/6/9,6
Keyword1,2015/6/10,6
Keyword1,2015/6/11,6
Keyword1,2015/6/12,6
Keyword1,2015/6/13,6
Keyword1,2015/6/14,6
Keyword1,2015/6/16,6
Keyword1,2015/6/17,6
Keyword1,2015/6/18,6
Keyword1,2015/6/19,6
Keyword1,2015/6/20,6
Keyword1,2015/6/21,20
Keyword1,2015/6/22,20
Keyword1,2015/6/23,20
Keyword1,2015/6/24,20
Keyword1,2015/6/25,21
Keyword1,2015/6/26,21
Keyword1,2015/6/27,21
Keyword1,2015/6/28,21
Keyword1,2015/6/29,21
Keyword1,2015/6/30,21
Keyword1,2015/7/1,21
Keyword1,2015/7/2,21
Keyword1,2015/7/3,22
Keyword1,2015/7/4,22
Keyword1,2015/7/5,22
Keyword1,2015/7/6,22
Keyword1,2015/7/7,22
Keyword1,2015/7/8,22
Keyword1,2015/7/9,22
Keyword1,2015/7/10,22
Keyword1,2015/7/11,22
Keyword1,2015/7/12,22
Keyword1,2015/7/15,22
Keyword1,2015/7/16,21
Keyword1,2015/7/19,21
Keyword1,2015/7/20,21
Keyword1,2015/7/21,21
Keyword1,2015/7/22,21
Keyword1,2015/7/24,21
Keyword1,2015/7/25,20
Keyword1,2015/7/26,21
Keyword1,2015/7/27,21
Keyword1,2015/7/28,22
Keyword1,2015/7/29,20
Keyword1,2015/7/30,20
Keyword1,2015/7/31,20
Keyword1,2015/8/1,21
Keyword1,2015/8/3,22
Keyword1,2015/8/4,22
Keyword1,2015/8/5,18
Keyword1,2015/8/6,35
Keyword1,2015/8/7,5
Keyword1,2015/8/8,5
Keyword1,2015/8/9,3
Keyword1,2015/8/10,3
Keyword1,2015/8/11,3
Keyword1,2015/8/12,3
Keyword1,2015/8/13,3
Keyword1,2015/8/14,3
Keyword1,2015/8/15,3
Keyword1,2015/8/16,3
Keyword1,2015/8/16,6
Keyword2,2015/5/6,40
Keyword2,2015/5/7,39
Keyword2,2015/5/8,41
Keyword2,2015/5/9,41
Keyword2,2015/5/10,41
Keyword2,2015/5/11,48
Keyword2,2015/5/12,45
Keyword2,2015/5/13,44
Keyword2,2015/5/14,45
Keyword2,2015/5/15,49
Keyword2,2015/5/16,49
Keyword2,2015/5/17,91
Keyword2,2015/5/18,26
Keyword2,2015/5/19,27
Keyword2,2015/5/20,26
Keyword2,2015/5/21,55
Keyword2,2015/5/22,51
Keyword2,2015/5/23,51
Keyword2,2015/5/24,56
Keyword2,2015/5/25,26
Keyword2,2015/5/26,59
Keyword2,2015/5/27,59
Keyword2,2015/5/28,58
Keyword2,2015/5/29,58
Keyword2,2015/5/30,58
Keyword2,2015/5/31,53
Keyword2,2015/6/1,57
Keyword2,2015/6/2,56
Keyword2,2015/6/3,57
Keyword2,2015/6/4,59
Keyword2,2015/6/6,28
Keyword2,2015/6/7,54
Keyword2,2015/6/8,53
Keyword2,2015/6/9,51
Keyword2,2015/6/10,57
Keyword2,2015/6/11,59
Keyword2,2015/6/12,60
Keyword2,2015/6/13,55
Keyword2,2015/6/14,55
Keyword2,2015/6/16,55
Keyword2,2015/6/17,55
Keyword2,2015/6/18,59
Keyword2,2015/6/19,57
Keyword2,2015/6/20,59
Keyword2,2015/6/21,29
Keyword2,2015/6/22,27
Keyword2,2015/6/23,29
Keyword2,2015/6/24,29
Keyword2,2015/6/25,31
Keyword2,2015/6/26,28
Keyword2,2015/6/27,28
Keyword2,2015/6/28,27
Keyword2,2015/6/29,35
Keyword2,2015/6/30,35
Keyword2,2015/7/1,34
Keyword2,2015/7/2,29
Keyword2,2015/7/3,29
Keyword2,2015/7/4,25
Keyword2,2015/7/5,25
Keyword2,2015/7/6,27
Keyword2,2015/7/7,27
Keyword2,2015/7/8,27
Keyword2,2015/7/9,27
Keyword2,2015/7/10,30
Keyword2,2015/7/11,29
Keyword2,2015/7/12,29
Keyword2,2015/7/15,26
Keyword2,2015/7/16,25
Keyword2,2015/7/19,23
Keyword2,2015/7/20,27
Keyword2,2015/7/21,28
Keyword2,2015/7/22,28
Keyword2,2015/7/23,21
Keyword2,2015/7/24,21
Keyword2,2015/7/25,20
Keyword2,2015/7/26,20
Keyword2,2015/7/27,27
Keyword2,2015/7/28,26
Keyword2,2015/7/29,27
Keyword2,2015/7/30,20
Keyword2,2015/7/31,20
Keyword2,2015/8/1,21
Keyword2,2015/8/3,21
Keyword2,2015/8/4,21
Keyword2,2015/8/5,20
Keyword2,2015/8/6,19
Keyword2,2015/8/7,33
Keyword2,2015/8/8,30
Keyword2,2015/8/9,29
Keyword2,2015/8/10,29
Keyword2,2015/8/11,29
Keyword2,2015/8/12,26
Keyword2,2015/8/13,27
Keyword2,2015/8/14,37
Keyword2,2015/8/15,33
Keyword2,2015/8/16,36
Keyword2,2015/8/16,36
When I use some code the "normal" way, like I saw in my researches, everything works fine:
s.max = d3.max(s.values, function (d) {
return d.Google;
})
s.min = d3.min(s.values, function (d) {
return d.Google;
})
This works well and outputs this:
Keyword1
Best position: 3
Worst position: 35
Keyword2
Best position: 19
Worst position: 91
But this only outputs the Google-value.
What I want to achieve is that the related "Date" to the found max-value gets displayed as well.
So I tried it like this:
s.max = d3.max(s.values, function (d) {
var parseDate = d3.time.format("%d-%m-%Y");
return d.Google + " (" + parseDate(d.Date) + ")";
})
s.min = d3.min(s.values, function (d) {
var parseDate = d3.time.format("%d-%m-%Y");
return d.Google + " (" + parseDate(d.Date) + ")";
})
This looks nice at first. But the problem is, that sometimes the output isn't correct.
Keyword1
Best position: 18 (05-08-2015)
Worst position: 6 (31-05-2015)
Keyword2
Best position: 19 (06-08-2015)
Worst position: 91 (17-05-2015)
So as you can see, the output for Keyword2 is correct, but not for Keyword1 ,which should be :
Keyword1
Best position: 3 (09-08-2015)
Worst position: 35 (06-08-2015)
I also tried it without the "parseDate", but this results in the same wrong output.
Can anyone tell me what is getting wrong here, why the output isn't correct?
Looks like in the first example you are sorting numbers and in the second you are sorting strings. 3 < 21 and "3" > "21" are both true. It's not the most efficient approach in the world, but I'd say just sort your array by number and then grab the first and last elements. Something like:
var sorted = s.values.map(function(d) { return d; }).sort(function(a,b) {
return b.Google - a.Google;
});
// Note: I can never remember if Array.sort is ascending or descending by default. Use with caution.
var max = sorted[0].Google + " (" + formatDate(sorted[0].Date) + ")";
var min = sorted[sorted.length - 1].Google + " (" + formatDate(sorted[sorted.length - 1].Date) + ")";
Then do whatever you want to build your displayed string based on min/max.

Convert a string with function calls to an array

I need to convert this function call to a simple array[] but it's not working for some reason.
Here's the fiddle
var LongCombinedReady = $('#GeoImageLat').val(exifObject.GPSLatitude + "," + "'" + exifObject.GPSLatitudeRef + "'")
var LatCombinedReady = exifObject.GPSLongitude + "," + "'" + exifObject.GPSLongitudeRef + "'"
//an attemp to take the values and convert them to an array but it doesn't work.
var LongCombined = [LongCombinedReady];
var LatCombined = [LatCombinedReady];
I've commented it all out in the fiddle also here's an image with GeoCoords if you don't have one for testing.
Test Geotag image
Basically I read the images Geotag and then convert the tag from DMS to DD so it can be used for something like Google maps.
There are three problems:
you are missing an apply in line 49
you are applying array with one item being a string while function you are applying to expects four parameters
at line 43 LongCombinedReady is an jQuery object

toFixed Isn't Doing Anything

I'm teaching myself JavaScript and have run into a problem with toFixed(). I'm working through an amortization calculator; and, one of the steps returns a number with a huge number of decimal places. I'm trying to cut it down to 4 decimal places.
Be advised the sample code has a lot of explanatory HTML in it. It's only there so that I can work through the steps of the equation. Also, when I add one to the very long number, it adds the numeral one to end of the scientific notation.
var paymentamount;
var principal=250000;
var interestrate = 4.5;
var annualrate = interestrate/12;
var numberofpayments = 360;
document.write("This is the annuitized interest rate: "+ annualrate +"%");
document.write("<h3> Now we add 1 to the annualized interest rate</h3>");
var RplusOne = annualrate + 1;
document.write("<p> This is One Added to R: " + RplusOne + "%");
document.write("<h3>Next RplusOne is Raised to the power of N </h3>");
var RRaised = (Math.pow(RplusOne, numberofpayments)).toFixed(4);
document.write("<p>This gives us the following very long number, even thought it shouldn't: " + RRaised);
document.write("<h3>Now we add one to the very long number </h3>");
var RplusOne = RRaised + 1;
document.write("<p>Now we've added one: " + RplusOne);
From MDN's documentation:
If number is greater than 1e+21, this method simply calls Number.prototype.toString() and returns a string in exponential notation.
The problem is that you are using 4.5 as your interest rate instead of 0.045, so doing this:
Math.pow(4.5 / 12 + 1, 360)
gives you a huge number (6.151362770461608e+49 or 6.15 * 10^49 to be exact). Change your interest rate to 0.045 and you will get what you are expecting.
As for the var RplusOne = RRaised + 1 line, the problem here is that RRaised is a string because of toFixed. I would only call toFixed when you're displaying things, and not at any other time; the primary reason for this would be to avoid rounding errors in subsequent calculations, but has the added benefit that your variables remain numbers and not strings.

Categories

Resources