Get computed histogram bin thresholds - javascript

I have correctly applied the d3 (v 4.0) histogram function to bin an array of data. My code looks like this:
var bins = d3.histogram()
.domain([data_points_min, data_points_max])
.thresholds(8)
(data_points);
Is there a function to retrieve the bin thresholds? I guess I could loop through the array and identify the max in each bin, but that would be tedious. Am guessing there must be a function, including one that produces bin thresholds that are 'pleasing to the human eye' and not some ghastly decimal number.
Pseudo code would be something like this:
var bin_thresholds = bin.thresholds();

There is no method (as far as I know) for returning the lower and upper limits for each bin. There is one method for returning the number of bins...
d3.thresholdSturges(values);
... which is clearly not what you want, specially because you're setting the number of bins already.
However, you don't need to "loop through the array and identify the max in each bin". The histogram generator generates two properties:
x0 - the lower bound of the bin (inclusive).
x1 - the upper bound of the bin (exclusive, except for the last bin).
So, you can loop through the result to get those properties only. For instance:
var data = d3.range(1000).map(() => Math.random() * 20);
var bins = d3.histogram()
.thresholds(8)(data)
bins.forEach(function(d, i) {
console.log("Array number " + i + " --> Lower limit: " + d.x0 + " Upper limit:" + d.x1)
})
<script src="https://d3js.org/d3.v5.min.js"></script>
PS: you don't need to set the domain, since you're just passing the min and max value of the array, which is the default domain:
If domain is specified, sets the domain accessor to the specified function or array and returns this histogram generator. If domain is not specified, returns the current domain accessor, which defaults to extent. (emphasis mine)

Related

Change pixel value in OpenCV.js

According to OpenCV.js docs to modify a pixel value you can use 3 methods:
Direct data manipulation
at() family of methods
ptr() family of methods
Althougth the header of the section in the docs say "Accessing and Modifying pixel values" it provides examples for retrieving a value but not for modifying them. The problem is that while in C++ this code using the at or ptr methods works:
mat.at<type>(row, col) = value;
The equivalent in javascript is not valid and gives an Invalid left hand side in assignment expression:
mat.floatAt(row, col)) = value;
I could make it work using the direct data manipulation method with:
mat.data[row * this.cols * this.channels() + col * this.channels()] = value;
But this method does not operate in pixel values but in the underlaying array data structure where a pixel may span more than one array index, so is not valid for my use case.
How can a pixel value at [row, col] position in a CvMat be modified using OpenCV.js?
I have been successful in setting single pixels of images (or matrices) with ucharPtr.
Instead of setting it like this:
img.ucharPtr(i, j) = 255
I set it like this:
img.ucharPtr(i, j)[0] = 255
Even if the image is black and white and only has one channel
If you want to set all 4 pixel values, you can do this:
src.ucharPtr(i, j)[0] = 255
src.ucharPtr(i, j)[1] = 255
src.ucharPtr(i, j)[2] = 255
src.ucharPtr(i, j)[3] = 0

What is this Javascript function parameter doing?

Consider the following code (shortened for clarity):
Vertices.chamfer = function(vertices, radius, quality, qualityMin, qualityMax) {
radius = radius || [8];
if (!radius.length)
radius = [radius];
};
I'm reading the first part as (pseudocode):
if (radius array passed to function) then
radius = radius
else
radius = [8] // new array, single element of value 8
end if
but I don't get the second expression (the if(!radius.length) radius = [radius] part).
Could someone explain it to me?
Vertices.chamfer = function(vertices, radius, quality, qualityMin, qualityMax) {
// Set the radius to the value passed in.
// If the value passed in is undefined, set the radius to an
// array containing 8 (the "default")
radius = radius || [8];
// If radius isn't an array (i.e. length is 0 which evaluates to false),
// make it an array.
if (!radius.length)
radius = [radius];
};
The concept used here is known as duck typing - i.e. checking the type of a variable by looking for the presence (or absence) of some characteristic properties/methods. Author of this code assumed that if something has a length property it is an Array, and if not it can be converted to an Array by wrapping it in [].
The second part, converting x to a single-item Array containing x using x = [x] is totally OK.
The problem is there are other types in JavaScript that have a length so this test is not really reliable.
For example: "7".length returns 1, so if you passed the variable as a string instead of a number (easy enough to make this mistake for example by reading values from <input> fields) something would break down the line expecting an Array but getting a String.
Another type that has a length is a Function: (function(a,b){}).length == 2.
So yeah, this is not really good test but the basic idea makes sense. Should have used either Array.isArray or some other property/method that is unique to Arrays.
EDIT: I'd also point out the radius = radius || [8] construct is only OK if 0 is not allowed as the radius argument.
I'm reading the first part as (pseudocode):
if (radius array passed to function) then
radius = radius || [8] checks to see if radius is falsy, which might be not passed in at all (undefined), or passed in as undefined, or passed in as null, 0, "", NaN, or of course false.
But yes, it's probably intended to use [8] if no radius was specified.
but I don't get the second expression (the if(!radius.length) radius = [radius] part).
If radius was given but is either A) An array with no entries (radius.length is 0 and therefore falsy), or B) Not an array (radius.length is undefined and therefore falsy), we create an array and make it the first entry in that array.
That's not at all robust validation, lots of things have length (strings, for instance), but that's probably what it's meant to do.
The robust way to check if something is an array is to use Array.isArray, which was added in ES5 and which can be reliably shimmed/polyfilled for obsolete engines (like the one in IE8).
if imported radius is not an array and it has value, then it returns an array with the radius value inside.
if imported radius is empty then it returns an array with the number 8 inside: [8]
However, inside the pseudocode, it is not gonna get in if statement, if the imported radius is not an array.

How do I code the equivalent in JavaScript of "Application.Match" in VBA? - - for use in a numerical interpolation function

I want to write an INTERPOLATION function in JavaScript in order to be able to use Google Sheets instead of Excel for a number of purposes. In Excel, I have this user defined function written in VBA:
Function interpolate_1D(xreq As Single, x As Range, y As Range) As Single
' If we have variable y that is a function of x and have two ranges, x and y that give the values
'of y for particular values of x, we may need to find the value of y for a value of x not 'given in the table.
'For example, we may have power curve data for a wind turbine that gives the power output of a wind turbine
'for integer values of the wind speed. To find the output power at any other speed we could 'use this function, using as arguments:
'xreq: wind speed for which we wish to know the output power
'x: range containing the known wind speeds in ascending order
'y: range containing the known wind turbine powers
Dim pointer As Integer
Dim x0 As Single, y0 As Single, x1 As Single, y1 As Single
pointer = Application.Match(xreq, x, 1)
x0 = x(pointer)
x1 = x(pointer + 1)
y0 = y(pointer)
y1 = y(pointer + 1)
interpolate_1D = y0 + (xreq - x0) * (y1 - y0) / (x1 - x0)
End Function
I probably copied this from somewhere, such as Billo's book on Excel for Scientists and Engineers. It works very well, as does a 2D version of it that I wrote.
I am fairly new to JavaScript, and I can't at the moment see how to get it to do the equivalent of the Application.Match (xreq,x,1) line, where it looks through the range of known x values and finds the position of the largest value that is smaller than the search value xreq. Once i have that position, I can do everything else.
Any ideas?
You may not need to. You may be able to use the array .IndexOf method:
http://www.w3schools.com/jsref/jsref_indexof_array.asp
var fruits = ["Banana", "Orange", "Apple", "Mango"];
var a = fruits.indexOf("Apple");
The result of a will be: 2
Whether it is possible to recreate the optimized Match worksheet function in another language would require some more detailed knowledge of the underlying code, which I can't offer you at this time.
Otherwise, without seeing more of what you're doing, I'd say trying to reconstruct the Match function -- although it will be slower -- is as simple as brute force iteration over the array (this will be faster if you test on an array, rather than the range object).
I have modified Tim Williams' test functions to compare several methods. In these tests, the Contains function is tested against the range .Value after transferring that to an array. I test Match function both against the array, and against the range object, and also test WorksheetFunction.Match against the range.
Sub Tester()
Application.ScreenUpdating = False
Dim i As Long, B, T
Dim Arr As Variant
Dim rng As Range
Set rng = Range("A1:A10000")
rng.Formula = "=""value_""&" & "RandBetween(1,1000)"
Range("A100000").Value = "Value_50"
T = Timer
Arr = Application.Transpose(rng.Value)
For i = 1 To 10000
B = Contains(Arr, "Value_50")
Next i
Debug.Print "Contains (array)" & vbTab & Timer - T
T = Timer
Arr = Application.Transpose(rng.Value)
For i = 1 To 10000
B = Application.Match("Value_50", Arr, False)
Next i
Debug.Print "Match (array)" & vbTab & Timer - T
T = Timer
For i = 1 To 10000
B = Application.Match("Value_50", rng, False)
Next i
Debug.Print "Match (range)" & vbTab & Timer - T
T = Timer
On Error Resume Next
For i = 1 To 10000
B = Application.WorksheetFunction.Match("Value_50", rng, False)
Next i
On Error GoTo 0
Debug.Print "WorksheetFunction.Match (range)" & vbTab & Timer - T
Application.ScreenUpdating = True
End Sub
Observed that the Contains custom function is faster than Match when performed on an array in memory, however the Application.Match and Application.WorksheetFunction.Match functions are both remarkably faster than either, when performed on a Range object on the worksheet:
Contains (array) 18.90625
Match (array) 43.25
Match (range) 0.2304688
WorksheetFunction.Match (range) 0.1914063
Thanks to the comments/discussion with #CharlesWilliams for assistance with this timing test & clarifying some things about it.
You could probably use the function given here and add your own logic in the loop to find the value you are looking for.
#All,
In the end, I got this to work:
function interpolate (xreq,knowndata){
var data = knowndata;
for (var i = 0; i < data.length-1; i++) {
if (xreq >=data[i][0] & xreq <data[i+1][0]) {break}
}
return data[i][1] + (data[i+1][1] - data[i][1]) / ( data[i+1][0] - data[i][0]) * (xreq - data[i][0]);
}
It needs error handling, but does the job that I wanted. "knowndata" is a 2 column range that contains known x and y data, with x in ascending order. "xreq" is the new x value for which we want to estimate the best value of y. This doesn't use an equivalent of MATCH, but at least it gives me a linear interpolation function that does the job, so now I can port several Excel spreadsheets into Google Sheets.
Thanks all for your input - it has been interesting to read.

Linearly scaling a number in a certain range to a new range

I've made a scaling function that takes numbers in an interval [oldMin,oldMax] and scales them linearly to the range [newMin,newMax] . It does not seem to work when using negative values.
function linearScaling(oldMin, oldMax, newMin, newMax, oldValue){
var newValue;
if(oldMin !== oldMax && newMin !== newMax){
newValue = parseFloat((((oldValue - oldMin) * (newMax - newMin)) / (oldMax - oldMin)) + newMin);
newValue = newValue.toFixed(2);
}
else{
newValue = error;
}
return newValue;
}
This function seems to work when scaling a value from 0 -> 32761 to the range range 0 -> 10. However it does not seem to give the correct output when given a new negative range i.e. -10 -> 10
I have done my best to find an answer on this site. However the person who asked the question didn't mention what he ended up doing to fix it. That question says it could have something to do with mixed up data types, but i converted everything to a float did I miss anything?
Now that you showed how you call your function, I can reproduce your problem - namely that quoted numbers that should map to the negative domain don't.
It seems to be due to the fact that Javascript is very loose about the difference between a number and a string - and if it's not sure what to do about two numbers (because one of them appears to be a string), it assumes you want concatenation rather than addition. In other words - by passing the newMin value as '-10' rather than -10 you confused JS.
As a simple example,
document.write('1' + '-2');
produces
1-2
However,
document.write(1*'1' + 1*'-2');
results in
-1
The expression you had included a "possible concatenation" where it added oldMin:
newValue = (((oldValue - oldMin) * (newMax - newMin)) / (oldMax - oldMin)) + newMin;
With newMin set to '-10', you might get newValue to look like 6-10 instead of -4, to give an example. When you then did a parseFloat, Javascript would quietly work its way through the string up to the minus sign, and return 6 instead of evaluating the expression and coming up with -4.
To clear up the confusion, multiply each parameter by 1 to make it "a genuine number":
oldMin = 1*oldMin;
oldMax = 1*oldMax;
newMin = 1*newMin;
newMax = 1*newMax;
oldValue = 1*oldValue;
When you add these lines at the start of your function declaration, everything works smoothly - regardless of how you call the function. Or just call it with the newMin value not in quotes - it is the one causing the trouble in this particular instance.
document.writeln('the new code called with parameter = 100:\n');
document.writeln(linearScaling('0', '32761', '-10', '10', 100)+'<br>');
document.writeln('the old code called with parameter = 100:\n');
document.writeln(linearScalingOld('0.0', '32761.0', '-10.0', '10.0', '100.0')+'<br>');
document.writeln('the old code called with unquoted parameters:\n');
document.writeln(linearScalingOld(0.0, 32761.0, -10.0, 10.0, 100.0)+'<br>');
results in the following:
the new code called with parameter = 100: -9.94
the old code called with parameter = 100: 0.06
the old code called with unquoted parameters: -9.94
I hope this illustrates the cause of the problem, and the solution.

Neural Network Continuous tanh-Sigmoid Activation Function and Random Weights

I really need help implementing a continuous tanh-sigmoid activation function in a very basic neural network. If you could give a basic example that would be great, but if you could change it in my source code I would be extremely grateful! Also, what range should the random weights be initiated with (i.e. what range)?
The weight range depends on what input data range you have. In some implementations the weights can also be negative.
For possible Sigmoid functions, check here (tanh is not the only possibility):
http://en.wikipedia.org/wiki/Sigmoid_function
Tip: You can typically compute the NN with matrix multiplications.
http://www.dtreg.com/mlfn.htm
http://en.wikipedia.org/wiki/Neural_network
P.S.: probably not a good idea to do this in JavaScript.
you can either implement it via exp(x) , See: http://www.javascripter.net/faq/mathfunc.htm
sinh(x) exp(x) - exp(-x) exp(2x) - 1
tanh(x) = ------- = ------------------ = -------------
cosh(x) exp(x) + exp(-x) exp(2x) + 1
that gives you:
function tanh(x) {
e = Math.exp(2*x);
return (e - 1) / (e + 1) ;
};
another solution is to store a table with the tanh function values in an array, and define a JavaScript function which interpolates the tanh values for x based on the tanh values stored in the array
typically people don't want [-inf...+inf] as the range of the input values, and don't want [-1...+1] as the range of output values -- therefore you might need a different sigmoid function!
you need to take the expected range of input values, and the expected range of output values, and use those to shift the actual sigmoid function, the weight-ranges and the value of the threshhold.
a threshhold of 0.7 or larger is typically used. You need to experiment with that.
this.output = 2 / (1 + Math.exp(-2 * input)) - 1;

Categories

Resources