本記事では、python の matplotlib で自分好みの color map を作る方法について紹介します。「IDL にあったあのカラーマップが使いたい」という時などに便利です。
今回も例として、Spitzer の 8.0 µm データを使用します。
https://irsa.ipac.caltech.edu/data/SPITZER/GLIMPSE/images/I/1.2_mosaics_v3.5/GLON_30-53/
から GLM_03000+0000_mosaic_I4.fits をダウンロードしました。
まず必要なものを import します。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
from matplotlib.colorbar import ColorbarBase
from matplotlib.colors import LogNorm, Normalize
from matplotlib import cm
from astropy.io import fits
import aplpy
作り方
最初に、シンプルなカラーマップを作ります。
# red, green, blue 3色の出現するタイミング (0-255) とサチるタイミング (0-255) を設定します。
r_start, r_end = 190, 255
g_start, g_end = 95, 255
b_start, b_end = 0, 180
r_a1 = 1.0/(r_end - r_start) # y = a1*x + a2
r_a2 = -r_start*r_a1
g_a1 = 1.0/(g_end - g_start) # y = a1*x + a2
g_a2 = -g_start*g_a1
b_a1 = 1.0/(b_end - b_start) # y = a1*x + a2
b_a2 = -b_start*b_a1
cm_data = np.array([[r_a1*i+r_a2, g_a1*i+g_a2, b_a1*i+b_a2] for i in range(256)])
cm_data[cm_data<0.0] = 0.0
cm_data[cm_data>1.0] = 1.0
print(cm_data.shape)
#(256, 3)
plot すると以下のようになっています。
plt.figure(figsize=(8, 8))
plt.plot(cm_data[:, 0], "r")
plt.plot(cm_data[:, 1], "g")
plt.plot(cm_data[:, 2], "b")
plt.grid()
plt.show()
これを color map として定義するには以下のようにします。
cmap = LinearSegmentedColormap.from_list("bw", colors=cm_data, gamma=1.0)
ガンマ値を設定することもできます。いろいろ変えて plot してみます。 (ColorbarBase でカラーバーのみを plot しています。)
fig = plt.figure(figsize=(8, 8))
for i in range(6):
gamma = 0.3333*i
ax = fig.add_subplot(1, 12, 2*i+1)
cmap = LinearSegmentedColormap.from_list("bw", colors=cm_data, gamma=gamma)
cb = ColorbarBase(ax=ax, cmap=cmap, norm=Normalize(vmin=0, vmax=1), orientation="vertical")
plt.show()
単調なカラーバーは以上のような作り方で作れます。(余談ですが、近年は単調なカラーバーがより好まれる傾向にあります。)
r_start, r_end = 190, 255
g_start, g_end = 95, 255
b_start, b_end = 0, 180
の部分を色々変更して、好きなカラーバーを作りましょう。
rainbow や不規則なカラーバーを作りたい場合などは、値を直打ちでももちろんいけます。例えば、
cm_data = [[254,254,254],[254,246,246],[254,239,239],[254,232,232],[254,224,224],[254,217,217],[254,210,210],[254,203,203],[254,195,195],[254,188,188],[254,181,181],[254,173,173],[254,166,166],[254,159,159],[254,152,152],[254,144,144],[254,137,137],[254,130,130],[254,122,122],[254,115,115],[254,108,108],[254,101,101],[254,93,93],[254,86,86],[254,79,79],[254,71,71],[254,64,64],[254,57,57],[254,50,50],[254,42,42],[254,35,35],[254,28,28],[254,20,20],[254,13,13],[254,6,6],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,7,0],[254,15,0],[254,23,0],[254,27,0],[254,35,0],[254,43,0],[254,47,0],[254,55,0],[254,63,0],[254,67,0],[254,75,0],[254,83,0],[254,91,0],[254,95,0],[254,103,0],[254,111,0],[254,115,0],[254,123,0],[254,131,0],[254,135,0],[254,143,0],[254,151,0],[254,159,0],[254,163,0],[254,171,0],[254,179,0],[254,183,0],[254,191,0],[254,199,0],[254,203,0],[254,211,0],[254,219,0],[254,227,0],[254,231,0],[254,239,0],[254,247,0],[254,251,0],[247,254,0],[239,254,0],[235,254,0],[227,254,0],[219,254,0],[211,254,0],[207,254,0],[199,254,0],[191,254,0],[187,254,0],[179,254,0],[171,254,0],[167,254,0],[159,254,0],[151,254,0],[143,254,0],[139,254,0],[131,254,0],[123,254,0],[119,254,0],[111,254,0],[103,254,0],[99,254,0],[91,254,0],[83,254,0],[75,254,0],[71,254,0],[63,254,0],[55,254,0],[51,254,0],[43,254,0],[35,254,0],[31,254,0],[23,254,0],[15,254,0],[7,254,0],[3,254,0],[0,254,0],[0,254,7],[0,254,11],[0,254,19],[0,254,27],[0,254,31],[0,254,39],[0,254,47],[0,254,55],[0,254,59],[0,254,67],[0,254,75],[0,254,79],[0,254,87],[0,254,95],[0,254,99],[0,254,107],[0,254,115],[0,254,123],[0,254,127],[0,254,135],[0,254,143],[0,254,147],[0,254,155],[0,254,163],[0,254,167],[0,254,175],[0,254,183],[0,254,191],[0,254,195],[0,254,203],[0,254,211],[0,254,215],[0,254,223],[0,254,231],[0,254,235],[0,254,243],[0,254,251],[0,247,254],[0,243,254],[0,235,254],[0,227,254],[0,223,254],[0,215,254],[0,207,254],[0,203,254],[0,195,254],[0,187,254],[0,179,254],[0,175,254],[0,167,254],[0,159,254],[0,155,254],[0,147,254],[0,139,254],[0,135,254],[0,127,254],[0,119,254],[0,111,254],[0,107,254],[0,99,254],[0,91,254],[0,87,254],[0,79,254],[0,71,254],[0,67,254],[0,59,254],[0,51,254],[0,43,254],[0,39,254],[0,31,254],[0,23,254],[0,19,254],[0,11,254],[0,3,254],[0,0,254],[0,0,248],[0,0,243],[0,0,238],[0,0,233],[0,0,228],[0,0,223],[0,0,218],[0,0,213],[0,0,208],[0,0,203],[0,0,197],[0,0,192],[0,0,187],[0,0,182],[0,0,177],[0,0,172],[0,0,167],[0,0,162],[0,0,157],[0,0,152],[0,0,146],[0,0,141],[0,0,136],[0,0,131],[0,0,126],[0,0,121],[0,0,116],[0,0,111],[0,0,106],[0,0,101],[0,0,95],[0,0,90],[0,0,85],[0,0,80],[0,0,75],[0,0,70],[0,0,65],[0,0,60],[0,0,55],[0,0,50],[0,0,44],[0,0,39],[0,0,34],[0,0,29],[0,0,24],[0,0,19],[0,0,14],[0,0,9],[0,0,4],[0,0,0]]
cm_data = np.array(cm_data)/255.0
plt.figure(figsize=(8, 8))
plt.plot(cm_data[:, 0], "r")
plt.plot(cm_data[:, 1], "g")
plt.plot(cm_data[:, 2], "b")
plt.grid()
plt.show()
fig = plt.figure(figsize=(8, 8))
for i in range(6):
gamma = 0.3333*i
ax = fig.add_subplot(1, 12, 2*i+1)
cmap = LinearSegmentedColormap.from_list("bw", colors=cm_data, gamma=gamma)
cb = ColorbarBase(ax=ax, cmap=cmap, norm=Normalize(vmin=0, vmax=1), orientation="vertical")
plt.show()
使い方
毎回以上のコードを打つのはしんどいです。好きなカラーマップが出来上がったら、以下のようなテキストファイルを PYTHONPATH の通っている場所 (もしくは script や notebook と同じディレクトリ) に置いておきましょう。
PYTHONPATHは以下で確認できます。
import sys
print(sys.path)
mycmap_1.py
import numpy as np
from matplotlib.colors import LinearSegmentedColormap
def cm(reverse = False, gamma=1.):
r_start, r_end = 190, 255
g_start, g_end = 95, 255
b_start, b_end = 0, 180
r_a1 = 1.0/(r_end - r_start) # y = a1*x + a2
r_a2 = -r_start*r_a1
g_a1 = 1.0/(g_end - g_start) # y = a1*x + a2
g_a2 = -g_start*g_a1
b_a1 = 1.0/(b_end - b_start) # y = a1*x + a2
b_a2 = -b_start*b_a1
cm_data = np.array([[r_a1*i+r_a2, g_a1*i+g_a2, b_a1*i+b_a2] for i in range(256)])
cm_data[cm_data<0.0] = 0.0
cm_data[cm_data>1.0] = 1.0
if reverse == True:
cm_data=cm_data[::-1,:]
cm = LinearSegmentedColormap.from_list(__file__, colors=cm_data, gamma=gamma)
return cm
my_cmap_2.py
import numpy as np
from matplotlib.colors import LinearSegmentedColormap
def cm(reverse = False, gamma=1.):
cm_data = [[254,254,254],[254,246,246],[254,239,239],[254,232,232],[254,224,224],[254,217,217],[254,210,210],[254,203,203],[254,195,195],[254,188,188],[254,181,181],[254,173,173],[254,166,166],[254,159,159],[254,152,152],[254,144,144],[254,137,137],[254,130,130],[254,122,122],[254,115,115],[254,108,108],[254,101,101],[254,93,93],[254,86,86],[254,79,79],[254,71,71],[254,64,64],[254,57,57],[254,50,50],[254,42,42],[254,35,35],[254,28,28],[254,20,20],[254,13,13],[254,6,6],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,0,0],[254,7,0],[254,15,0],[254,23,0],[254,27,0],[254,35,0],[254,43,0],[254,47,0],[254,55,0],[254,63,0],[254,67,0],[254,75,0],[254,83,0],[254,91,0],[254,95,0],[254,103,0],[254,111,0],[254,115,0],[254,123,0],[254,131,0],[254,135,0],[254,143,0],[254,151,0],[254,159,0],[254,163,0],[254,171,0],[254,179,0],[254,183,0],[254,191,0],[254,199,0],[254,203,0],[254,211,0],[254,219,0],[254,227,0],[254,231,0],[254,239,0],[254,247,0],[254,251,0],[247,254,0],[239,254,0],[235,254,0],[227,254,0],[219,254,0],[211,254,0],[207,254,0],[199,254,0],[191,254,0],[187,254,0],[179,254,0],[171,254,0],[167,254,0],[159,254,0],[151,254,0],[143,254,0],[139,254,0],[131,254,0],[123,254,0],[119,254,0],[111,254,0],[103,254,0],[99,254,0],[91,254,0],[83,254,0],[75,254,0],[71,254,0],[63,254,0],[55,254,0],[51,254,0],[43,254,0],[35,254,0],[31,254,0],[23,254,0],[15,254,0],[7,254,0],[3,254,0],[0,254,0],[0,254,7],[0,254,11],[0,254,19],[0,254,27],[0,254,31],[0,254,39],[0,254,47],[0,254,55],[0,254,59],[0,254,67],[0,254,75],[0,254,79],[0,254,87],[0,254,95],[0,254,99],[0,254,107],[0,254,115],[0,254,123],[0,254,127],[0,254,135],[0,254,143],[0,254,147],[0,254,155],[0,254,163],[0,254,167],[0,254,175],[0,254,183],[0,254,191],[0,254,195],[0,254,203],[0,254,211],[0,254,215],[0,254,223],[0,254,231],[0,254,235],[0,254,243],[0,254,251],[0,247,254],[0,243,254],[0,235,254],[0,227,254],[0,223,254],[0,215,254],[0,207,254],[0,203,254],[0,195,254],[0,187,254],[0,179,254],[0,175,254],[0,167,254],[0,159,254],[0,155,254],[0,147,254],[0,139,254],[0,135,254],[0,127,254],[0,119,254],[0,111,254],[0,107,254],[0,99,254],[0,91,254],[0,87,254],[0,79,254],[0,71,254],[0,67,254],[0,59,254],[0,51,254],[0,43,254],[0,39,254],[0,31,254],[0,23,254],[0,19,254],[0,11,254],[0,3,254],[0,0,254],[0,0,248],[0,0,243],[0,0,238],[0,0,233],[0,0,228],[0,0,223],[0,0,218],[0,0,213],[0,0,208],[0,0,203],[0,0,197],[0,0,192],[0,0,187],[0,0,182],[0,0,177],[0,0,172],[0,0,167],[0,0,162],[0,0,157],[0,0,152],[0,0,146],[0,0,141],[0,0,136],[0,0,131],[0,0,126],[0,0,121],[0,0,116],[0,0,111],[0,0,106],[0,0,101],[0,0,95],[0,0,90],[0,0,85],[0,0,80],[0,0,75],[0,0,70],[0,0,65],[0,0,60],[0,0,55],[0,0,50],[0,0,44],[0,0,39],[0,0,34],[0,0,29],[0,0,24],[0,0,19],[0,0,14],[0,0,9],[0,0,4],[0,0,0]]
cm_data = np.array(cm_data)/255.0
if reverse == True:
cm_data=cm_data[::-1,:]
cm = LinearSegmentedColormap.from_list(__file__, colors=cm_data, gamma=gamma)
return cm
import することで呼び出せます。
import my_cmap_1
import my_cmap_2
使い方は、以下のように cmap を指定します。
fig = plt.figure(figsize=(12, 8))
f = aplpy.FITSFigure("~/your/fits/dir/GLM_03000+0000_mosaic_I4.fits", slices=[0], figure=fig, convention='wells')
f.show_colorscale(vmin=1, vmax=1000, cmap=my_cmap_1.cm(reverse=False, gamma=0.6), stretch="log")
fig = plt.figure(figsize=(12, 8))
f = aplpy.FITSFigure("~/your/fits/dir/GLM_03000+0000_mosaic_I4.fits", slices=[0], figure=fig, convention='wells')
f.show_colorscale(vmin=1, vmax=1200, cmap=my_cmap_2.cm(reverse=True, gamma=1.0), stretch="log")
既存のカラーマップの値を取り出す
例えば、デフォルトカラーマップの viridis のカラー情報を取り出して参考にしたい場合は、以下のようにします。
cm_data = np.array(cm.viridis.colors)
plt.figure(figsize=(8, 8))
plt.plot(cm_data[:, 0], "r")
plt.plot(cm_data[:, 1], "g")
plt.plot(cm_data[:, 2], "b")
plt.grid()
plt.show()
fig = plt.figure(figsize=(8, 8))
for i in range(6):
gamma = 0.3333*i
ax = fig.add_subplot(1, 12, 2*i+1)
cmap = LinearSegmentedColormap.from_list("bw", colors=cm_data, gamma=gamma)
cb = ColorbarBase(ax=ax, cmap=cmap, norm=Normalize(vmin=0, vmax=1), orientation="vertical")
plt.show()
cm_data[:,0] = cm_data[:,0]*0.5
fig = plt.figure(figsize=(8, 8))
for i in range(6):
gamma = 0.3333*i
ax = fig.add_subplot(1, 12, 2*i+1)
cmap = LinearSegmentedColormap.from_list("bw", colors=cm_data, gamma=gamma)
cb = ColorbarBase(ax=ax, cmap=cmap, norm=Normalize(vmin=0, vmax=1), orientation="vertical")
plt.show()
以上です。
リンク
目次