Python 计算一系列值的 RGB 值以创建热图

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20792445/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 21:14:35  来源:igfitidea点击:

Calculate RGB value for a range of values to create heat map

pythoncolorsrgbheatmaplinear-interpolation

提问by aldorado

I am trying to create a heat map with python. For this I have to assign an RGB value to every value in the range of possible values. I thought of changing the color from blue (minimal value) over green to red (maximal value).

我正在尝试用 python 创建一个热图。为此,我必须为可能值范围内的每个值分配一个 RGB 值。我想将颜色从蓝色(最小值)更改为绿色到红色(最大值)。

The picture example below explains how I thought of the color composition: We have a range from 1 (pure blue) to 3 (pure red), 2 is in between resembled by green.

下面的图片示例解释了我对颜色组合的看法:我们有一个范围从 1(纯蓝色)到 3(纯红色),2 介于两者之间,类似于绿色。

color composition RGB in range(1-3)

范围内的颜色组合 RGB(1-3)

I read about linear interpolation and wrote a function that (more or less) handles the calculation for a certain value in the range between a minimum and a maximum and returns an RGB tuple. It uses ifand elifconditions (which does not make me completely happy):

我阅读了线性插值并编写了一个函数,该函数(或多或少)处理最小值和最大值之间范围内某个值的计算,并返回一个 RGB 元组。它的用途ifelif条件(这并不让我完全满意):

def convert_to_rgb(minimum, maximum, value):
    minimum, maximum = float(minimum), float(maximum)    
    halfmax = (minimum + maximum) / 2
    if minimum <= value <= halfmax:
        r = 0
        g = int( 255./(halfmax - minimum) * (value - minimum))
        b = int( 255. + -255./(halfmax - minimum)  * (value - minimum))
        return (r,g,b)    
    elif halfmax < value <= maximum:
        r = int( 255./(maximum - halfmax) * (value - halfmax))
        g = int( 255. + -255./(maximum - halfmax)  * (value - halfmax))
        b = 0
        return (r,g,b)

However I wonder if one could write a function for each color value withoutusing ifconditions. Does anybody have an idea? Thank you a lot!

但是我想知道是否可以在使用if条件的情况下为每个颜色值编写一个函数。有人有想法吗?非常感谢!

采纳答案by John1024

def rgb(minimum, maximum, value):
    minimum, maximum = float(minimum), float(maximum)
    ratio = 2 * (value-minimum) / (maximum - minimum)
    b = int(max(0, 255*(1 - ratio)))
    r = int(max(0, 255*(ratio - 1)))
    g = 255 - b - r
    return r, g, b

回答by Darren Stone

You can often eliminate an ifwith an index into an array of two values. Python lacks a ternary conditional operator, but this works:

您通常可以将if带有索引的 an消除到包含两个值的数组中。Python 缺少三元条件运算符,但这有效:

r = [red_curve_1, red_curve_2][value>=halfmax]
g = [green_curve_1, green_curve_2][value>=halfmax]
b = [blue_curve_1, blue_curve_2][value>=halfmax]

Replace the *_curve_1and *_curve_2expressions with the constants or slopes or curves either left or right of the midpoint, respectively.

分别用中点左侧或右侧的常数或斜率或曲线替换*_curve_1*_curve_2表达式。

I'll leave those substitutions to you, but for example:

我会把这些替换留给你,但例如:

  • red_curve_1and blue_curve_2are simply 0
  • green_curve_1is 255*(value-minimum)/(halfmax-minimum)
  • etc.
  • red_curve_1并且blue_curve_2只是0
  • green_curve_1255*(value-minimum)/(halfmax-minimum)
  • 等等。

回答by martineau

Here's another way to do it that, while not as absolutely short as possible, is much more general since it hasn't been hardcoded for your specific set of colors. This means it can also be used to linearly interpolate a specified range of values over a variably-sized palette of arbitrary colors.

这是另一种方法,虽然不是尽可能短,但更通用,因为它没有针对您的特定颜色集进行硬编码。这意味着它还可以用于在任意颜色的可变大小调色板上线性插入指定范围的值。

Also note that colors could have been interpolated in other colorspaces giving results that may be more pleasing than in others. This is illustrated in the different results obtained from the two separate answers I submitted to a related question titled Range values to pseudocolor.

另请注意,颜色可能已插入其他颜色空间,从而产生可能比其他颜色空间更令人愉悦的结果。这在我提交给题为Range values to pseudocolor的相关问题的两个单独答案中获得的不同结果中得到了说明。

import sys
EPSILON = sys.float_info.epsilon  # Smallest possible difference.

def convert_to_rgb(minval, maxval, val, colors):
    # "colors" is a series of RGB colors delineating a series of
    # adjacent linear color gradients between each pair.
    # Determine where the given value falls proportionality within
    # the range from minval->maxval and scale that fractional value
    # by the total number in the "colors" pallette.
    i_f = float(val-minval) / float(maxval-minval) * (len(colors)-1)
    # Determine the lower index of the pair of color indices this
    # value corresponds and its fractional distance between the lower
    # and the upper colors.
    i, f = int(i_f // 1), i_f % 1  # Split into whole & fractional parts.
    # Does it fall exactly on one of the color points?
    if f < EPSILON:
        return colors[i]
    else:  # Otherwise return a color within the range between them.
        (r1, g1, b1), (r2, g2, b2) = colors[i], colors[i+1]
        return int(r1 + f*(r2-r1)), int(g1 + f*(g2-g1)), int(b1 + f*(b2-b1))

if __name__ == '__main__':
    minval, maxval = 1, 3
    steps = 10
    delta = float(maxval-minval) / steps
    colors = [(0, 0, 255), (0, 255, 0), (255, 0, 0)]  # [BLUE, GREEN, RED]
    print('  Val       R    G    B')
    for i in range(steps+1):
        val = minval + i*delta
        r, g, b = convert_to_rgb(minval, maxval, val, colors)
        print('{:.3f} -> ({:3d}, {:3d}, {:3d})'.format(val, r, g, b))

Numeric output:

数字输出:

  Val       R    G    B
1.000 -> (  0,   0, 255)
1.200 -> (  0,  50, 204)
1.400 -> (  0, 101, 153)
1.600 -> (  0, 153, 101)
1.800 -> (  0, 204,  50)
2.000 -> (  0, 255,   0)
2.200 -> ( 51, 203,   0)
2.400 -> (102, 152,   0)
2.600 -> (153, 101,   0)
2.800 -> (203,  51,   0)
3.000 -> (255,   0,   0)

Here's the output visualized as a horizontal gradient:

这是可视化为水平渐变的输出:

horizontal gradient generated with function in answer

用函数生成的水平梯度作为答案

回答by Maarten Albers

"We sense light intensity on a logarithmic scale – an exponential intensity ramp will be seen as a linear ramp" https://courses.cs.washington.edu/courses/cse455/09wi/Lects/lect11.pdf

“我们在对数尺度上感知光强度——指数强度斜坡将被视为线性斜坡” https://courses.cs.washington.edu/courses/cse455/09wi/Lects/lect11.pdf

From the https://en.wikipedia.org/wiki/RGB_color_model: "an input intensity RGB value of (0.5, 0.5, 0.5) only outputs about 22% of full brightness (1.0, 1.0, 1.0), instead of 50%"

来自https://en.wikipedia.org/wiki/RGB_color_model:“输入强度 RGB 值 (0.5, 0.5, 0.5) 仅输出约 22% 的全亮度 (1.0, 1.0, 1.0),而不是 50% ”

This leads to the brownish smudge at 2.5 in @martineau example, where it should be yellow, and cyan at 1.5 in order to get a proper hue gradient.

这会导致@martineau 示例中 2.5 的褐色污迹,它应该是黄色,而青色是 1.5,以获得适当的色调渐变。

So the formula you should use to get the gradient is not necessarily what you will want. (sorry for not answering your question directly)

所以你应该用来获得梯度的公式不一定是你想要的。(抱歉没有直接回答你的问题)

But it might be handy to convert to the HSV or HLS color space model, and use H (for hue) and use that as input, and convert back to RGB for display purposes. ie:

但是转换为 HSV 或 HLS 颜色空间模型并使用 H(用于色调)并将其用作输入,然后转换回 RGB 以进行显示可能会很方便。IE:

colorsys.hsv_to_rgb(value, 1, 1)

https://docs.python.org/2/library/colorsys.html

https://docs.python.org/2/library/colorsys.html