条件格式化 -- 百分比转颜色转换

21

如何将百分比转换为颜色,使其从绿色(100%)到红色(0%)之间变化,并在50%时呈黄色?

我使用的是简单的32位RGB格式——因此每个组件都是介于0和255之间的整数。我正在使用C#进行操作,但我想对于这样的问题来说,语言并不是那么重要。

基于Marius和Andy的答案,我采用以下解决方案:

double red = (percent < 50) ? 255 : 256 - (percent - 50) * 5.12;
double green = (percent > 50) ? 255 : percent * 5.12;
var color = Color.FromArgb(255, (byte)red, (byte)green, 0);

完美运作-我需要做出的唯一调整是使用256,因为在Silverlight中 (255 - (百分比 - 50) * 5.12) 在100%时会产生-1的值,导致黄色 (-1, 255, 0) -> 黄色 ...

9个回答

14

我用JavaScript编写了这个函数。它返回一个CSS字符串表示的颜色。它以百分比为变量,范围从0到100。该算法可以用任何语言实现:

function setColor(p){
    var red = p<50 ? 255 : Math.round(256 - (p-50)*5.12);
    var green = p>50 ? 255 : Math.round((p)*5.12);
    return "rgb(" + red + "," + green + ",0)";
}

1
如果p = 50,则红色和绿色都将生成256。 - Raj

6
你可能想要做的是在HSV或HSL颜色空间中为你的0%到100%分配一些点。从那里,你可以插值颜色(而黄色恰好在红色和绿色之间:)并将它们转换为RGB。这将给你两者之间漂亮的渐变。

然而,假设你将使用颜色作为状态指示器并从用户界面角度考虑,这可能不是一个好主意,因为我们很难看到颜色的微小变化。因此,将值分成三到七个桶会在事物发生变化时给你更明显的差异,但代价是一些精度(你很可能无法欣赏)。

所以,除了所有的数学,最后我建议使用以下颜色的查找表,其中v是输入值:

#e7241d for v <= 12%
#ef832c for v > 12% and v <= 36%
#fffd46 for v > 36% and v <= 60%
#9cfa40 for v > 60% and v <= 84%
#60f83d for v > 84%

这些颜色值是从HSL值(0.0, 1.0, 1.0)、(30.0, 1.0, 1.0)、(60.0, 1.0, 1.0)、(90.0, 1.0, 1.0)、(120.0, 1.0, 1.0)中转换而来的,但你可能需要调整一下颜色以适应你的需求(有些人不喜欢红色和绿色不是“纯粹”的)。请参阅以下内容:
- 使用HSL颜色(色相、饱和度、亮度)创建更美观的GUI 进行讨论 - RGB和HSL颜色空间转换 提供C#源代码示例。

最近我解决了同样的问题,我认为颜色之间的差异并不像Henrik所说的那样明显。最终,我只是从3种颜色和范围中切换。 - Iain M Norman

5
在伪代码中。
  • From 0-50% your hex value would be FFxx00 where:

    XX = ( Percentage / 50 ) * 255 converted into hex.
    
  • From 50-100 your hex value would be xxFF00 where:

    XX = ((100-Percentage) / 50) * 255 converted into hex.  
    
希望这有所帮助并且易于理解。

4
这是一个很好的干净解决方案,它在目前被接受的答案上有三个改进:
  1. 去除了魔数(5.12),因此使代码更易于理解。
  2. 不会产生四舍五入误差,即当百分比为100%时不会给出-1。
  3. 允许您自定义使用的最小和最大RGB值,因此您可以生成比简单的rgb(255,0,0)- rgb(0,255,0)更浅或更深的范围。
所示的代码是C#,但将算法调整到任何其他语言都是微不足道的。
private const int RGB_MAX = 255; // Reduce this for a darker range
private const int RGB_MIN = 0; // Increase this for a lighter range

private Color getColorFromPercentage(int percentage)
{
    // Work out the percentage of red and green to use (i.e. a percentage
    // of the range from RGB_MIN to RGB_MAX)
    var redPercent = Math.Min(200 - (percentage * 2), 100) / 100f;
    var greenPercent = Math.Min(percentage * 2, 100) / 100f;

    // Now convert those percentages to actual RGB values in the range
    // RGB_MIN - RGB_MAX
    var red = RGB_MIN + ((RGB_MAX - RGB_MIN) * redPercent);
    var green = RGB_MIN + ((RGB_MAX - RGB_MIN) * greenPercent);

    return Color.FromArgb(red, green, RGB_MIN);
}

注释

这里是一个简单的表格,展示了一些百分比值和我们想要生成的相应红色和绿色比例:

VALUE   GREEN    RED       RESULTING COLOUR
 100%    100%     0%       green
  75%    100%    50%       yellowy green
  50%    100%   100%       yellow
  25%     50%   100%       orange
   0%      0%   100%       red

我希望您能清楚地看到:

  • 绿色数值是百分比数值的2倍(但最高为100)
  • 红色数值则是相反数: 2x(100 - 百分比)(但最高为100)

因此,我的算法从类似以下表格的表中计算数值...

VALUE   GREEN    RED
 100%    200%     0%
  75%    150%    50%
  50%    100%   100%
  25%     50%   150%
   0%      0%   200%

...然后使用 Math.Min() 将它们限制在 100%。


1
同意,这比被接受的答案要好得多。 - robasaurus

1
我根据 JavaScript 代码编写了这个 Python 函数。它以小数形式接受一个百分比。我还对该值进行平方,以保持在百分比尺度下颜色更红。我还将颜色范围从 255 缩小到 180,在每个端点给出更深的红色和绿色。可以调整这些参数以获得漂亮的颜色。我想在中间加入一点橙色,但我必须继续正经的工作,唉。
def getBarColour(value):
    red = int( (1 - (value*value) ) * 180 )
    green = int( (value * value )* 180 )

    red = "%02X" % red
    green = "%02X" % green

    return '#' + red + green +'00'

1

由于黄色是红色和绿色的混合,因此您可以从#F00开始,然后将绿色滑动到#FF0,再将红色向下滑动到#0F0

for (int i = 0; i < 100; i++) {
    var red = i < 50
        ? 255
        : 255 - (256.0 / 100 * ((i - 50) * 2));
    var green = i < 50
        ? 256.0 / 100 * (i * 2)
        : 255;
    var col = Color.FromArgb((int) red, (int) green, 0);
}

0

我对ActionScript 3的解决方案:

var red:Number = (percentage <= 50) ? 255 : 256 - (percentage - 50) * 5.12;
var green:Number = (percentage >= 50) ? 255 : percentage * 5.12;

var redHex:Number = Math.round(red) * 0x10000;
var greenHex:Number = Math.round(green) * 0x100;

var colorToReturn:uint = redHex + greenHex;

0

我使用以下Python例程在颜色之间进行混合:

def blendRGBHex(hex1, hex2, fraction):
    return RGBDecToHex(blendRGB(RGBHexToDec(hex1), 
                                RGBHexToDec(hex2), fraction))

def blendRGB(dec1, dec2, fraction):
    return [int(v1 + (v2-v1)*fraction) 
        for (v1, v2) in zip(dec1, dec2)]

def RGBHexToDec(hex):
    return [int(hex[n:n+2],16) for n in range(0,len(hex),2)]

def RGBDecToHex(dec):
    return "".join(["%02x"%d for d in dec])

例如:

>>> blendRGBHex("FF8080", "80FF80", 0.5)
"BFBF80"

另一个例程将其封装起来,以在“条件格式设置”中的数字值之间实现良好的混合:
def colourRange(minV, minC, avgV, avgC, maxV, maxC, v):
    if v < minV: return minC
    if v > maxV: return maxC
    if v < avgV:
        return blendRGBHex(minC, avgC, (v - minV)/(avgV-minV))
    elif v > avgV:
        return blendRGBHex(avgC, maxC, (v - avgV)/(maxV-avgV))
    else:
        return avgC

所以,在乔纳斯的情况下:

>>> colourRange(0, "FF0000", 50, "FFFF00", 100, "00FF00", 25)
"FF7F00"

-1

因为它是 R-G-B 的,颜色从 -1(白色)的整数值到黑色的 -16777216。红绿和黄色介于中间。黄色实际上是 -256,而红色是 -65536,绿色是 -16744448。因此,在 RGB 表示法中,黄色实际上不在红色和绿色之间。我知道在波长方面,绿色在光谱的一侧,红色在另一侧,但我从未见过计算机使用这种类型的符号,因为光谱不能表示所有可见颜色。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接