linear scale value between two values - javascript

I have a three values.
let a = 10;
let b = 200;
let c = 140;
I want to make the line scale chart by which straight line starting point is 10 and end point is 140.
Now I have to make the calculation by which 140 value will be lie in between the line.
Its like 0, 50 & 100. ) is starting point, 100 is end point and 50 is the central point.
So I pass the 50 percent so that it will be on the center.
I have made the UI. I just need to pass the percent value by which UI will be made.
Any suggestion for this will highly appreciable

If I understand you right the formula you need is
(c-a)/(b-a)*100
or in javascript
((c-a)/(b-a)*100).toFixed(1)+'%`

Related

Efficient algorithm for finding which hexagon a point belongs to

I'm trying to find a more efficient way of determining which hexagon a point belongs to from the following:
an array of points - for the sake of argument, 10000 points.
an array of center points of hexagons, approximately 1000 hexagons.
every point will belong to exactly one hexagon, some (most) hexagons will be empty.
The hexagons form a perfect grid, with the point of one hexagon starting in the top left corner (it will overlap the edge of the total area).
My current solution works, but is rather slow n * (m log m) I think, where n=length(points) and m=length(hexagons).
I suspect I can do much better than this, one solution that comes to mind is to sort (just once) both the points and the hexagons by their distance to some arbitrary point (perhaps the middle, perhaps a corner) then iterate over the points and over a subset of the hexagons, starting from the first hexagon whose distance to this point is >= to the last hexagon matched. Similarly, we could stop looking at hexagons once the distance difference between the (point -> ref point) and (hexagon center -> ref point) is larger than the "radius" of the hexagon. In theory, since we know that every point will belong to a hexagon, I don't even have to consider this possibility.
My question is: Is there a Much better way of doing it than this? In terms of complexity, I think it's worst case becomes marginally better n * m but the average case should be very good, probably in the region of n * 20 (e.g., we only need to look at 20 hexagons per point). Below is my current inefficient solution for reference.
points.forEach((p) => {
p.hex = _.sortBy(hexes, (hex) => {
const xDist = Math.abs(hex.middle.x - p.x);
const yDist = Math.abs(hex.middle.y - p.y);
return Math.sqrt((xDist * xDist) + (yDist * yDist));
})[0];
});
For an arbitrary point, you can find the nearest hexagon center in two steps (assuming the same arrangement as that of Futurologist):
divide the abscissa by the horizontal spacing between the centers, and round to the nearest integer.
divide the ordinate by the half of the vertical spacing, and round to the nearest even or odd integer, depending on the parity found above.
consider this center and the six ones around it, and keep the closest to the target point.
This gives you the indexes of the tile, in constant time.
Just a suggestion: assume you have the centers of each regular hexagon from your regular hexagonal grid (if I have understood correctly, that's part of the information you have).
-----
/ \
- ----- -----------> x - axis
\ / \
----- -
/ \ /
- -----
\ / \
----- -
| \ /
| -----
|
|
V
y - axis
You can think that your coordinate system starts from the center of the hexagon in the upper left corner and the y coordinate axis runs vertically down, while the x axis runs from left to right horizontally. The centers of the hexagons from your regular hexagonal grid form an image of the regular square grid, where the integer vertices of the square grid are transformed into the centers of the polygons by simply multiplying the coordinates of points in the square grid by the 2 x 2 square matrix (a sheer metrix)
A = a*[ sqrt(3)/2 0;
1/2 1 ]
where a is a parameter of the hexagonal grid, the distance between the centers of two edge-adjacent hexagons. This provides a way to assign integer indices [m n] to the grid formed by the hexagonal centers. After that, if you are given a point with coordinates [x y] in the hexagonal grid, you can apply the inverse matrix of A
[u; v] = A^(-1)*[x; y]
where
A^(-1) = (2/(a*sqrt(3)))*[ 1 0 ;
-1/2 sqrt(3)/2 ]
([x; y] and [u; v] are column vectors) and then take m = floor(u) and n = floor(v) to determine the integer coordinates (also the indices) [m = floor(u), n = floor(v)] of the upper left corner of the square cell from the square grid (observe that we have chosen the coordinates for both grids to start from the upper left corner). Thus, your point [u, v] is in the square with vertices [m,n] [m+1, n] [m, n+1] [m+1, n+1]
which means that the original point [x y] is in one of the four hexagons whose centers have indices [m,n] [m+1, n] [m, n+1] [m+1, n+1]. So you can use that to check in which of the four hexagons the point [x y] is.
I hope this helps.
Update: Leaving the below comment for posterity
I am now using the code provided here: https://www.redblobgames.com/grids/hexagons/
A really important note, is that your hexagon grid MUST start with the first hexagons mid point at (0, 0) - if it doesn't you get extremely odd results from this, which at first glance appeared as rounding errors (even after accounting for the expected offset). For me, it didn't matter where the first hexagon was positioned, so I just set it to be (0, 0) and it worked great.
Old solution
I'm still hoping for an optimal solution, but I ended up rolling my own which needs only check 6 hexagons per point, with a little overhead (approximately sqrt(m)) needed in addition.
With approximately 3000 points, and 768 hexagons (of which 310 were populated), it correctly assigned the point to the hexagon 100% of the time (as checked against a brute force approach) and took 29 milliseconds, compared to ~840 with brute force.
To start with, I store the hexagons in a map where the key is "${column},${row}". The columns technically overlap, so for the 0th row, the 0th column starts at -0.5 * hexWidth, and for row 1, the 0th column starts at 0px.
Next, I start from the position of the top left hexagon, item "0,0", which should also be at position 0, and increment y by either the height of the hexagon, or the edge length of the hexagon accordingly. When the y is > the points y, I've found the probable row, I then check the row above and below.
For the column within the row, I take the both the Math.floor and Math.ceil of x / hexWidth.
Doing this gives 6 hexagons to check, from this point the solution is identical to the solution in the question.
In theory, this could be used to just look up the correct hexagon, using the x/y position. However in practice, this didn't work for me about 5% of the time with off by 1 errors, likely a rounding problem.
Some other things I looked at:
As suggested by #jason-aller, https://www.redblobgames.com/grids/hexagons/#rounding. Unfortunately, this seems to assume some form of transformation on the hex grid (rotations) and is not easy to follow - continually referencing functions which have yet to be defined.
QuadTree (various implementations) unfortunately, this returned approximately 100 "potential matches" for each point - so the performance improvement was not good. I'm aware that insertion order changes how useful QuadTree is, I tried natural order, sorted by distance from top, left and shuffled, they all performed equally badly. It's likely that an optimal solution with QuadTree would involve populating the tree with the item closest to the mid point, then the items 1/2 from the mid point to each corner, recursively. Too much like hard work for me!

Javascript D3 Histogram: thresholds producing wrong number of bins

I'm in the process of creating a histogram JS script using D3, and it all seems to be working correctly... except for the number of bins.
Following is the relevant part of my code:
//Define the scales for the x and y attributes
var x = d3.scaleBand()
.range([0, width])
.padding(configProperties.barPadding);
var y = d3.scaleLinear()
.range([height,0]);
//Create the bins
var bins = d3.histogram()
.domain(d3.extent(data))
.thresholds(configProperties.binsCount)
(data);
console.log("number of bins: " + bins.length); //9
console.log("intended number of bins: " + configProperties.binsCount); //10
If I set configProperties.binsCount to 9, bins.length is still 9.
If I set configProperties.binsCount to 14, bins.length is still 9.
If I set binsCount to 15 or higher, however... bins.length outputs 23.
My understanding of how histogram.thresholds works based on the documentation is that if I give it a value, it will divide the data into that many + 1 equal segments (i.e. that many bins). However, it doesn't seem to be doing that at all. All of the example code that I could find seemed to indicate that I am using it correctly, but I can't get the number of bins that I need.
I've also tried using d3.ticks as a thresholds argument, but I encounter the same issue.
Is there something I'm missing? Does it have to do with my domain? Thanks in advance.
You are passing a count (that is, a simple number) to the thresholds function, not an array.
What you're seeing is the expected behaviour when you pass a number. According to the same docs:
If a count is specified instead of an array of thresholds, then the domain will be uniformly divided into approximately count bins;
Let's see it in this demo:
var data = d3.range(100);
const histogram = d3.histogram()
.value(d => d)
.thresholds(5);
var bins = histogram(data);
console.log("The number of bins is " + bins.length)
<script src="https://d3js.org/d3.v4.js"></script>
As you can see, count is 5 and the number of bins is also 5.
If you pass an array, however, the behaviour is what you expect: the number of bins will be array.length + 1:
Thresholds are defined as an array of values [x0, x1, …]. Any value less than x0 will be placed in the first bin; any value greater than or equal to x0 but less than x1 will be placed in the second bin; and so on. Thus, the generated histogram will have thresholds.length + 1 bins.
Here is the demo:
var data = d3.range(100);
const histogram = d3.histogram()
.value(d => d)
.thresholds([10, 30, 50, 70, 90]);
var bins = histogram(data);
console.log("The number of bins is " + bins.length)
<script src="https://d3js.org/d3.v4.js"></script>
As you can see, the array has 5 values and the number of bins is 6.
Finally, have in mind that the actual number of bins depends on the data you pass to the histogram generator. That explains the other results you're describing in your question.
I realize this is a little old, and that Gerardo explained how to do what you were asking, but he didn't actually answer the why of the question. So here's that, in case anyone else comes across this question and is curious. If you pass a number to the thresholds function, D3 finds a number of bins that is near to that number, such that the thresholds are 'nice' numbers. And it's the choosing of those 'nice' numbers that results in the number of bins being different than what you specify.
So if your data goes from 0 to 24.37, and you request 8 bins, the thresholds will not be multiples of 3.481428571428... ( = 24.37 / (8-1)). Instead D3 will pick a 'nice' maximum of 25, and the threshold will be multiples of 2.5 (to make 10 bins) or multiples of 5 (to make 5 bins). These numbers are much nicer to display on a graph, and are what a human would probably choose if they were making the histogram by hand.

How to divide an ellipse to equal segments?

This calculates vertex coordinates on ellipse:
function calculateEllipse(a, b, angle)
{
var alpha = angle * (Math.PI / 180) ;
var sinalpha = Math.sin(alpha);
var cosalpha = Math.cos(alpha);
var X = a * cosalpha - b * sinalpha;
var Y = a * cosalpha + b * sinalpha;
}
But how can I calculate the "angle" to get equal or roughly equal circumference segments?
So from what Jozi's said in the OP's comments, what's needed isn't how to subdivide an ellipse into equal segments (which would require a whole bunch of horrible integrals), it's to construct an ellipse from line segments of roughly equal length.
There are a whole pile of ways to do that, but I think the best suited for the OP's purposes would be the concentric circle method, listed on the page as 'the draftman's method'. If you don't mind installing the Mathematica player, there's a neat lil' app here which illustrates it interactively.
The problem with those methods is that the segment lengths are only roughly equal at low eccentricities. If you're dealing in extreme eccentricities, things get a lot more complicated. The simplest solution I can think of is to linearly approximate the length of a line segment within each quadrant, and then solve for the positions of the endpoints in that quadrant exactly.
In detail: this is an ellipse quadrant with parameters a = 5, b = 1:
And this is a plot of the length of the arc subtended by an infinitesimal change in the angle, at each angle:
The x axis is the angle, in radians, and the y axis is the length of the arc that would be subtended by a change in angle of 1 radian. The formula, which can be derived using the equations in the Wikipedia article I just linked, is y = Sqrt(a^2 Sin^2(x) + b^2 Cos^2(x)). The important thing to note though is that the integral of this function - the area under this curve - is the length of the arc in the whole quadrant.
Now, we can approximate it by a straight line:
which has gradient m = (a-b) / (Pi/2) and y intercept c = b. Using simple geometry, we can deduce that the area under the red curve is A = (a+b)*Pi/4.
Using this knowledge, and the knowledge that the area under the curve is the total length of the curve, the problem of constructing an approximation to the ellipse reduces to finding say a midpoint-rule quadrature (other quadratures would work too, but this is the simplest) of the red line such that each rectangle has equal area.
Converting that sentence to an equation, and representing the position of a rectangle in a quadrature by it's left hand boundary x and its width w, we get that:
(v*m)*w^2 + (m*x+c)*w - A/k == 0
where k is the number of pieces we want to use to approximate the quadrant, and v is a weighting function I'll come to shortly. This can be used to construct the quadrature by first setting x0 = 0 and solving for w0, which is then used to set x1 = w0 and solve for w1. Then set x2 = w1, etc etc until you've got all k left-hand boundary points. The k+1th boundary point is obviously Pi/2.
The weighting function v effectively represents where the rectangle crosses the red line. A constant v = 0.5 is equivalent to it crossing in the middle, and gets you this with 10 points:
but you can play around with it to see what better balances the points. Ideally it should stay in the range [0, 1] and the sum of the values you use should be k/2.
If you want an even better approximation without messing around with weighting functions, you could try least-squares fitting a line rather than just fitting it to the endpoints, or you could try fitting a cubic polynomial to the blue curve instead of a linear polynomial. It'll entail solving quartics but if you've a maths package on hand that shouldn't be a problem.
Too long for a comment, so I suppose this has to be an answer ...
Here's a mathematically simple approach to forming a first order approximation. Pick one quadrant. You can generate the data for the other quadrants by reflection in the X and Y axis. Calculate (x,y) for the angle = 0 degrees, 1 degree, ... 90 degrees. Now you want the little lengths joining consecutive points. If (x_n, y_n) are the coordinates at angle = n, then Pythagoras tells us the distance D between points (x_n, y_n) and (x_n+1, y_n+1) is D = sqrt((x_n+1 - x_n)^2 + (y_n+1 - y_n)^2). Use this formula to produce a table of cumulative distances around the ellipse for angles from 0 degrees to 90 degrees. This is the inverse of the function you seek. Of course, you don't have to pick a stepsize of 1 degree; you could use any angle which exactly divides 90 degrees.
If you want to find the angle which corresponds to a perimeter step size of x, find the largest angle n in your table producing a partial perimeter less than or equal to x. The partial perimeter of angle n+1 will be larger than x. Use linear interpolation to find the fractional angle which corresponds to x.
All we are doing is approximating the ellipse with straight line segments and using them instead of the original curve; its a first order approximation. You could do somewhat better by using Simpson's rule or similar instead of linear interpolation.
Yes, you have to calculate the table in advance. But once you have the table, the calculations are easy. If you don't need too much accuracy, this is pretty simple both mathematically and coding-wise.

Rotate a line from one exact point to another

I need to mimic an angled line being drawn between two html elements using another html element that's essentially flat (1 px height by 200 px wide) like a line. Here's an example.
In this example, I hard-coded the angle of the line using the CSS skewY transform to make the lines angle at roughly 10px intervals. The problem is I need to do this dynamically using javascript. While already knowing the origin and destination points, I'll be using jQuery to style the line using skewY which requires a number in degrees.
How does one figure out the angle of the skew in order to have it start and end at 2 exact pixel points? I'm guessing they'll be some algebra involved.
Thanks!
Mark
Given the known starting point, and the known ending point, and the fact that each line appears to be the longest side of a right angle triangle, I would think a bit of trigonometry could come into play.
Assumptions would be that you know the x distance between the start and the end (in your code 'one' and 'two') i.e. the horizontal - call this the adjacent, and that you should be able to establish the distance from the top (the distance from the first two, to nth two), call this the opposite then one could establish the angle (lets call it x) by SOHCAHTOA being the TOA part (or TAN angle = Opposite over adjacent) or TAN x = O/A or x = tan -1 (O/A). If I remember correctly the angle will be in radians, so will need to be converted to degrees (multiple by 180/pi)
Sample code
var O = //to be set
var A = //to be set
var x = Math.atan(O/A) * (180 / Math.PI)

Linear regression to predict the y-value for the trend series

I have [x,y] pairs where x value is in Unix- time values and y in float. I am needing to find the best fit line for this series. I am using the linear regression model as in this link below:
http://dracoblue.net/dev/linear-least-squares-in-javascript/159/
I am getting the values correctly. But, Since my x-data is in unix timestamp, I get really huge values. So, has any one got any suggestions on how to tone it down? I tried using seconds instead of milliseconds, by diving the x-data by 1000. But, that just makes the difference in the final y-values very negligible and I don't see a proper trendline.
Any help would be appreciated.
Thanks,S.
Make it start at 0 : substract each occurence of a x value by what was the first x (say x0) value.
For instance, line 31 of your link :
replace x = values_x[v]; with x = values_x[v] - values_x[0];
If values_x is ordered and ascending then it should be ok
Can you subtract the first x value to the entire series so that the x start from 0?

Categories

Resources