标签:javascript d3-js
我想构建一个比例,将一系列连续的整数(字符串中的字符索引)映射到另一个整数范围(像素,比如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-js 来源: https://codeday.me/bug/20190519/1134664.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。