Use scales to remap a number

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:

Logarithmic Scale

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.

Tags:

Javascript