我正在尝试创建一个将浮点值转换为颜色的函数。我创建了一个简单的线性比例:
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
}
但是由于我试图表示的集合中的大多数(但不是全部)值与一个特定值非常接近,因此使用线性刻度的图形表示不是很有用(几乎所有内容都转换为一个颜色)。
如何创建非线性比例以使值之间的差异更明显?
答案 0 :(得分:2)
Interpolation就是你想要的。插值在数据集中的已知样本之间生成样本。
在这里,您已知的样本是您的颜色;蓝色,绿色,黄色,橙色和红色。这些已知颜色之间的颜色是您正在寻找的颜色。
Here's a link一个很好的插值函数可视化器。
这里有一些插值函数,方便您使用。与他们一起玩,找到最适合你的那个!
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.
编辑:
这里,start和end指的是一个开始和结束的样本。 normalizedValue是[0,1]之间的某个值(这意味着它可以恰好等于0或1,或0到1之间的任何值。这就是术语normalized
通常意味着什么。)
因此,对您而言,start
和end
将是两种颜色,normalizedValue
将表示您与起始颜色或结束颜色的接近程度。
以linearInterpolation为例。
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)
因此,对于线性插值,normalizedValue
越接近1,返回值越接近end
。 normalizedValue
越接近0,返回的值越接近start
。
其他插值函数不一定如此。您可以将线性插值视为连接值的简单线段。想要在这些细分市场之间获得价值吗?使用标准化值.5,viola!
其他功能可能会有更陡峭的斜率,甚至在start
和end
之间振荡!
尝试并停止思考颜色,并开始更抽象地思考。颜色相隔一定距离。插值可帮助您定义它们之间的距离中的值。
答案 1 :(得分:1)
由于浮点值在一个集合中,您知道有多少,并且可以计算颜色间隔。然后,您可以迭代它们,分配颜色并按颜色间隔递增。
编辑:这种方法的缺点是当值的数量发生变化时,相同的浮点值不会映射到相同的颜色。
答案 2 :(得分:0)
我建议采用对数标度。如果使用基数为10的日志,则范围将为-39到+39。
答案 3 :(得分: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),分布图,或者更好的是分布直方图,我们可以帮助您更好。诀窍是找到数据的分布函数。从该函数可以很容易地得到第二个函数,使得分布均匀(“平坦”)。
答案 4 :(得分:0)
在你的情况下的第二种选择(由于你只想使用几种颜色而相对简单),是使用不同“宽度”的scaleStep
。
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,依此类推。您可以使用办公室电子表格程序来执行此操作,因为这是一次性活动。