我有一个数字域,例如domain = [100, 200],多个带可划分范围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
Run Code Online (Sandbox Code Playgroud)
这些值是固定的(硬编码):如果乐队成为乐队,bands = 6那么开发人员将选择的值band #6。
我想将域划分为多个带,其大小根据使用的规模而变化。例如,我可能要使用线性或对数或磅秤。
然后,我想要一个在输入中带有数字x ? domain并且必须返回v与inout编号所属的波段相关联的值的函数。
这是一个类似的问题,但是现在我想使用不同的比例(例如,可以使用d3 scales),但是我不知道如何。
这里是一段代码:
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
}
}
Run Code Online (Sandbox Code Playgroud)
其中min和max是域的最小值和最大值。
我认为梦游的例子很好,所以我把它们放在这里:
如果频段= 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
Run Code Online (Sandbox Code Playgroud)
(1)如果小数位数是线性的,并且domain = [0,100]->条带是:
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]
Run Code Online (Sandbox Code Playgroud)
例如:
if x = 0 --> v = 0.2
if x = 10 --> v = 0.2
if x = 21 --> v = 0.4
if x = 98 --> v = 1.0
Run Code Online (Sandbox Code Playgroud)
(2)如果小数位数是线性的,并且domain = [100,200]->带为:
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]
Run Code Online (Sandbox Code Playgroud)
例如:
if x = 100 --> v = 0.2
if x = 110 --> v = 0.2
if x = 121 --> v = 0.4
if x = 198 --> v = 1.0
Run Code Online (Sandbox Code Playgroud)
(3)如果小数位数是对数且domain = [0,100]->带为:
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 --> [?, ?]
Run Code Online (Sandbox Code Playgroud)
例如:
if x = 0 --> v = ?
if x = 10 --> v = ?
if x = 21 --> v = ?
if x = 98 --> v = ?
Run Code Online (Sandbox Code Playgroud)
在我之前的回答中,我展示了计算某个范围内数字的带索引的正确函数:
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 4Run Code Online (Sandbox Code Playgroud)
上述函数使用线性标度。然而,很容易将其推广到使用其他尺度:
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 4Run Code Online (Sandbox Code Playgroud)
这里我们使用对数刻度。请注意,我们在计算其对数之前增加了索引,因为零的对数是未定义的,尽管 JavaScript 很乐意返回趋于零的自然对数的极限x(x即-Infinity)。但是,-Infinity这不是一个有效的索引。
无论如何,我们的范围如下:
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
Run Code Online (Sandbox Code Playgroud)
请注意,虽然我们的尺度是对数的,但我们的范围呈指数增长。这是有道理的,因为当我们以对数方式缩放范围时,我们是将数字压缩在一起。因此,当我们将压缩范围划分为多个带时,每个带中的元素数量呈指数增长。下图可以最好地解释这一点:
在 x 轴上,我们有线性刻度,其值从1到101。在 y 轴上,我们有对数刻度,其值从log(1)到log(101)(出于教育目的表示为 5/5)。正如您所看到的,我们将对数范围划分为均匀大小的带。然而,在我们的线性尺度上,这些带会呈指数级增长。