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

Python 计算一系列值的RGB值以创建热图,python,colors,rgb,heatmap,linear-interpolation,Python,Colors,Rgb,Heatmap,Linear Interpolation,我正在尝试用python创建一个热图。为此,我必须为可能值范围内的每个值指定一个RGB值。我想把颜色从蓝色(最小值)改为红色(最大值) 下面的图片示例解释了我对颜色组成的想法:我们有一个从1(纯蓝色)到3(纯红色)的范围,2介于两者之间,类似于绿色 我阅读了有关线性插值的内容,并编写了一个函数(或多或少)处理最小值和最大值之间的某个值的计算,并返回一个RGB元组。它使用if和elif条件(这并不能让我完全高兴): def convert_to_rgb(最小值、最大值、值): 最小值,最大值=浮

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

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

我阅读了有关线性插值的内容,并编写了一个函数(或多或少)处理最小值和最大值之间的某个值的计算,并返回一个RGB元组。它使用
if
elif
条件(这并不能让我完全高兴):

def convert_to_rgb(最小值、最大值、值):
最小值,最大值=浮动(最小值),浮动(最大值)
半最大值=(最小值+最大值)/2

if-minimum通常可以通过索引将
if
消除为两个值的数组。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]
*\u curve\u 1
*\u curve\u 2
表达式分别替换为中点左侧或右侧的常数或斜率或曲线

我将把这些替换留给您,但例如:

  • red\u curve\u 1
    blue\u curve\u 2
    只是
    0
  • 绿色曲线1
    255*(最小值)/(最小半最大值)
  • 等等

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

还请注意,颜色可以在其他颜色空间中进行插值,得到的结果可能比其他颜色空间中的结果更令人满意。这一点在我提交给一个相关问题的两个单独答案中得到的不同结果中得到了说明

以下是显示为水平渐变的输出:

我们在对数尺度上感知光强度 –指数强度渐变将被视为线性 坡道“

来自:“输入强度RGB值(0.5,0.5,0.5)仅输出约22%的全亮度(1.0,1.0,1.0),而不是50%。”

这导致@martineau示例中2.5处出现褐色污点,其中应为黄色,1.5处为青色,以获得适当的色调梯度

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

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


这正是我所说的“条件索引”。顺便说一句,Python确实有一个三元运算符,它称之为。它允许像
r=red\u curve\u 1 if value>=halfmax else red\u curve\u 2
这样的语句——尽管我认为使用它会使它更明显地表明,该方法实际上没有摆脱OP试图消除的
if
条件。感谢您对条件表达式的提醒。它实际上比我提出的条件索引读起来更模糊。但正如你所说,OP显然想摆脱
if
。(条件表达式方法还有一个优点,即在返回其结果之前不计算所有内容。)
halfmax
应计算为
(最小-最大)/2
value/halfmax
应计算为
(值-最小)/halfmax
,否则,它仅在
最小值
为1且
最大值
为3时才能正常工作。请看:我已经使用了这段代码,它工作得很愉快,即使使用非常不同的颜色贴图(红色、橙色、白色)。这个解决方案可以通过代码中的注释来改进,帮助我们理解这里的理论和实践。例如,找到上面的浮点和int之间的差异有什么意义?一种看法是,
colors
通过2D颜色空间指定一条直线,线性输入映射到该直线上。@Wes:减法是分离浮点整数和小数部分的过程中涉及的步骤之一正在进行的第一次线性插值(aka)的结果。整数部分是
i
,小数部分是
f
。然后使用这两个值进行另一次lerp,以计算调色板中
颜色[i]
颜色[i+1]
之间的加权平均值(使用
f
,其范围为0–1.0)。这是我多年前发明的一种制作平滑渐变的技术。@Wes:这种观点的一个错误是,大多数颜色空间都是3D的(例如RGB、YIQ和HLS),而不是2D。对。通过三维颜色空间的线条。
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
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]
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` palette.
    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: # Return a color linearly interpolated in the range between it and 
          # the following one.
        (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))
colorsys.hsv_to_rgb(value, 1, 1)