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

本記事では、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 します。

```python
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
```
# 作り方
最初に、シンプルなカラーマップを作ります。

```python
# 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 すると以下のようになっています。

```python
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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117814/34442118-ff28-d4c2-1236-494b92524ad6.png)
これを color map として定義するには以下のようにします。

```python
cmap = LinearSegmentedColormap.from_list("bw", colors=cm_data, gamma=1.0)
```
ガンマ値を設定することもできます。いろいろ変えて plot してみます。 (ColorbarBase でカラーバーのみを plot しています。)

```python
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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117814/a915be85-5f46-4051-a491-60cc482145f8.png)
単調なカラーバーは以上のような作り方で作れます。(余談ですが、近年は単調なカラーバーがより好まれる傾向にあります。)

```python
r_start, r_end = 190, 255
g_start, g_end = 95, 255
b_start, b_end = 0, 180
```
の部分を色々変更して、好きなカラーバーを作りましょう。
rainbow や不規則なカラーバーを作りたい場合などは、値を直打ちでももちろんいけます。例えば、

```python
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
```

```python
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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117814/ffca8dbc-de53-74bc-a390-265bd4f64ff5.png)

```python
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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117814/b09d1dbc-a93e-b951-a2bc-9cceb8171797.png)

# 使い方
毎回以上のコードを打つのはしんどいです。好きなカラーマップが出来上がったら、以下のようなテキストファイルを PYTHONPATH の通っている場所 (もしくは script や notebook と同じディレクトリ) に置いておきましょう。
PYTHONPATHは以下で確認できます。

```python
import sys
print(sys.path)
```
### mycmap_1.py
```python
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

```python
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 することで呼び出せます。

```python
import my_cmap_1
import my_cmap_2
```
使い方は、以下のように cmap を指定します。

```python
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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117814/7b97ab5c-6358-65ba-0172-d64e18d99934.png)

```python
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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117814/6cc90e87-9ca2-661e-3e1b-65fd5b9d096d.png)

# 既存のカラーマップの値を取り出す
例えば、デフォルトカラーマップの viridis のカラー情報を取り出して参考にしたい場合は、以下のようにします。

```python
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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117814/bce5ef59-f5b3-5469-4960-72f7044a0340.png)

```python
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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117814/99ecf9d4-852c-7cb4-0603-d07e0a44019d.png)
ちょっと変えてみます。例えば赤を半分にします。

```python
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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117814/0ccb258b-2354-8005-e346-48b2fcf065c9.png)


以上です。

リンク
[目次](https://qiita.com/Shinji_Fujita/items/ecb869e5b6a9fa468483)