12

我有单元格,其数值可以是 0 到Integer.MAX_VALUE. 我想相应地对这些单元格进行颜色编码。

如果值 = 0,则 r = 0。如果值为Integer.MAX_VALUE,则 r = 255。但是介于两者之间的值呢?

我在想我需要一个函数,其限制为 x =>Integer.MAX_VALUE为 255。这个函数是什么?还是有更好的方法来做到这一点?

我可以这样做(value / (Integer.MAX_VALUE / 255)),但这会导致许多低值为零。所以也许我应该用日志功能来做。

我的大部分值都在 [0, 10,000] 范围内。所以我想强调那里的差异。

4

13 回答 13

16

“最公平”的线性缩放实际上是这样完成的:

floor(256 * value / (Integer.MAX_VALUE + 1))

请注意,这只是伪代码并假定浮点计算。

如果我们假设 Integer.MAX_VALUE + 1 是 2^31,并且 / 会给我们整数除法,那么它简化为

value / 8388608

为什么其他答案是错误的

一些答案(以及问题本身)暗示了(255 * value / Integer.MAX_VALUE). 据推测,这必须使用round()或转换为整数floor()

如果使用,则产生 255floor()的唯一值是 Integer.MAX_VALUE 本身。value这种分布是不均匀的。

如果使用round(),0 和 255 的命中次数分别是 1-254 的一半。也参差不齐。

使用我上面提到的缩放方法,不会出现这样的问题。

非线性方法

如果你想使用日志,试试这个:

255 * log(value + 1) / log(Integer.MAX_VALUE + 1)

您也可以只取该值的平方根(这不会一直到 255,但如果您愿意,可以按比例放大)。

于 2009-10-11T03:17:47.590 回答
5

我认为对数拟合会对此有好处,但看看结果,我不太确定。

然而,Wolfram|Alpha非常适合尝试这种事情

我从那个开始,最后是:

r(x) = floor(((11.5553 * log(14.4266 * (x + 1.0))) - 30.8419) / 0.9687)

有趣的是,事实证明,这与 Artelius 的回答几乎相同:

r(x) = floor(255 * log(x + 1) / log(2^31 + 1)

恕我直言,您最好使用 0-10000 和 10000-2^31 的拆分功能。

于 2009-10-11T19:48:35.113 回答
3

对于 0-2^32 到 0-255 范围的线性映射,只需取高位字节。这是使用二进制&和位移位的样子:

r = value & 0xff000000 >> 24

使用 mod 256 肯定会返回 0-255 的值,但您将无法从结果中得出任何分组意义 - 1、257、513、1025 都将映射到缩放值 1,即使它们彼此相距很远.

如果您想更加区分低值,并将更多大值合并在一起,那么日志表达式将起作用:

r = log(value)/log(pow(2,32))*256

编辑:哎呀,我的高中代数老师巴肯迈尔夫人会晕倒的! log(pow(2,32))与 相同32*log(2),而且评估成本要低得多现在我们也可以更好地考虑这一点,因为 256/32 甚至是 8:

r = 8 * log(value)/log(2)

log(value)/log(2)实际上log-base-2 of value,哪个日志为我们做了非常巧妙的事情:

r = 8 * log(value,2)

在那里,巴肯迈尔夫人——你的努力并没有完全白费!

于 2009-10-11T04:04:03.737 回答
2

一般来说(因为我不清楚这是一个 Java 还是与语言无关的问题)你会将你拥有的值除以 Integer.MAX_VALUE乘以255并转换为整数。

于 2009-10-11T03:04:39.207 回答
2

这行得通! r= value /8421504;

8421504 实际上是“神奇”数字,等于 MAX_VALUE/255。因此,MAX_VALUE/8421504 = 255(还有一些变化,但足够小的整数数学会摆脱它。

如果你想要一个没有幻数的,这应该可以工作(并且性能相同,因为任何好的编译器都会用实际值替换它:

r= value/ (Integer.MAX_VALUE/255);

好的部分是,这不需要任何浮点值。

于 2009-10-11T03:16:50.697 回答
1

您要查找的值是:r = 255 * (value / Integer.MAX_VALUE)。所以你必须把它变成一个双精度,然后再转换回一个整数。

于 2009-10-11T03:03:11.927 回答
1

请注意,如果您想要越来越亮,那么亮度不是线性的,因此从值到颜色的直接映射不会给出好的结果。

Color 类有一种方法可以使颜色更亮。看看那个。

于 2009-10-11T06:43:48.533 回答
1

这些答案中的大多数都讨论了线性实现,而 Artelius 的答案似乎是最好的。但最好的公式取决于你想要达到的目标以及你的价值观的分布。不知道很难给出一个理想的答案。

但只是为了说明,这些中的任何一个都可能最适合您:

  • 线性分布,每个映射到一个范围是整个范围的 1/266。
  • 对数分布(偏向低值),这将突出较低幅度的差异并减少较高幅度的差异
  • 反向对数分布(偏向高值),这将突出较高幅度的差异并减少较低幅度的差异。
  • 颜色出现的正态分布,其中每种颜色出现的次数与其他颜色相同。

同样,您需要确定您要实现的目标以及数据的用途。如果您的任务是构建它,那么我强烈建议您澄清它以确保它尽可能有用 - 并避免以后重新开发它。

于 2009-10-11T06:47:25.577 回答
1

问自己一个问题,“什么值应该映射到 128?” 如果答案大约是十亿(我怀疑是这样),那么使用线性。如果答案在 10-10 万范围内,则考虑平方根或对数。

另一个答案表明了这一点(我还不能评论或投票)。我同意。

r = log(值)/log(pow(2,32))*256

于 2009-10-11T07:17:51.397 回答
1

这里有一堆算法,用于在 C# 中使用扩展方法对数字进行缩放、规范化、排名等,尽管您可以将它们调整为其他语言:

http://www.redowlconsulting.com/Blog/post/2011/07/28/StatisticalTricksForLists.aspx

有一些解释和图形可以解释您何时可能想要使用一种或另一种方法。

于 2011-07-30T14:04:31.630 回答
0

最佳答案实际上取决于您想要的行为。

如果您希望每个单元格通常具有与相邻单元格不同的颜色,请使用akf在第二段中所说的内容并使用模数 (x % 256)。

如果您希望颜色对实际值有一定影响(例如“蓝色表示较小的值”一直到“红色表示较大的值”),您必须发布一些关于您预期的值分布的信息。由于您担心许多低值为零,我可能会猜测您有很多值,但这只是一个猜测。

在第二种情况下,您确实希望将可能的响应分配到 256 个“百分位数”中,并为每个百分位数分配一种颜色(其中每个百分位数的可能响应数量相等)。

于 2009-10-11T03:32:21.913 回答
0

如果您抱怨低数字变为零,那么您可能希望将值标准化为 255,而不是值的整个范围。

公式将变为:

currentValue /(集合的最大值)

于 2009-10-11T04:54:35.773 回答
-1

我可以这样做 (value / (Integer.MAX_VALUE / 255)) 但这会导致许多低值为零。

您可以采取的一种方法是使用模运算符 ( r = value%256;)。 尽管这不能确保Integer.MAX_VALUE结果为 255,但它可以保证 0 到 255 之间的数字。它还允许在 0-255 范围内分布低数字。

编辑:

有趣的是,当我对此进行测试时,Integer.MAX_VALUE % 256确实会导致255 (我最初错误地针对 进行了测试%255,从而产生了错误的结果)。这似乎是一个非常直接的解决方案。

于 2009-10-11T03:02:29.167 回答