Perceptually Uniform Colormaps
Matplotlibのカラーマップは多数用意されていていますが,特にperceptually uniform,すなわち知覚的に均一なものはデータを歪めることなく可視化できるのでとても優れています.また色覚障害のある方にも均一に見えるように設計されています.SciPy 2015において発表されたA Better Default Colormap for Matplotlibにperceptually uniformなカラーマップの開発話やmatlabデフォルトのカラーマップとの比較があります.
Matplotlibのデフォルトカラーマップ以外にも,cmoceanというパッケージをインストールすると更に多くのperceptually uniformなカラーマップを使えるようになります.
またCrameri et al.によるNature Communicationの論文"The misuse of colour in science communication"でも誤ったカラーマップの使用について議論されています.さらに,新しいperceptually uniformかつ色覚障害者にも優しいカラーマップとしてbatlow等が提案されています.
ここでテイラー・グリーン渦の渦度をjetと3種類のperceptually uniformなカラーマップで可視化してみましょう.
$$
\begin{aligned}
\omega &= 2 \sin x \sin y.
\end{aligned}
$$
こうやって比較してみるとjetが以下にデータを歪曲させているかが一目瞭然です.他のperceptually uniformなカラーマップは滑らかにデータを可視化できています.
簡単にカスタムカラーマップを自作したい
matplotlibのカラーマップを組み合わせる方法
上記で紹介したmatplotlibやcmoceanで大体は事足りるのですが,稀にそれ以外のカラーマップが欲しいときがあります.
Matplotlib公式に方法が載っていますが,基本的に2行でできます.
例としてMatplotlibのデフォルトカラーマップにある"Blues"と"OrRd"を使ってdivergingカラーマップを作ります.
import matplotlib as mpl
from matplotlib.colors import LinearSegmentedColormap
BuWhOr_colours = [(0, mpl.cm.datad['Blues'][-1]), (0.25, mpl.cm.datad['Blues'][4]), (0.4, mpl.cm.datad['Blues'][1]), (0.5, 'white'), (0.6, mpl.cm.datad['OrRd'][1]), (0.75, mpl.cm.datad['OrRd'][4]), (1, mpl.cm.datad['OrRd'][-1])]
BuWhOr = LinearSegmentedColormap.from_list('BuWhOr', BuWhOr_colours)
ここで
(0, mpl.cm.datad['Blues'][-1])
は新しいカラーマップの下端(0)でMatplotlib "Blues"の上端(-1)の色を指定という意味です.
cmoceanのカラーマップを組み合わせる方法
例としてcmoceanの"tempo"と"matter"を組み合わせてdivergingカラーマップを作ります.
from cmocean.cm import balance, curl, thermal, matter, tempo
from cmocean.tools import get_dict
tempo_cm = get_dict(tempo, N=9)
matter_cm = get_dict(matter, N=9)
TempoMatter_Colours = [(0, (tempo_cm['red'][-1][1], tempo_cm['green'][-1][1], tempo_cm['blue'][-1][1])), (0.25, (tempo_cm['red'][4][1], tempo_cm['green'][4][1], tempo_cm['blue'][4][1])),\
(0.4, (tempo_cm['red'][1][1], tempo_cm['green'][1][1], tempo_cm['blue'][1][1])), (0.5, 'white'), (0.6, (matter_cm['red'][1][1], matter_cm['green'][1][1], matter_cm['blue'][1][1])),\
(0.75, (matter_cm['red'][4][1], matter_cm['green'][4][1], matter_cm['blue'][4][1])), (1, (matter_cm['red'][-1][1], matter_cm['green'][-1][1], matter_cm['blue'][-1][1]))]
TempoMatter = LinearSegmentedColormap.from_list('TempoMatter', TempoMatter_Colours)
get_dict()
でカラーマップのRGBコード(辞書型)にアクセスします.
tempo_cm['red'][-1][1]
はtempo_cm
のRGBのうちRの下端という意味です.tempo_cm['red'][-1]
だけだと同じ値を二つ返してくるので最後に[1]
を足しています.
Matplotlib, cmocean, batlowの同系色のカラーマップと比較してみましょう.
綺麗なカラーマップができました!