1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

天文データ解析入門 その19 (自分好みの color map を作る)

Posted at

本記事では、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()

ダウンロード (8).png
これを 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()

ダウンロード (9).png
単調なカラーバーは以上のような作り方で作れます。(余談ですが、近年は単調なカラーバーがより好まれる傾向にあります。)

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()

ダウンロード (10).png

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()

ダウンロード (11).png

使い方

毎回以上のコードを打つのはしんどいです。好きなカラーマップが出来上がったら、以下のようなテキストファイルを 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")

ダウンロード (12).png

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")

ダウンロード (13).png

既存のカラーマップの値を取り出す

例えば、デフォルトカラーマップの 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()

ダウンロード (14).png

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()

ダウンロード (15).png
ちょっと変えてみます。例えば赤を半分にします。

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()

ダウンロード (16).png

以上です。

リンク
目次

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?