はじめに
色の遷移情報(カラーバー)を使った擬似カラー画像(2次元ヒートマップ)は、数値を色にマッピングすることで情報を伝える手段として、医療、科学、工学、情報学といった様々な分野で使われています。色彩は情報の伝達に大きく影響し、例えば下図のようにカラーバーの種類によってその印象に違いが現れます。
実際、RGBの感度は多様性があり人それぞれで異なるため、正確な情報が求められる場合には、色だけでなく数値やグラフで補足したり、一般的に理解しやすいユニバーサルなカラーバーを使用することが重要です。Matplotlibのデフォルトであるviridis
、黒から黄色に遷移するcividis
、最も単調なgray
などは、明度が一定に遷移することから、比較的判別しやすいカラーバーとして知られています。カラーバーに限らずユニバーサルな色は公共の場でよく使われており、プログラマが知っているとよい色使い(JIS安全色)に詳しくまとめられていますので、興味のある方はご参照ください。
ただし、目的(例えば、周期性や正負の値が現れる、派手さやインパクトがほしいとき、特徴を多角的に解析したいとき)に応じて使い分ける楽しさや柔軟性を持ち合わせることも大事だと思います。
本記事ではMatplotlibの様々なカラーバーの色の遷移をRGBの3次元空間に描画し、それぞれの特徴を定性的に観察してみようと思います。普段愛用しているカラーマップをRGB空間で眺めてみたり、自身に適したカラーバーを見つける一助になれば幸いです。
本記事で使用したコードは、Goole Colabに載せています。
方法
実装コードとその説明
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.cm as cm
from matplotlib import colormaps
# カラーマップ
cmap_name = 'viridis'
# 角度リスト
angles = [(30, -60), (-90, 0), (0, -90), (0, 0)]
angles_name = ['R-G-B', 'G-R', 'R-B', 'G-B']
# 各カラーマップの色をプロット
fig = plt.figure(figsize=(20, 5))
for i, (angle, angle_name) in enumerate(zip(angles, angles_name)):
ax = fig.add_subplot(1, 4, i+1, projection='3d')
cmap = colormaps.get_cmap(cmap_name)
norm = plt.Normalize(vmin=0, vmax=1)
colors_rgb = cmap(norm(np.linspace(0, 1, 256)))[:, :3]
ax.scatter(colors_rgb[:, 0], colors_rgb[:, 1], colors_rgb[:, 2], c=colors_rgb, marker='o', s=3)
ax.set_title(f'View Angle: {angle_name}')
ax.set_xlabel('R')
ax.set_ylabel('G')
ax.set_zlabel('B')
ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
ax.set_zlim(0, 1)
ax.view_init(elev=angle[0], azim=angle[1])
ax.set_box_aspect([1, 1, 1])
fig.tight_layout()
plt.show()
- Matplotlibと必要なモジュールをインポート
matplotlib.pyplot
、numpy
、mpl_toolkits.mplot3d
、matplotlib.cm
、matplotlib.colormaps
をインポートします。 - カラーマップと角度の定義
使用するカラーマップ(例: 'viridis')と描画するview_init()
関数の角度のリスト(例:[(30, -60), (-90, 0), (0, -90), (0, 0)]
)を定義します。
angles_name
リストには、各角度に対応する説明を格納します。 - RGB空間にカラーマップをプロット
指定されたカラーマップを使用して、各角度から見たRGB空間にカラーマップの色をプロットします。
各カラーマップの色は、colormaps.get_cmap()
関数とNormalize()
関数を使用して、カラーバーの値とRGB値を紐づけます。cmap(norm(np.linspace(0, 1, 256)))[:, :3]
では、256段階の色を取得しますが、この時、透明度アルファが4次元目にあるため、それを除く値を保持できるように[:, :3]
のような指定をします。
RGB空間でカラーバー'viridis'をプロットした例(左から、適当な角度からのRGB空間、G-R、R-B、G-B方向のプロット)
上図左から、RGB空間で滑らかに遷移している様子がわかります。
また、上図2色(G-R、R-B、G-B)方向の射映プロットから程度の重なりが少ない(情報損失が小さい)ことがわかります。このように、任意の軸に射映した際の色の重なり度合いも、カラーバーの特徴を知る指標の一つだと思います。
主なカラーバーのRGBグラフ
Matplotlibに登録されているカラーバ一覧
補足
色の連続性に関する明度の問題
左下に示すjet
カラーバーを用いた図は、色の遷移が青から緑、緑から赤にかけて、明度の変化が急峻であり、その値付近で色合いが不連続に見えています。Turbo, An Improved Rainbow Colormap for Visualizationでは、この問題に対処するため、明度の変化を滑らかにしたturbo
カラーバーを提案しています。右下の図はこのturbo
を用いた結果です。jet
に比べて、より自然な色合いになっていることがわかります。人間は彩度よりも明度の変化に敏感であり、本記事では明度のグラフについて示していませんが、カラーバーの見た目として明度の滑らかさも重要な指標となります。カラーマップの明度については、Matplotlib公式のlightness-of matplotlib colormapsで説明されています。
周辺の色が及ぼす影響(同時対比)
Diverging Color Maps for Scientific Visualization (2009)で説明されているように、周囲の明るさによって色の知覚が変わる場合もあります。この問題は、同時対比(simultaneous contrast)と呼ばれます。下図に、同時対比の例を示します。
Diverging Color Maps for Scientific Visualization (2009) より引用
中央の長方形のグレーの画像(全領域で同じ色)は、背景のグレースケール画像によって、明るさが違うように見えます(具体的には、中央の長方形の左側は少し明るめで、右側にかけて暗いように見えると思います)。このため、2次元ヒートマップは周辺色との影響があることを念頭に置いて、観察することも重要です。
まとめ
本記事では、Matplotlibを使用してRGB空間に様々なカラーマップをプロットしました。各カラーマップは異なる角度から観察することで、その特徴を定性的に理解することができると思います。また、補足では2次元カラーマップにおける問題について説明しました。カラーバーの選択は情報の伝達に大きく影響するため、使用する目的やコンテキストに応じた適切な色を選択するための一助となれば幸いです。
参考資料