Interpolate function in Google Scripts - google-apps-script

I am using google sheets to log my water usage and want to find out how much I have used in a given period by using linear interpolation. I would really like to use a function similar to forecast, but instead of using the entire range to interpolate, just use the nearest points above and below.
I am keen to try and code it myself (have done lots of VBA) but don't know really where to start with google scripts. Does anyone have a starting point for me?
The process I would take is:
Interpolate(x, data_y, data_x)
// Check value is within range of known values (could expand function to use closet two values and extrapolate...)
(is X within XMin and XMax)
// Find closet X value below (X1), corresponding Y1
// Find closet X value above (X2), corresponding Y2
Return Y = Y1+(X-X1)*((Y2-Y1)/(X2-X1))

function interpolation(x_range, y_range, x_value) {
var xValue, yValue, xDiff, yDiff, xInt, index, check = 0;
if(x_value > Math.max.apply(Math, x_range) || x_value < Math.min.apply(Math, x_range)) {
throw "value can't be interpolated !!";
return;
}
for(var i = 0, iLen = x_range.length; i < iLen-1; i++) {
if((x_range[i][0] <= x_value && x_range[i+1][0]> x_value) || (x_range[i][0] >= x_value && x_range[i+1][0] < x_value)){
yValue = y_range[i][0];
xDiff = x_range[i+1][0] - x_range[i][0];
yDiff = y_range[i+1][0] - yValue;
xInt = x_value - x_range[i][0];
return (xInt * (yDiff / xDiff)) + yValue;
}
}
return y_range[x_range.length-1][0];
}

Related

Check if point exists within a polygon in react-native-maps?

I have an API that returns an array of latitudes and longitudes that define the boundaries of an area on a map(polygon).
In my react-native app, I have react-native-maps installed. How do I check if the user's location is in the polygon returned by the api?
I know this can be achieved with google maps web with the containsLocation() function. Does a function like that exist for react-native-maps?
For anyone still looking for an easier alternative (or for Circle support just like I needed it), look into using geolib: https://github.com/manuelbieh/Geolib.
Installation is simple and straightforward:
$yarn add geolib
Afterward in your React Native project, import it using:
import geolib from 'geolib'
And then just use the API as explained in the README.md.
react-native-maps doesn't expose that function, but there are two packages that I'm aware of that can help you:
react-native-geo-fencing that does the same as the google maps utility you've mentioned.
react-native-geo-fence handles location checks for you and exposes events you can hook into.
geolibe
is the best solution.
react-native-geo-fencing is deprecated and it cause more errors to your project and also
react-native-geo-fence is not what you want
My code to check if lat, lon is inside object of many polys. It returns true if coordinate is inside one of the polygons.
isInsidePoly = (lat, lon, multiPolycoords) => {
// ray-casting algorithm based on
// https://wrf.ecse.rpi.edu/Research/Short_Notes/pnpoly.html/pnpoly.html
var x = lat,
y = lon;
var inside = false;
multiPolycoords.map(poly => {
vs = poly;
for (var i = 0, j = vs.length - 1; i < vs.length; j = i++) {
var xi = vs[i].latitude,
yi = vs[i].longitude;
var xj = vs[j].latitude,
yj = vs[j].longitude;
var intersect =
yi > y != yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi;
if (intersect) inside = !inside;
}
});
return inside;
};

AS3: Minimum value from that is not 0?

I have a problem:
Is there any way I can find the minimum value of an Array that is not 0? Let's say I have this Array:
{0,2,0,0,1} and I want it to find 1.
It should just be a slight variation on finding the minimum including zero. This would be achieved by setting the minimum to the first value and then going through all the others, replacing the minimum if a value in the array is lower.
The modification needed to that for your scenario is to just ignore those having a value of zero. Something like this should do:
var numbers:Array = [0,2,0,0,1];
var started:Boolean = false;
var minval:Number = 0;
for each (var num:Number in numbers) {
if ((!started) && (num != 0)) {
started = true;
minval = num;
}
if ((started) && (num != 0) && (num < minval)) {
minval = num;
}
}
The first if statement will be the only one executed until you find the first non-zero value, at which point you'll set started and store that number as the minimum.
From then on (including on that iteration), you'll just check the non-zero numbers to see if they're less and store them if so.
At the end, either started will be false in which case there were no non-zero numbers, or started will be true and minval will hold the smallest number found.

Bogus math with app scripts

Anyone had an issue with bogus math results when using Google Apps Script? The following is the code, where a/b/c are send from another function. A/b/c are verified with the logger. ? StartPt is fine, but endpt is generating a false value.
function calcTime(a,b,c) {
var x;
var startHr = 8;
var startMin = 0;
var startSec=0;
var startPt;
var endPt;
startPt = (startHr * 60) + startMin + (startSec/60);
endPt = (a * 60) + b + (c/60);
Logger.log(endPt);
x = endPt -startPt;
return x;
}
flag
I found that the math error is a multiplication factor of 100 (when endPt is calculated, it multiplies the result by 100). What could cause this?
Real number arithmetic is prone to rounding errors in javascript and apps-script. See Is floating point math broken?. If you're watching your function in the debugger, you'll see rounding errors esp. with (c/60). But that's not likely causing a factor-of-100 error.
Most likely, your parameters aren't what you thing they are. If b arrives as a string, for instance, the calculation of (a * 60) + b + (c/60) will effectively ignore b. The other two parameters, however, will get changed to numbers to to complete the multiplication and division operations. (You can avoid that by using b * 1.)
Anyway, to confirm what you're getting as parameters, try replacing the first few lines of your function with this:
function calcTime(a,b,c) {
var params = {
a:{type:typeof a, value:a},
b:{type:typeof b, value:b},
c:{type:typeof c, value:c}}
Logger.log(params);
var x;
...
Verify that you're getting what you need. If any of the parameters are arriving as date objects, for instance, your math will be wildly incorrect. You may just need to enforce types for your data source.

OCR: weighted Levenshtein distance

I'm trying to create an optical character recognition system with the dictionary.
In fact I don't have an implemented dictionary yet=)
I've heard that there are simple metrics based on Levenstein distance which take in account different distance between different symbols. E.g. 'N' and 'H' are very close to each other and d("THEATRE", "TNEATRE") should be less than d("THEATRE", "TOEATRE") which is impossible using basic Levenstein distance.
Could you help me locating such metric, please.
This might be what you are looking for: http://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance (and kindly some working code is included in the link)
Update:
http://nlp.stanford.edu/IR-book/html/htmledition/edit-distance-1.html
Here is an example (C#) where weight of "replace character" operation depends on distance between character codes:
static double WeightedLevenshtein(string b1, string b2) {
b1 = b1.ToUpper();
b2 = b2.ToUpper();
double[,] matrix = new double[b1.Length + 1, b2.Length + 1];
for (int i = 1; i <= b1.Length; i++) {
matrix[i, 0] = i;
}
for (int i = 1; i <= b2.Length; i++) {
matrix[0, i] = i;
}
for (int i = 1; i <= b1.Length; i++) {
for (int j = 1; j <= b2.Length; j++) {
double distance_replace = matrix[(i - 1), (j - 1)];
if (b1[i - 1] != b2[j - 1]) {
// Cost of replace
distance_replace += Math.Abs((float)(b1[i - 1]) - b2[j - 1]) / ('Z'-'A');
}
// Cost of remove = 1
double distance_remove = matrix[(i - 1), j] + 1;
// Cost of add = 1
double distance_add = matrix[i, (j - 1)] + 1;
matrix[i, j] = Math.Min(distance_replace,
Math.Min(distance_add, distance_remove));
}
}
return matrix[b1.Length, b2.Length] ;
}
You see how it works here: http://ideone.com/RblFK
A few years too late but the following python package (with which I am NOT affiliated) allows for arbitrary weighting of all the Levenshtein edit operations and ASCII character mappings etc.
https://github.com/infoscout/weighted-levenshtein
pip install weighted-levenshtein
Also this one (also not affiliated):
https://github.com/luozhouyang/python-string-similarity
I've recently created a python package that does exactly that https://github.com/zas97/ocr_weighted_levenshtein.
In my Weigthed-Levenshtein implementation the distance between "THEATRE" and "TNEATRE" is 1.3 while the distance between "THEATRE" and "TOEATRE" is 1.42.
Other exemples are the d("O", "0") is 0.06 and d("e","c") is 0.57.
This distances have been calculated by running multiple ocrs in a synthetic dataset and doing statistics on the most common ocr errors. I hope it helps someone =)

1D multiple peak detection?

I am currently trying to implement basic speech recognition in AS3. I need this to be completely client side, as such I can't access powerful server-side speech recognition tools. The idea I had was to detect syllables in a word, and use that to determine the word spoken. I am aware that this will grealty limit the capacities for recognition, but I only need to recognize a few key words and I can make sure they all have a different number of syllables.
I am currently able to generate a 1D array of voice level for a spoken word, and I can clearly see, if I somehow draw it, that there are distinct peaks for the syllables in most of the cases. However, I am completely stuck as to how I would find out those peaks. I only really need the count, but I suppose that comes with finding them. At first I thought of grabbing a few maximum values and comparing them with the average of values but I had forgot about that peak that is bigger than the others and as such, all my "peaks" were located on one actual peak.
I stumbled onto some Matlab code that looks almost too short to be true, but I can't very that as I am unable to convert it to any language I know. I tried AS3 and C#. So I am wondering if you guys could start me on the right path or had any pseudo-code for peak detection?
The matlab code is pretty straightforward. I'll try to translate it to something more pseudocodeish.
It should be easy to translate to ActionScript/C#, you should try this and post follow-up questions with your code if you get stuck, this way you'll have the best learning effect.
Param: delta (defines kind of a tolerance and depends on your data, try out different values)
min = Inf (or some very high value)
max = -Inf (or some very low value)
lookformax = 1
for every datapoint d [0..maxdata] in array arr do
this = arr[d]
if this > max
max = this
maxpos = d
endif
if this < min
min = this
minpos = d
endif
if lookformax == 1
if this < max-delta
there's a maximum at position maxpos
min = this
minpos = d
lookformax = 0
endif
else
if this > min+delta
there's a minimum at position minpos
max = this
maxpos = d
lookformax = 1
endif
endif
Finding peaks and valleys of a curve is all about looking at the slope of the line. At such a location the slope is 0. As i am guessing a voice curve is very irregular, it must first be smoothed, until only significant peaks exist.
So as i see it the curve should be taken as a set of points. Groups of points should be averaged to produce a simple smooth curve. Then the difference of each point should be compared, and points not very different from each other found and those areas identified as a peak, valleys or plateau.
If anyone wants the final code in AS3, here it is:
function detectPeaks(values:Array, tolerance:int):void
{
var min:int = int.MIN_VALUE;
var max:int = int.MAX_VALUE;
var lookformax:int = 1;
var maxpos:int = 0;
var minpos:int = 0;
for(var i:int = 0; i < values.length; i++)
{
var v:int = values[i];
if (v > max)
{
max = v;
maxpos = i;
}
if (v < min)
{
min = v;
minpos = i;
}
if (lookformax == 1)
{
if (v < max - tolerance)
{
canvas.graphics.beginFill(0x00FF00);
canvas.graphics.drawCircle(maxpos % stage.stageWidth, (1 - (values[maxpos] / 100)) * stage.stageHeight, 5);
canvas.graphics.endFill();
min = v;
minpos = i;
lookformax = 0;
}
}
else
{
if (v > min + tolerance)
{
canvas.graphics.beginFill(0xFF0000);
canvas.graphics.drawCircle(minpos % stage.stageWidth, (1 - (values[minpos] / 100)) * stage.stageHeight, 5);
canvas.graphics.endFill();
max = v;
maxpos = i;
lookformax = 1;
}
}
}
}