Try   HackMD

不連続カラーバーの作成(Python)

概要

pythonで図を作成するとき,既存のcolormapを良く使用しますね.
普段は特に問題なく使用しているのですが,既存のcolormapを不連続にして使用したい時があります.
調べたところ,自作のcolormapを作成するのはたくさん載っていたんですが,ドンピシャのやり方がありませんでした.
色々調べた結果,できるようになったので簡単にまとめます.

今回はscatter でこの操作をしたかったので,それを載せます.
他のコマンドについては,自身で調べてみてください.
応用すれば使えると思いますが

目次

  1. 自作カラーマップの作成
  2. 既存colormapのカラーコード入手
  3. 最終コード
  4. あとがき

1.自作カラーマップの作成

まず,調べた中で一番多かった方法を紹介します.

とりあえずは以下のページを参考にしました.

コマンドはmatplotlib.colors.listedColormapを使用します.
テストコードは以下の通りです.

import numpy as np import matplotlib.pyplot as plt from matplotlib.colors import ListedColormap, BoundaryNorm # # データ作成 x = np.arange(0,101,1) y = np.arange(0,101,1) value = np.arange(0,101,1) # カラーマップ作成 cmap = ListedColormap(['red','blue','green','yellow']) bounds = np.linspace(0,100,5) norm = BoundaryNorm(bounds,cmap.N) # プロット plt.figure() sc = plt.scatter(x,y,c=value,cmap=cmap,norm=norm,\ vmin=min(bounds),vmax=max(bounds) ) cbar = plt.colorbar(sc,aspect=30,shrink=0.7) plt.show()

行っていることは,

  • 11行目で,自分が使いたい色を指定してカラーバーを作る.
  • 12行目で,色を与えるの区切りを指定.
  • 13行目で,正規化する(カラーバーが等間隔になる) ← 後で説明

これを行うとできるのが下の図です.
簡単ですね.

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

BoundaryNormboundsが等間隔でないの時に力を発揮します.
横のカラーバーに注目すると値は等間隔ではありませんが,バーの間隔は等間隔で見やすくなっています.(下に例を表示)

# 12行目のみを変更 bounds = [0, 10, 40, 85, 100]

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

2.既存colormapのカラーコード入手

さあ,本題に入りましょう.

調べた当初,ListedColormapの引数を,既存のcolormapにすればいいのではと考えて,

cmap = ListedColormap(cm.viridis)

としていたのですが,まあうまくいきません.

色を自分で直接入力して作成することも過去に行ったことがありましたが,その都度カラーバーの色を検索して手入力は非常にだるいし,汎用性がありません.

そこで,
colormapのカラーコードを自動で調べてくれる機能があれば,できるのでは? 
と思ったので,調べました.

そして,以下のサイトを見つけたのです!!

1つ目は色は16進数で指定することができること,2つ目はcolormapの色の16進数を抽出できることが示されています.

主に,2つ目が重要ですので読んでみてください.
以下にサンプルコードを示します(といってもほぼ写しですが).

import matplotlib.cm as cm from matplotlib.colors import rgb2hex cmap = cm.get_cmap('viridis',4) #colormapと分割数の指定 for i in range(cmap.N): rgb = cmap(i)[:3] print(rgb2hex(rgb))

出力:

#440154 #31688e #35b779 #fde725

これによって簡単にカラーコードを調べることができます.

3.最終コード

いよいよ実装する時が来ました.

1と2を組み合わせて,1つのコードにしましょう.
使い勝手がいいので,defを用いて書きました.

import numpy as np import matplotlib.pyplot as plt import matplotlib.cm as cm from matplotlib.colors import ListedColormap, BoundaryNorm, rgb2hex def main(): # カラーコードの入手(→ 2) colorname = 'viridis' num = 5 color_code = get_color_code(colorname,num) # データ作成 x = np.arange(0,101,1) y = np.arange(0,101,1) value = np.arange(0,101,1) # カラーマップ作成(→ 1) cmap = ListedColormap(color_code) #bounds = np.arange(0,101,20) bounds = [10,30,60,70,90] norm = BoundaryNorm(bounds,cmap.N) # 作図 plt.figure() sc = plt.scatter(x,y,c=x,cmap=cmap,norm=norm, \ vmin=min(bounds),vmax=max(bounds)) cbar = plt.colorbar(sc,aspect=30,shrink=0.7) plt.show() return def get_color_code(cname,num): cmap = cm.get_cmap(cname,num) code_list =[] for i in range(cmap.N): rgb = cmap(i)[:3] print(rgb2hex(rgb)) code_list.append(rgb2hex(rgb)) return code_list if __name__ == '__main__': main()

組み合わせる際に重要なのは8~10行目,32~42行目です.

get_color_codeの説明を簡単にします.

  • 2の出力されたカラーコードをlistとして保存して,mainコードに戻しています.

  • 入出力の引数は以下の通り.

    引数名 データ型 入出力
    cname str 入力
    num int 入力
    code_list list(要素はstr) 出力

出力された図は以下の通りです.
ちゃんとviridesを不連続にできてますね,成功です.

4.あとがき

今回は散布図のカラーマップに使う,不連続カラーマップの作成の仕方をまとめました.
冒頭でも述べている通り,作成したカラーマップは他のコマンド(imshowplot)にも応用可能だと思いますので,試してみてください.

tags: Python