我想构建一个比例尺,将一系列连续整数(字符串中字符的索引)映射到另一个整数范围(像素,比如 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/
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
请帮助我理解范围运算符...和..之间的区别,作为Ruby中使用的“触发器”。这是PragmaticProgrammersguidetoRuby中的一个示例:a=(11..20).collect{|i|(i%4==0)..(i%3==0)?i:nil}返回:[nil,12,nil,nil,nil,16,17,18,nil,20]还有:a=(11..20).collect{|i|(i%4==0)...(i%3==0)?i:nil}返回:[nil,12,13,14,15,16,17,18,nil,20] 最佳答案 触发器(又名f/f)是
我正在尝试从Postgresql表(table1)中获取数据,该表由另一个相关表(property)的字段(table2)过滤。在纯SQL中,我会这样编写查询:SELECT*FROMtable1JOINtable2USING(table2_id)WHEREtable2.propertyLIKE'query%'这工作正常:scope:my_scope,->(query){includes(:table2).where("table2.property":query)}但我真正需要的是使用LIKE运算符进行过滤,而不是严格相等。然而,这是行不通的:scope:my_scope,->(que
我刚刚被困在这个问题上一段时间了。以这个基地为例:moduleTopclassTestendmoduleFooendend稍后,我可以通过这样做在Foo中定义扩展Test的类:moduleTopmoduleFooclassSomeTest但是,如果我尝试通过使用::指定模块来最小化缩进:moduleTop::FooclassFailure这失败了:NameError:uninitializedconstantTop::Foo::Test这是一个错误,还是仅仅是Ruby解析变量名的方式的逻辑结果? 最佳答案 Isthisabug,or
假设我有这个范围:("aaaaa".."zzzzz")如何在不事先/每次生成整个项目的情况下从范围中获取第N个项目? 最佳答案 一种快速简便的方法:("aaaaa".."zzzzz").first(42).last#==>"aaabp"如果出于某种原因你不得不一遍又一遍地这样做,或者如果你需要避免为前N个元素构建中间数组,你可以这样写:moduleEnumerabledefskip(n)returnto_enum:skip,nunlessblock_given?each_with_indexdo|item,index|yieldit
我正在尝试查询我的Rails数据库(Postgres)中的购买表,我想查询时间范围。例如,我想知道在所有日期的下午2点到3点之间进行了多少次购买。此表中有一个created_at列,但我不知道如何在不搜索特定日期的情况下完成此操作。我试过:Purchases.where("created_atBETWEEN?and?",Time.now-1.hour,Time.now)但这最终只会搜索今天与那些时间的日期。 最佳答案 您需要使用PostgreSQL'sdate_part/extractfunction从created_at中提取小时
有没有一种简单的方法可以将给定的整数格式化为具有固定长度和前导零的字符串?#convertnumberstostringsoffixedlength3[1,12,123,1234].map{|e|???}=>["001","012","123","234"]我找到了解决方案,但也许还有更聪明的方法。format('%03d',e)[-3..-1] 最佳答案 如何使用%1000而不是进行字符串操作来获取最后三位数字?[1,12,123,1234].map{|e|format('%03d',e%1000)}更新:根据theTinMan的
我认为我的问题最好用一个例子来描述。假设我有一个名为“Thing”的简单模型,它有一些简单数据类型的属性。像...Thing-foo:string-goo:string-bar:int这并不难。数据库表将包含具有这三个属性的三列,我可以使用@thing.foo或@thing.bar之类的东西访问它们。但我要解决的问题是当“foo”或“goo”不再包含在简单数据类型中时会发生什么?假设foo和goo代表相同类型的对象。也就是说,它们都是“Whazit”的实例,只是数据不同。所以现在事情可能看起来像这样......Thing-bar:int但是现在有一个新的模型叫做“Whazit”,看起来
我正在尝试使用在我的代码中是动态的Time.local来安排时间。在每个月的第一天,我传递的值是Time.local(2009,9,-1,0)。在PHP中,这会将时间设置为上个月的最后一天。在ruby中,我只是得到“ArgumentError:参数超出范围”。是我用错了方法还是什么?谢谢。 最佳答案 您应该使用DateTime类而不是Time。(您可能需要先require'date'并安装activesupportgem。)它比Time更通用,并且可以用DateTime.civil(2009,9-1,-1,0)做你想做的事。为天