Pythonでヒートマップを作成しようとしています。このために、可能な値の範囲内のすべての値にRGB値を割り当てる必要があります。色を青(最小値)から緑(赤)(最大値)に変えることを考えました。
次の図の例は、色の構成をどのように考えているかを説明しています。1(純粋な青)から3(純粋な赤)までの範囲があり、2は緑に似ています。
私は線形補間について読み、最小と最大の間の範囲内の特定の値の計算を(多かれ少なかれ)処理してRGB Tupleを返す関数を作成しました。 if
条件とElif
条件を使用します(これは私を完全に幸せにしません):
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)
しかし、if
条件を使用して、各色の値withoutに対して関数を記述できるかどうか疑問に思います。誰もがアイデアを持っていますか?本当にありがとうございます!
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
これを行う別の方法は、可能な限り絶対的に短くはありませんが、特定の色のセットに対してハードコーディングされていないため、はるかに一般的です。これは、任意の色の可変サイズのパレット上で、指定された範囲の値を線形補間するためにも使用できることを意味します。
また、他の色空間で色が補間されている可能性があることに注意してください。これは、 Range values to pseudocolor というタイトルの関連質問に提出した2つの個別の回答から得られた異なる結果に示されています。
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))
数値出力:
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)
これは、水平方向のグラデーションとして視覚化された出力です。
多くの場合、2つの値の配列へのインデックスを使用して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]
_
_*_curve_1
_および_*_curve_2
_式を、それぞれ中点の左側または右側の定数または勾配または曲線に置き換えます。
これらの置換はあなたに任せますが、例えば:
red_curve_1
_および_blue_curve_2
_は、単に_0
_ですgreen_curve_1
_は255*(value-minimum)/(halfmax-minimum)
です「対数スケールで光の強度を感知します。指数関数的な強度ランプは線形ランプとして表示されます」 https://courses.cs.washington.edu/courses/cse455/09wi/Lects/lect11.pdf
https://en.wikipedia.org/wiki/RGB_color_model から:「(0.5、0.5、0.5)の入力強度RGB値は、フル輝度(1.0、1.0、 1.0)、50%の代わりに」
これにより、@ martineauの例では2.5で茶色がかった汚れになり、適切な色相勾配を得るために黄色で、1.5でシアンになります。
したがって、グラデーションを取得するために使用する式は、必ずしも必要なものではありません。 (質問に直接答えていないためごめんなさい)
ただし、HSVまたはHLS色空間モデルに変換し、H(色相)を使用して入力として使用し、表示目的でRGBに戻すのが便利な場合があります。すなわち:
colorsys.hsv_to_rgb(value, 1, 1)