青ポスの部屋

旅と技術とポエムのブログ

Matplotlibで既存のColormapをカスタムする

はじめに

Matplotlibのpcolorなどでカラーマップはよく使います。私はjetをよく使うのですが、「0のときに黒や白など色みのない色にしたい」など微調整したいときはしばしばあります。今回はその方法を調べたのでまとめておきます。

参考:Matplotlibで簡単に使えるカラーマップ

matplotlib.org

matplotlibのColormapオブジェクト

matplotlibのカラーマップはmatplotlib.cmライブラリ上でColormapオブジェクトとして管理されています。例えばjetのカラーマップは次のようにして生成できます。

    mycmap = cm.jet

このColormapオブジェクトにはcallableであるという特徴があります。どういうことかというと、0から1.0までの値かそのリストを引数に与えると、0~1.0が値域になっているカラーバーで対応する色をRGBAで出力してくれます。

    # 例:値0.5に対応するjetの色がmycolorに入る
    mycolor = mycmap(0.5)

またColormap自体は色のリストから生成することができます。jetのような連続的な分布をするカラーマップはLinearSegmentedColormap.from_list関数で生成できます。LinearSegmentedColormapでは 離散的に色をいくつか与えても自動的に補完してくれます。したがって、任意のカラーマップからいくつかの色をサンプリングしてfrom_list関数に与えればカラーマップを再構成することができますこの再構成する前の色のリストをいじることで、カスタマイズしたカラーマップを得ることができる、というわけです。

今回はjetの0のところを黒にしたいので、サンプリングした色のリストのうち0に対応する部分を黒に置き換えて再構成します

サンプルコード

n_base = 10 # サンプリングする個数

base_cmap = cm.jet
new_colors = base_cmap(np.linspace(0,1.0,n_base))

new_colors[0] = [0,0,0,1] #一番最初を黒(#000000, アルファ値1)にする 

# 色のリストから新たなカラーマップの生成
mycmap = colors.LinearSegmentedColormap.from_list("mycmap",new_colors) 

サンプリング数ですが少なすぎると黒に引きずられて全体が暗くなり、多すぎると黒い領域が少なすぎてうまく設定できません。経験則ですが等間隔で取るならば10くらいがちょうどよいでしょう*1

こうして得られたmycmapは他のカラーマップと同様にpcolorなどで使うことができます。

c = myax.pcolor(xx, yy, zz, shading="auto",cmap=mycmap)

補足

本記事は生成AI(Copilot)を用いて得たサンプルコードをヒントに用いています。

参考文献

*1:なお今回はnp.linspaceで与えているので等間隔になっていますが、サンプリングの仕方を工夫すればもうちょっと調整できる余地があります。