0

我正在尝试创建一个将浮点值转换为颜色的函数。我创建了一个简单的线性比例:

float value;
float maxValue;

float scaleStep = maxValue / 5;

if (value < scaleStep) {
    color = blue
}

if (value > scaleStep && value <= scaleStep * 2) {
    color = green
}

if (value > scaleStep * 2 && value <= scaleStep * 3) {
    color = yellow
}

if (value > scaleStep * 3 && value <= scaleStep * 4) {
    color = orange
}

if (value > scaleStep * 4 && value <= scaleStep * 5) {
    color = red
}

但是由于我试图表示的集合中的大多数(但不是全部)值都与一个特定值非常接近,因此使用线性比例的图形表示并不是很有用(几乎所有内容都被转换为一种颜色)。

如何创建非线性比例,使值之间的差异更加明显?

4

5 回答 5

2

插值是你想要的。插值在数据集中的已知样本之间生成样本。

在这里,您已知的样本就是您的颜色;蓝色、绿色、黄色、橙色和红色。这些已知颜色之间的颜色就是您要寻找的颜色。

这是一个很好的插值函数可视化器的链接。

为了您的方便,这里有一些插值函数。和他们一起玩,找到最适合你的!

public float linearInterpolation(float start, float end, float normalizedValue) {
    return start + (end - start) * normalizedValue;
}

public float sinInterpolation(float start, float end, float normalizedValue){
    return (start+(end-start)* (1 - Math.cos(normalizedValue * Math.PI)) / 2;
}

//usage
linearInterpolation(red, green, .5f);//halfway between red and green.
//same with other demonstrations.

编辑:

这里,开始和结束指的是开始和结束样本。normalizedValue 是介于 [0, 1] 之间的某个值(这意味着它可以恰好等于 0 或 1,或介于 0 和 1 之间的任何值。这就是该术语的normalized典型含义。)

所以,对你来说,startend将是两种颜色,normalizedValue将代表你与开始或结束颜色的距离。

以线性插值为例。

red = 1;
green = 2;
float midway = 1 + (2 - 1) * .5;
//midway = 1.5, which is halfway between red and green.
float allRed = 1 + (2 - 1) * 0;
//allRed = 1, which is the value of red (or start)
float allGreen = 1 + (2 - 1) * 1;
//allGreen = 2, which is the value of green (or end)

因此,对于线性插值, 越接近normalizedValue1,返回值越接近end。越接近normalizedValue0,返回值越接近start

对于其他插值函数,这不一定是正确的。您可以将线性插值视为连接值的简单线段。想要介于这些细分市场之间的价值吗?使用归一化值 0.5,中提琴!

其他函数可能有更陡峭的斜率,甚至在start和之间振荡end

试着停止思考颜色,开始更抽象地思考。颜色相距一定距离。插值可帮助您定义它们之间的距离中的值。

于 2013-08-10T22:06:47.650 回答
1

由于浮点值在一组中,因此您知道有多少并且可以计算颜色区间。然后,您可以迭代它们,分配颜色并按颜色间隔递增。

编辑:这种方法的缺点是当值的数量发生变化时,相同的浮点值不会映射到相同的颜色。

于 2013-08-10T22:11:00.640 回答
0

我建议使用对数刻度。如果您使用以 10 为底的对数,则范围为 -39 到 +39。

于 2013-08-10T22:06:20.680 回答
0

在您的情况下,第二种选择(相对简单,因为您只想使用几种颜色)是使用scaleStep不同“宽度”的 s 。

if( value < greenMin ) color= blue ;
else if( value < yellowMin ) color= green ;
else if( value < orangeMin ) color= yellow ;
else if( value < redMin ) color = orange ;
else color= red ;

我冒昧地压缩了代码。如果不清楚,请告诉我。当然,您需要确定 greenMin、yellowMin、orangeMin 和 redMin 的值。为此,抓取一个具有代表性的大数据样本,对其进行排序,然后将其分成 5 组大小相等的组。第二组的第一个值是greenMin,第三组的第一个值是yellowMin,依此类推。您可以使用办公室电子表格程序来执行此操作,因为它是一次性活动。

于 2013-08-10T23:10:21.363 回答
0

根据您的分布,双重或三重对数可能会更好。我做了一个非常快速的测试,对于示例{ 1.00, 1.20, 1.10, 1.05, 1.15, 9.70, 1.20, 2.00, 1.01, 1.03, 1.16, 1.02, 9.00, 1.20, 1.10, 1.50, 1.05, 1.15, 2.00, 3.00 },功能

int f(float x) {
    return (int)(Math.log(Math.log(x)*100+1)*2.5) ;
}

产生以下分布:

f(x)  color   count
 0    blue      4
 1    green     4
 2    yellow    6
 3    orange    3
 4    red       3

5分钟的工作还不错。但是,如果您发布合理的数字样本(例如 100)、分布图,或者更好的是分布直方图,我们可以为您提供更好的帮助。诀窍是找到数据的分布函数。从该函数很容易得到第二个函数,使分布均匀(“平坦”)。

于 2013-08-10T22:51:24.357 回答