gpt4 book ai didi

javascript - 映射整数范围的最佳 d3 比例

转载 作者:数据小太阳 更新时间:2023-10-29 06:15:11 26 4
gpt4 key购买 nike

我想构建一个比例尺,将一系列连续整数(字符串中字符的索引)映射到另一个整数范围(像素,比如 0-600)中的规则间隔。也就是说,我想尽可能有规律地将字符分配给像素,反之亦然,一个字符的长度不一定是另一个的倍数。

例如,我希望将 [0,1,2,3] 映射到 400 像素

0 -> 0-99
1 -> 100-199
2 -> 200-299
3 -> 300-399

反之

0-99 -> 0
100-199 -> 1
200-299 -> 2
300-399 -> 3

虽然对于 0-4000 到 400 像素的映射,我希望

0-9 -> 0
10-19 -> 1
etc.

d3 中对此使用的最佳比例是多少?

一方面,如果元素数量很大,我担心离散尺度不会使用域被等分的事实并生成巨大的 switch 语句。因为我会在每个元素上使用比例来绘制图像,所以我担心性能。

另一方面,线性标度如

d3.scaleLinear()
.domain([0,399]) // 400 pixels
.rangeRound([0,3]) // 4 elements

给我

0 0
66 0 // 1st interval has 66 pixels
67 1
199 1 // other intervals have 132 pixels
200 2
332 2
333 3 // last interval has 66 pixels
400 3

( fiddle )

因此插值器返回不相等的间隔(末端较短)。

编辑: 不使用 d3,不难实现:

function coordinateFromSeqIndex(index, seqlength, canvasSize) {
return Math.floor(index * (canvasSize / seqlength));
}
function seqIndexFromCoordinate(px, seqlength, canvasSize) {
return Math.floor((seqlength/canvasSize) * px);
}

如果它不带有 d3 刻度,那就太糟糕了,因为它会变得更具可读性。

最佳答案

d3 Quantize Scale如果你想映射到一个区间是最好的选择。不过,比例映射在离散值和连续区间之间。我不是 100% 清楚你想做什么,但让我们看看我如何用量化尺度做你提到的一些事情。

将整数映射到区间很简单,只要您知道 d3 使用半开区间 [,) 来打散连续域即可。

var s1 = d3.scaleQuantize()
.domain([0,400])
.range([0,1,2,3]);

s1.invertExtent(0); // the array [0,100] represents the interval [0,100)
s1.invertExtent(1); // [100,200)
s1.invertExtent(2); // [200,300)
s1.invertExtent(3); // [300,400)

您还可以枚举离散值:

var interval = s.invertExtent(0);
d3.range(interval[0], interval[1]); // [0, 1, ... , 399]

不过,这些是您提供的不错的值,并且由于您希望将整数映射到整数区间,因此当数字不可整除时我们将需要舍入。不过,我们可以只使用 Math.round。

var s2 = d3.scaleQuantize()
.domain([0,250])
.range([0,1,2,3]);

s2.invertExtent(0); // [0, 62.5)
s2.invertExtent(0).map(Math.round); // [0,63) ... have to still interpret as half open

没有从区间本身到整数的映射,但是尺度将区间中的一个点从域(连续的)映射到它在范围内的值。

[0, 99, 99.9999, 100, 199, 250, 399, 400].map(s1); // [0, 0, 0, 1, 1, 2, 3, 3]

我还怀疑您将 rangeRound 的输出从线性刻度切换为其他东西。我明白了

var srr = d3.scaleLinear()
.domain([0,3]) // 4 elements
.rangeRound([0,399]);

[0,1,2,3].map(srr); // [0, 133, 266, 399]

var srr2 = d3.scaleLinear()
.domain([0,4]) // 4 intervals created with 5 endpoints
.rangeRound([0,400]);
[0,1,2,3,4].map(srr2); // [0, 100, 200, 300, 400]

对于我们来说,输出看起来像是一个带有 50% 填充的条形图的比例尺(然后每个位置将是 132 像素间隔的中点)。我猜测原因是 rangeRound 使用 round 来插值,而不是 floor。

如果您想要间隔的宽度,您也可以使用专为条形图设计的函数。

 var sb = d3.scaleBand().padding(0).domain([0,1,2,3]).rangeRound([0,400]);
[0,1,2,3].map(sb); // [0, 100, 200, 300]
sb.bandwidth(); // 100

这并不是说这些会使代码更简单。

一旦我了解了您实现的功能,似乎要求就简单多了。真的没有任何间隔。问题是没有一对一的映射。最好的解决方案要么是您已经完成的,要么只是使用两个带有自定义插值器的线性标尺(找到底线,而不是四舍五入。

var interpolateFloor = function (a,b) {
return function (t) {
return Math.floor(a * (1 - t) + b * t);
};
}

var canvasSize = 400;
var sequenceLength = 4000;

var coordinateFromSequenceIndex = d3.scaleLinear()
.domain([0, sequenceLength])
.range([0, canvasSize])
.interpolate(interpolateFloor);

var seqIndexFromCoordinate = d3.scaleLinear()
.domain([0, canvasSize ])
.range([0, sequenceLength])
.interpolate(interpolateFloor);

关于javascript - 映射整数范围的最佳 d3 比例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38867962/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com