Use scales to remap a number - javascript

I have a domain of numbers, for example domain = [100, 200] and a number of bands in which to divide the range, for example bands = 5.
I know that each band corresponds to a value:
band #1 --> v = 0.2
band #2 --> v = 0.4
band #3 --> v = 0.6
band #4 --> v = 0.8
band #5 --> v = 1.0
These values are fixed (hard coded): if bands became bands = 6 then is the developer that choose what is the value of band #6.
I want to divide the domain into bands whose size varies according to the scale used.
For example I might want to use either the linear or the logarithmic or the pow scale.
Then I want a function that in input takes a number x ∈ domain and must return the value v associated with the band to which the inout number belongs.
Here a similar question, but now I want to use different scales (for example I can use d3 scales) but I don't know how..
Here a piece of code:
function getLinearScaledValue(x, min, max, bands) {
const range = max - min
if (x === max) {
return 1
} else {
return Math.floor(1 + ((x - min) / range) * bands) / bands
}
}
where min and max are the min and max value of the domain.
I think sleepwalking's examples was good so I put them here:
if bands = 5:
band #1 --> v = 0.2
band #2 --> v = 0.4
band #3 --> v = 0.6
band #4 --> v = 0.8
band #5 --> v = 1.0
(1) if scale is linear and domain = [0, 100] --> bands are:
band #1 --> v = 0.2 --> [0, 20]
band #2 --> v = 0.4 --> [21, 40]
band #3 --> v = 0.6 --> [41, 60]
band #4 --> v = 0.8 --> [61, 80]
band #5 --> v = 1.0 --> [81, 100]
for example:
if x = 0 --> v = 0.2
if x = 10 --> v = 0.2
if x = 21 --> v = 0.4
if x = 98 --> v = 1.0
(2) if scale is linear and domain = [100, 200] --> bands are:
band #1 --> v = 0.2 --> [100, 120]
band #2 --> v = 0.4 --> [121, 140]
band #3 --> v = 0.6 --> [141, 160]
band #4 --> v = 0.8 --> [161, 180]
band #5 --> v = 1.0 --> [181, 200]
for example:
if x = 100 --> v = 0.2
if x = 110 --> v = 0.2
if x = 121 --> v = 0.4
if x = 198 --> v = 1.0
(3) if scale is logarithmic and domain = [0, 100] --> bands are:
band #1 --> v = 0.2 --> [?, ?]
band #2 --> v = 0.4 --> [?, ?]
band #3 --> v = 0.6 --> [?, ?]
band #4 --> v = 0.8 --> [?, ?]
band #5 --> v = 1.0 --> [?, ?]
for example:
if x = 0 --> v = ?
if x = 10 --> v = ?
if x = 21 --> v = ?
if x = 98 --> v = ?

In my previous answer I showed the correct function to calcuate the band index of a number within a range:
const index = (min, max, bands, n) =>
Math.floor(bands * (n - min) / (max - min + 1));
const band = n => index(0, 100, 5, n);
console.log(band(0), band(20)); // 0 0
console.log(band(21), band(40)); // 1 1
console.log(band(41), band(60)); // 2 2
console.log(band(61), band(80)); // 3 3
console.log(band(81), band(100)); // 4 4
The above function uses a linear scale. However, it's easy to generalize it to use another scale:
const index = (scale, min, max, bands, n) =>
Math.floor(bands * scale(n - min) / scale(max - min + 1));
const log = x => Math.log(x + 1);
const logBand = n => index(log, 0, 100, 5, n);
console.log(logBand(0), logBand(1)); // 0 0
console.log(logBand(2), logBand(5)); // 1 1
console.log(logBand(6), logBand(15)); // 2 2
console.log(logBand(16), logBand(39)); // 3 3
console.log(logBand(40), logBand(100)); // 4 4
Here we used the logarithmic scale. Note that we incremented the index before calculating its logarithm because the logarithm of zero is undefined, although JavaScript happily returns the limit of the natural logarithm of x as x tends to zero (i.e. -Infinity). However, -Infinity is not a valid index.
Anyway, our ranges are as follows:
i: 0 --> [0 - 1] --> 0.2
i: 1 --> [2 - 5] --> 0.4
i: 2 --> [6 - 15] --> 0.6
i: 3 --> [16 - 39] --> 0.8
i: 4 --> [40 - 100] --> 1
Note that although our scale is logarithmic yet our ranges grow exponentially. This makes sense because when we scale our range logarithmically we're squishing numbers together. Hence, when we divide our squished range into bands, the number of elements in each band grows exponentially. It can be best explained by the following graph:
One the x-axis we have our linear scale with values from 1 to 101. On the y-axis we have our logarithmic scale with values from log(1) to log(101) (denoted as 5/5 for educational purposes). As you can see, we're dividing our logarithmic range into even sized bands. However, on our linear scale those bands become exponentially bigger.

First of all, you need conventions. You need to ask yourself the right questions.
What does logarithmic mean? The logarithm function has two inputs, a base and a value. The output is the power to which you raise the base in order to get the number. Let's suppose that the base is 2, and that the domain is 0–200. In this case you calculate log(2, 200), which is approximately 7.64. This means that we have the limits, [1, 2, 4, 8, 16, 32, 64, 128]. If we exclude 1 (i.e. 20), then we have 6 borders, which means we have 7 regions.
What happens if the domain is 200–400? In this case you would have only two regions, which doesn't make sense. In contrast with linear scaling, logarithmic scaling will yield different results for different domains even if their size is the same.
I think it makes sense to consider domains to be vectorial, i.e. it's irrelevant whether the domain is from 0–200 or from 200–400. The only constraints are that the domain is positive and 200 long. So, the domain 200–400 would be divided similarly to the domain 0–200, the only difference being the values. For the division itself we use the indices.
If we accept this convention, then the problem is greatly simplified. The domain 200–400 has a length of 201. Hence, instead of [1, 2, 4, 8, 16, 32, 64, 128] we have [201, 202, 204, 208, 216, 232, 264, 328].
Now the logarithmic scale look like the linear scale. The number of borders in the linear scale is equal to the base of the logarithm. Hence, in the case of a logarithmic scale, we would have this:
function getBaseLog(x, y) {
return Math.log(y) / Math.log(x);
}
function getLogarithmicScaledValue(x, min, max, base) {
return parseInt(getBaseLog(base, x - min));
}
See the logarithmic base conversion.
An obvious use-case of logarithmic scaling is that it plays well with heap data structures.

Related

Percentage value from different ranges

I tried from yesterday to find a formula in JavaScript (also math formula) that return the value, of a given percentage from 3 different cases.
Example:
range A = [0, 10 ] - percentage 25% => value will be 2.5
range B = [0, 100] - percentage 50% => value will be 50
but how do I treat this 2 cases?:
case 1 = range [-5, 5 ] - percentage for example 50% => value will be 0
case 2 = range [-10, 0 ] - percentage for example 25% => value will be -7.5
case 3 = range [-11, -1] - percentage for example 30% => value will be ?
Here is your formula:
Try this.
const percentage = function(x, y, perc){
// x is start point
// y is end point
// so you need length of this range (between x and y) and we subtract x from y
// and dividing to 100 (because 100% is full range between x and y)
// when we divide it to 100, the result is 1% of the range
// then we multiply it to percentage we want for example 25%
// and adding x to result. Because we started from x;
return ((y-x)/100)*perc+x;
}
console.log(percentage(0,10,25));
console.log(percentage(0,100,50));
console.log(percentage(-5,5,50));
console.log(percentage(-10,0,25));
console.log(percentage(-11,-1,30));

Getting two points on the edges of a rectangle

I have a rectangle and would like to:
Get a random point on one (any) of the sides.
Get a random point on one (except for the previously picked) side.
My initial approach is to create arrays for each possible side.
var arr:Array = [[{x:0,y:0}, // Top
{x:width,y:0}], //
[{x:width,y:0}, // Right
{x:width,y:height}], //
[{x:width,y:height}, // Bottom
{x:0,y:height}], //
[{x:0,y:height}, // Left
{x:0,y:0}]]; //
Then, I get the sides.
rand is an instance of Rand and has the methods:
.next() which provides a random number between 0 and 1
.between(x,y) which returns a random number between x and y.
var firstSide:Array = arr[rand.next() * arr.length];
var secondSide:Array;
do {
secondSide = arr[rand.next() * arr.length];
} while(secondSide.equals(firstSide));
Finally, I calculate my points.
var pointOnFirstSide:Object = {x:rand.between(firstSide[0].x, firstSide[1].x),
y:rand.between(firstSide[0].y, firstSide[1].y};
var pointOnSecondSide:Object = {x:rand.between(secondSide[0].x, secondSide[1].x),
y:rand.between(secondSide[0].y, secondSide[1].y};
I don't think this is the most efficient way to solve this.
How would you do it?
Assuming we have the following interfaces and types:
interface Rand {
next(): number;
between(x: number, y: number): number;
}
interface Point {
x: number;
y: number;
}
type PointPair = readonly [Point, Point];
and taking you at your word in the comment that the procedure is: first randomly pick two sides, and then pick random points on those sides... first let's see what's involved in picking two sides at random:
const s1 = Math.floor(rand.between(0, arr.length));
const s2 = (Math.floor(rand.between(1, arr.length)) + s1) % arr.length;
s1 and s2 represent the indices of arr that we are choosing. The first one chooses a whole number between 0 and one less than the length of the array. We do this by picking a real number (okay, floating point number, whatever) between 0 and the length of the array, and then taking the floor of that real number. Since the length is 4, what we are doing is picking a real number uniformly between 0 and 4. One quarter of those numbers are between 0 and 1, another quarter between 1 and 2, another quarter between 2 and 3, and the last quarter are between 3 and 4. That means you have a 25% chance of choosing each of 0, 1, 2 and 3. (The chance of choosing 4 is essentially 0, or perhaps exactly 0 if rand is implemented in the normal way which excludes the upper bound).
For s2 we now pick a number uniformly between 1 and the length of the array. In this case, we are picking 1, 2, or 3 with a 33% chance each. We add that number to s1 and then take the remainder when dividing by 4. Think of what we are doing as starting on the first side s1, and then moving either 1, 2, or 3 sides (say) clockwise to pick the next side. This completely eliminates the possibility of choosing the same side twice.
Now let's see what's involved in randomly picking a point on a line segment (which can be defined as a PointPair, corresponding to the two ends p1 and p2 of the line segment) given a Rand instance:
function randomPointOnSide([p1, p2]: PointPair, rand: Rand): Point {
const frac = rand.next(); // between 0 and 1
return { x: (p2.x - p1.x) * frac + p1.x, y: (p2.y - p1.y) * frac + p1.y };
}
Here what we do is pick a single random number frac, representing how far along the way from p1 to p2 we want to go. If frac is 0, we pick p1. If frac is 1, we pick p2. If frac is 0.5, we pick halfway between p1 and p2. The general formula for this is a linear interpolation between p1 and p2 given frac.
Hopefully between the two of those, you can implement the algorithm you're looking for. Good luck!
Link to code
jcalz already gave an excellent answer. Here is an alternate version for the variant I asked about in the comments: When you want your points uniformly chosen over two sides of the perimeter, so that if your w : h ratio was 4 : 1, the first point is four times as likely to lie on a horizontal side as a vertical one. (This means that the chance of hitting two opposite long sides is 24/45; two opposite short side, 1/45; and one of each, 20/45 -- by a simple but slightly tedious calculation.)
const rand = {
next: () => Math. random (),
between: (lo, hi) => lo + (hi - lo) * Math .random (),
}
const vertices = (w, h) => [ {x: 0, y: h}, {x: w, y: h}, {x: w, y: 0}, {x: 0, y: 0} ]
const edges = ([v1, v2, v3, v4]) => [ [v1, v2], [v2, v3], [v3, v4], [v4, v1] ]
const randomPoint = ([v1, v2], rand) => ({
x: v1 .x + rand .next () * (v2 .x - v1 .x),
y: v1 .y + rand .next () * (v2 .y - v1 .y),
})
const getIndex = (w, h, x) => x < w ? 0 : x < w + h ? 1 : x < w + h + w ? 2 : 3
const twoPoints = (w, h, rand) => {
const es = edges (vertices (w, h) )
const perimeter = 2 * w + 2 * h
const r1 = rand .between (0, perimeter)
const idx1 = getIndex (w, h, r1)
const r2 = (
rand. between (0, perimeter - (idx1 % 2 == 0 ? w : h)) +
Math .ceil ((idx1 + 1) / 2) * w + Math .floor ((idx1 + 1) / 2) * h
) % perimeter
const idx2 = getIndex (w, h, r2)
return {p1: randomPoint (es [idx1], rand), p2: randomPoint (es [idx2], rand)}
}
console .log (
// Ten random pairs on rectangle with width 5 and height 2
Array (10) .fill () .map (() => twoPoints (5, 2, rand))
)
The only complicated bit in there is the calculation of r2. We calculate a random number between 0 and the total length of the remaining three sides, by adding all four sides together and subtracting off the length of the current side, width if idx is even, height if it's odd. Then we add it to the total length of the sides up to and including the index (where the ceil and floor calls simply count the number of horizontal and vertical sides, these values multiplied by the width and height, respectively, and added together) and finally take a floating-point modulus of the result with the perimeter. This is the same technique as in jcalz's answer, but made more complex by dealing with side lengths rather than simple counts.
I didn't make rand an instance of any class or interface, and in fact didn't do any Typescript here, but you can add that yourself easily enough.

How to map a number in some ranges

I have a range of values like, for example, [0, 100] = [minValue, maxValue] and the number of bands, for example BANDS_NUMBER = 5.
So I can obtain these bands:
[0 - 20]
[21 - 40]
[41 - 60]
[61 - 80]
[81 - 100]
Then I want to associate a scale value at each range:
i: 0 --> [0 - 20] --> 0.2
i: 1 --> [21 - 40] --> 0.4
i: 2 --> [41 - 60] --> 0.6
i: 3 --> [61 - 80] --> 0.8
i: 4 --> [81 - 100] --> 1
This value is computed in this way: (i + 1) / BANDS_NUMBER where i is the index of a hypothetical loop.
Then I have an input n whose value is in range [minValue, maxValue] = [0, 100].
What I want is the scale value related to this number.
So, for example, if:
n = 0 --> scaleValue = 0.2
n = 10 --> scaleValue = 0.2
n = 20 --> scaleValue = 0.2
n = 35 --> scaleValue = 0.4
n = 68 --> scaleValue = 0.8
n = 99 --> scaleValue = 1
...
How can I create a function like that? I imagine a function like that:
function map(n, minValue, maxValue, bandsNumber) {
const scaleValue = ...
return scaleValue
}
All the values here are examples, I want that all works with any other values.
I don't know how to do to that. I need some help...
Nina Scholz's answer is wrong. Her normalize function returns 0.4 instead of 0.2 for the value 20:
function normalize(min, max, bands, n) {
return n === max
? 1
: Math.floor(1 + ((n - min) / (max - min)) * bands) / bands;
}
console.log(normalize(0, 100, 5, 20)); // expected 0.2, actual 0.4
Because 20 is in the first band, it should have the value 0.2:
i: 0 --> [0 - 20] --> 0.2
i: 1 --> [21 - 40] --> 0.4
i: 2 --> [41 - 60] --> 0.6
i: 3 --> [61 - 80] --> 0.8
i: 4 --> [81 - 100] --> 1
The correct answer is:
const index = (min, max, bands, n) =>
Math.floor(bands * (n - min) / (max - min + 1));
const band = n => index(0, 100, 5, n);
console.log(band(0), band(20)); // 0 0
console.log(band(21), band(40)); // 1 1
console.log(band(41), band(60)); // 2 2
console.log(band(61), band(80)); // 3 3
console.log(band(81), band(100)); // 4 4
As you can see, the edge cases are handled correctly. How did we get to this answer?
First, we find the length of the range which is max - min + 1. The + 1 is important because there are 101 elements in the range [0 - 100] inclusive.
Next, we get the index of the number n in the given range (i.e. n - min).
Then, we divide the index of n by the number of elements in the range to get a value in the range [0 - 1). Note that 1 is not in the range.
Finally, we multiply this value by the number of bands and discard the fractional part. The result is our index.
Note that if the length of the range is not divisible by the number of bands then the first x bands will have one additional element, where x is the remainder of dividing the length of the range by the number of bands.
Finally, we can get the value you want by incrementing the resulting index and then dividing it by the number of bands:
const index = (min, max, bands, n) =>
Math.floor(bands * (n - min) / (max - min + 1));
const value = (min, max, bands, n) =>
(index(min, max, bands, n) + 1) / bands;
const result = n => value(0, 100, 5, n);
console.log(result(0), result(20)); // 0.2 0.2
console.log(result(21), result(40)); // 0.4 0.4
console.log(result(41), result(60)); // 0.6 0.6
console.log(result(61), result(80)); // 0.8 0.8
console.log(result(81), result(100)); // 1 1
Hope that helps.
You could take a formula, which take the range and the slot and returns a normalized value.
Because of the range, which is a bit too long (the last value is included in the interval), you need a check for the last value and prevent getting the next value, outside of the wanted interval.
function normalize(min, max, bands, n) {
return n === max
? 1
: Math.floor(1 + ((n - min) / (max - min)) * bands) / bands;
}
// 0.2 0.2 0.4 0.4 0.8 1 1
console.log(...[0, 10, 20, 35, 68, 99, 100].map(normalize.bind(null, 0, 100, 5)));
You can use a native Array.map function to map each value.
Something like this:
const vals = [
[0, 20],
[21, 40],
[41, 60],
[61, 80],
[81, 100],
];
const BANDS_NUMBER = 5;
const result = vals.map((range, index) => (index + 1) / BANDS_NUMBER);
console.log(result);

Setting vAxis format in Google Line Chart [duplicate]

This question already has answers here:
Google Charts vertical axis in whole numbers
(4 answers)
Closed 9 years ago.
How to set the vAxis value format in google Line Chart in order to not get multiple lines with same value? Let's say I have lines with values: 1.5 1.0 0.5 and 0, after I set the format to '#', I got 0, 0, 1, 1...
Possible duplicate of this question
Copy-pasted answer:
If you just want numbers to display as whole numbers, then it's
easy:
function drawVisualization() {
// Create and populate the data table.
var data = google.visualization.arrayToDataTable([
['x', 'Cats', 'Blanket 1', 'Blanket 2'],
['A', 1, 1, 0.5],
['B', 2, 0.5, 1],
['C', 4, 1, 0.5],
['D', 8, 0.5, 1],
['E', 7, 1, 0.5],
['F', 7, 0.5, 1],
['G', 8, 1, 0.5],
['H', 4, 0.5, 1],
['I', 2, 1, 0.5],
['J', 3.5, 0.5, 1],
['K', 3, 1, 0.5],
['L', 3.5, 0.5, 1],
['M', 1, 1, 0.5],
['N', 1, 0.5, 1]
]);
// Create and draw the visualization.
new google.visualization.LineChart(document.getElementById('visualization')).
draw(data, {curveType: "function",
width: 500, height: 400,
vAxis: {maxValue: 10, format: '0'}}
);
}
If you go to [google playground][1] you will note that the axis labels
are 0, 2.5, 5, 7.5, 10. By adding the format: '0' to the vAxis, it
will display only whole numbers, so my labels become 0, 3, 5, 8, 10.
But obviously this is not ideal since 8 displays as being halfway
between 5 and 10, which it isn't, because the number is actually 7.5
and just being rounded.
Your ability to change the axis scale/labels is restricted. And to do
what you're asking would take a special bit of javascript to create an
appropriate scale and number of gridlines to prevent breaking things
down in to funky numbers.
Basically, you want to make sure that your maximum and minimum values,
and number of gridlines, allow for easy division such that you will
only get whole numbers. To do that, you need to create some funky new
logic. Here is some sample code that will allow you to get an
appropriate min/max axis value:
// Take the Max/Min of all data values in all graphs
var totalMax = 345;
var totalMin = -123;
// Figure out the largest number (positive or negative)
var biggestNumber = Math.max(Math.abs(totalMax),Math.abs(totalMin));
// Round to an exponent of 10 appropriate for the biggest number
var roundingExp = Math.floor(Math.log(biggestNumber) / Math.LN10);
var roundingDec = Math.pow(10,roundingExp);
// Round your max and min to the nearest exponent of 10
var newMax = Math.ceil(totalMax/roundingDec)*roundingDec;
var newMin = Math.floor(totalMin/roundingDec)*roundingDec;
// Determine the range of your values
var range = newMax - newMin;
// Define the number of gridlines (default 5)
var gridlines = 5;
// Determine an appropriate gap between gridlines
var interval = range / (gridlines - 1);
// Round that interval up to the exponent of 10
var newInterval = Math.ceil(interval/roundingDec)*roundingDec;
// Re-round your max and min to the new interval
var finalMax = Math.ceil(totalMax/newInterval)*newInterval;
var finalMin = Math.floor(totalMin/newInterval)*newInterval;
There are a couple issues here (unfortunately). The first is that I am
using the number of gridlines to determine the min/max values -- you
want to figure out how many gridlines you should have to use nice
whole numbers. The easiest way to do this, I think, would be as
follows (pseudo-code only):
// Take the Max/Min of all data values in all graphs
var totalMax = 3;
var totalMin = -1;
// Figure out the largest number (positive or negative)
var biggestNumber = Math.max(Math.abs(totalMax),Math.abs(totalMin));
// Round to an exponent of 10 appropriate for the biggest number
var roundingExp = Math.floor(Math.log(biggestNumber) / Math.LN10);
var roundingDec = Math.pow(10,roundingExp);
// Round your max and min to the nearest exponent of 10
var newMax = Math.ceil(totalMax/roundingDec)*roundingDec;
var newMin = Math.floor(totalMin/roundingDec)*roundingDec;
// Determine the range of your values
var range = newMax - newMin;
// Calculate the best factor for number of gridlines (2-5 gridlines)
// If the range of numbers divided by 2 or 5 is a whole number, use it
for (var i = 2; i <= 5; ++i) {
if ( Math.round(range/i) = range/i) {
var gridlines = i
}
}
Then you set the gridlines option (vAxis.gridlines) to the above
variable, and your max to newMax, and your min to newMin. That should
give you whole number axis labels.
Note: if your numbers are really small then the above function may not
work. The function is also not tested so please check it against some
examples on your own time and let me know if it doesn't work properly.
[1]:
http://code.google.com/apis/ajax/playground/?type=visualization#line_chart

Math equation for graph

I am working on a graphing class (in javascript) which uses canvas. This is just for experimental / learning purposes. Currently the graph scales correctly based on whatever height and width the canvas is set at. This is not a problem, and here is basically what I am doing to plot the correct coordinates [pseudo-code].
point[0] = [10, 15]
point[1] = [20, 10]
point[2] = [30, 20]
point[3] = [40, 15]
canvas width = 300
max x = 40
so for any given point:
position x = ( point[i][0] / max x ) * canvas width
simple enough. I get a ratio, then multiply it by the canvas width to plot it at the correct pixel.
The problem however, is coming up with an equation that would cause the minimum value of x to reside at 0 on the x coordinate of the graph, and the max value to be at the maximum point of the graph (which it already does because of the 1:1 ratio in my current equation). Currently the minimum value of x (10 in the example), resides at 75px in the x coordinate, because of the 1:4 ratio being multiplied to the canvas' width.
tldr / summary: I need to make a graph in which the minimum value is plotted at the beginning of the graph(0,0), and the maximum value plotted to the end.
try calculating a value for pixel-width-per-point first.
e.g.
widthPerPoint = canvasWidth / (maxX - minX)
then your position can be normalised to zero by subtracting the minimum value:
position = widthPerPoint * (point[i][0] - minX)
for your first example
widthPerPoint = 300 / (40 - 10) = 10
position = 10 * (point[i][0] - 10) = 10 * 0 = 0
and for the others:
point[0] = [10, 15] -> 0
point[1] = [20, 10] -> 100
point[2] = [30, 20] -> 200
point[3] = [40, 15] -> 300
at least I think that'll work....
Just loop over your points and record what you find (sorry, I can't do algorithm programming in JavaScript. pseudo-Python is so much easier):
minimum = [infinity, infinity, -1]
maximum = [-infinity, -infinity, -1]
for point in points:
if point.x > maximum.x and point.y > maximum.y:
maximum = [point.x, point.y, point.index]
if point.x < minimum.x and point.y < minimum.y:
minimum = [point.x, point.y, point.index]
if maximum.index == -1:
print 'No point is a maximum, so the points all lie in a horizontal line.'
maximum = [points[0].x, points[0].y, 0]
minimum = [points[0].x, points[0].y, 0]
You need to map linearly the range [min_x, max_x] to [0, width]. A point x = point[i][0] is mapped to
position(x) = width/(max_x - min_x) * (x - min_x).
Not sure I understand your question correctly. If so, this is the equation:
position x = (point[i][0] - min x) * canvas width / (max x - min x)
This way when point[i][0] is minimal (min x) your value is 0.0. and when it is maximal (max x) the value is canvas width, growing linearly.

Categories