HOWTO · Matplotlib

Python Matplotlib を使用したカスタムカラーマップ

この記事では、Python で Matplotlib を使用してカスタムカラーマップを作成する方法について説明します。ListedColormap クラスと LinearSegmentedColormap クラスを使用して、Python で Matplotlib を使用してカスタムカラーマップを作成する 2つの方法を示します。

このページの内容

カテゴリごとに異なる色を割り当てる場合は ListedColormap を、値に応じて色を滑らかに変化させる場合は LinearSegmentedColormap を使います。どちらも Matplotlib のカラーマップクラスで、プロット関数の cmap 引数に渡せます。このガイドでは、組み込みカラーマップの確認方法と、RGBA 値の取得方法も紹介します。

Matplotlib を使って Python でカスタムカラーマップを作成する

カラーマップは数値を色に対応付けます。カテゴリコードや少数の固定色を使う場合は ListedColormap を定義します。値に応じて色を滑らかに変化させる測定データには、LinearSegmentedColormap を定義します。どちらのマップを適用する場合も、色を付ける値の範囲に合った正規化を使ってください。そうしないと、プロットの色が意図したデータ範囲を正しく表さないことがあります。

Matplotlib の get_cmap() 関数でカラーマップとその値を取得する

get_cmap() 関数を使うと、名前を指定して組み込みカラーマップを取得できます。カラーマップは呼び出し可能です。0 から 1 までの値を渡すと、最後の成分が不透明度を表す RGBA タプルが返ります。複数の色を確認するには、値の列を渡します。次の例では、サンプルした色を1つ出力します。

import matplotlib.pyplot as plt

viridis = plt.get_cmap("viridis")
print(viridis(0.56))
(np.float64(0.120081), np.float64(0.622161), np.float64(0.534946), np.float64(1.0))

有限個の色を持つルックアップテーブルが必要な場合は、viridis.resampled(8) でマップを再サンプリングします。ListedColormap の各色は colors から確認できます。一方、LinearSegmentedColormap のような連続カラーマップは、値を渡して呼び出すことでサンプリングできます。

ListedColormap の colors 属性を使って Python でカスタムのリスト型カラーマップを作成する

ListedColormap には、色名または数値の RGBA 値を指定できます。RGBA の各チャンネル値は通常、0 から 1 の範囲です。マップをリストとして表す場合、colors 属性に離散的な色の各項目が格納されます。次の独立した例では、色名と RGBA 値を使う両方の形式を作成し、色名で定義したマップを散布図のカテゴリコードに適用します。データに合わせて categories と正規化の設定を調整してください。

import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap, Normalize

named_map = ListedColormap(["darkorange", "gold", "lightseagreen"], name="groups")
rgba_map = ListedColormap([
    (0.58, 0.41, 0.27, 1.0),
    (0.00, 0.41, 0.27, 1.0),
    (0.58, 0.00, 0.27, 1.0),
], name="rgba_groups")

x = [1, 2, 3, 4, 5, 6]
y = [1, 4, 2, 5, 3, 6]
categories = [0, 0, 1, 1, 2, 2]
plt.scatter(x, y, c=categories, cmap=named_map, norm=Normalize(0, 2))
plt.colorbar(ticks=[0, 1, 2])
plt.show()

Normalize(0, 2) はカテゴリコードを3つの色に対応付け、カラーバーの目盛りは各コードを示します。明示的に指定した RGBA のリストを確認するには rgba_map.colors を使います。色の数とカテゴリコードの数が異なる場合は、各カテゴリに意図した色が割り当てられるよう、マップまたは正規化を調整してください。

Python でカスタムの線形セグメント化カラーマップを作成する方法

LinearSegmentedColormap は指定した位置の間で色チャンネルを補間し、グラデーションを作ります。その cdict(色辞書)には、red、green、blue などのチャンネルキーを指定します。各チャンネルの行は [x, yleft, yright] の形式です。x は0から1までの位置で、残りの値はその位置の左右におけるチャンネル値を表します。位置は0から1へ昇順に並べてください。アンカーポイントで左右の値が等しければ連続的に変化し、異なれば不連続な変化になります。

次の独立した例では、アンカーポイントを使ったグラデーションと、from_list() で作るグラデーションを用意し、それぞれをサンプルデータに表示します。プロットに表示されるタイトル「Anchors」と「Color list」は英語のままです。「Anchors」はアンカーポイントで定義したグラデーションを、「Color list」は色のリストから作るグラデーションを示します。描画された図は目視確認されていません。

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import LinearSegmentedColormap

cdict = {
    "red": [(0.0, 0.0, 0.0), (0.5, 0.1, 0.1), (1.0, 1.0, 1.0)],
    "green": [(0.0, 0.0, 0.0), (0.5, 0.8, 0.8), (1.0, 0.2, 0.2)],
    "blue": [(0.0, 0.4, 0.4), (0.5, 0.1, 0.1), (1.0, 0.0, 0.0)],
}
anchor_map = LinearSegmentedColormap("anchor_gradient", cdict, N=256)
list_map = LinearSegmentedColormap.from_list(
    "list_gradient", ["navy", "gold", "crimson"], N=256
)

values = np.arange(36).reshape(6, 6)
fig, axes = plt.subplots(1, 2)
for ax, cmap, title in zip(axes, [anchor_map, list_map], ["Anchors", "Color list"]):
    image = ax.imshow(values, cmap=cmap)
    ax.set_title(title)
    fig.colorbar(image, ax=ax)
plt.tight_layout()
plt.show()

チャンネル値を細かく制御したい場合や、アンカーポイントを明示したい場合は辞書形式のコンストラクターを使います。色名を並べたシンプルなグラデーションには LinearSegmentedColormap.from_list() を使います。色はマップ全体にわたって補間されます。N はルックアップテーブルのサイズを設定し、gamma は入力位置のスケーリングを制御します。

まとめ

色を明示的に割り当てる離散カテゴリには ListedColormap を選びます。連続的なグラデーションには LinearSegmentedColormap を使い、cdict のアンカーポイントまたは from_list() の色指定で作成できます。組み込みマップは get_cmap() で取得し、サンプルした RGBA 値を確認したうえで、適切な正規化とともにプロットへ渡してください。