【问题标题】:Conditional formatting -- percentage to color conversion条件格式——颜色转换的百分比
【发布时间】:2023-12-06 20:40:02
【问题描述】:

将百分比转换为从绿色 (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);

完美运行 - 我必须从 Marius 解决方案中进行的唯一调整是使用 256,因为 (255 - (percent - 50) * 5.12 在 100% 时产生 -1,由于某种原因在 Silverlight (-1, 255, 0) -> 黄色 ...

【问题讨论】:

    标签: c# colors rgb


    【解决方案1】:

    我用 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)";
    }
    

    【讨论】:

    • 如果 p = 50,它将为红色和绿色都生成 256
    【解决方案2】:

    您可能想要做的是在 HSV 或 HSL 颜色空间中分配 0% 到 100% 的一些点。从那里你可以插入颜色(黄色恰好介于红色和绿色之间:)和convert them to 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) 转换而来的),并且您可能需要稍微调整颜色以适应您的目的(有些人不喜欢红色和绿色不是“纯”的)。

    请看:

    【讨论】:

    • 最近解决了同样的问题,我认为色调之间的差异并不像 Henrik 提到的那样明显。我最终只是从 3 种颜色和范围中切换。
    【解决方案3】:

    在伪代码中。

    • 从 0-50% 开始,您的十六进制值为 FFxx00,其中:

      XX = ( Percentage / 50 ) * 255 converted into hex.
      
    • 从 50 到 100,您的十六进制值为 xxFF00,其中:

      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%。

      【讨论】:

      • 同意,这是一个比接受的答案更好的解决方案。
      【解决方案5】:

      我基于 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'
      

      【讨论】:

        【解决方案6】:

        由于黄色是红色和绿色的混合,您可以从#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);
        }
        

        【讨论】:

          【解决方案7】:

          我使用以下 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"
          

          【讨论】:

            【解决方案8】:

            我的 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;
            

            【讨论】:

              【解决方案9】:

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

              【讨论】: