Matplotlib でカラーマップを作成する#

Matplotlib には、 経由でアクセスできる多数の組み込みカラーマップがあります matplotlib.colormaps。多くの余分なカラーマップを持つpalettableのような外部ライブラリもあります 。

ただし、Matplotlib でカラーマップを作成または操作したいことがよくあります。これは、クラスListedColormapまたは LinearSegmentedColormap. 外側から見ると、どちらのカラーマップ クラスも 0 と 1 の間の値を一連の色にマップします。ただし、若干の違いがあります。その一部を以下に示します。

カラーマップを手動で作成または操作する前に、まず既存のカラーマップ クラスからカラーマップとその色を取得する方法を見てみましょう。

カラーマップの取得とその値へのアクセス#

まず、名前付きカラーマップを取得します。そのほとんどは 、Matplotlib でのカラーマップの選択matplotlib.colormapsにリストされています。これは、カラーマップ オブジェクトを返すを使用して実行できます。カラーマップを定義するために内部的に使用される色のリストの長さは、 で調整できますColormap.resampled。以下では、控えめな値の 8 を使用しているため、注目すべき値は多くありません。

import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
from matplotlib.colors import ListedColormap, LinearSegmentedColormap

viridis = mpl.colormaps['viridis'].resampled(8)

このオブジェクトviridisは呼び出し可能で、0 から 1 の間の float が渡されると、カラーマップから RGBA 値を返します。

print(viridis(0.56))
(0.122312, 0.633153, 0.530398, 1.0)

リストされたカラーマップ#

ListedColormap.colors色の値を属性に格納します。カラーマップを構成する色のリストには、プロパティを使用して直接アクセスするか、カラーマップの長さに一致する値の配列をcolors呼び出して間接的にアクセスできます。viridis返されるリストは RGBA Nx4 配列の形式であることに注意してください。ここで、N はカラーマップの長さです。

print('viridis.colors', viridis.colors)
print('viridis(range(8))', viridis(range(8)))
print('viridis(np.linspace(0, 1, 8))', viridis(np.linspace(0, 1, 8)))
viridis.colors [[0.267004 0.004874 0.329415 1.      ]
 [0.275191 0.194905 0.496005 1.      ]
 [0.212395 0.359683 0.55171  1.      ]
 [0.153364 0.497    0.557724 1.      ]
 [0.122312 0.633153 0.530398 1.      ]
 [0.288921 0.758394 0.428426 1.      ]
 [0.626579 0.854645 0.223353 1.      ]
 [0.993248 0.906157 0.143936 1.      ]]
viridis(range(8)) [[0.267004 0.004874 0.329415 1.      ]
 [0.275191 0.194905 0.496005 1.      ]
 [0.212395 0.359683 0.55171  1.      ]
 [0.153364 0.497    0.557724 1.      ]
 [0.122312 0.633153 0.530398 1.      ]
 [0.288921 0.758394 0.428426 1.      ]
 [0.626579 0.854645 0.223353 1.      ]
 [0.993248 0.906157 0.143936 1.      ]]
viridis(np.linspace(0, 1, 8)) [[0.267004 0.004874 0.329415 1.      ]
 [0.275191 0.194905 0.496005 1.      ]
 [0.212395 0.359683 0.55171  1.      ]
 [0.153364 0.497    0.557724 1.      ]
 [0.122312 0.633153 0.530398 1.      ]
 [0.288921 0.758394 0.428426 1.      ]
 [0.626579 0.854645 0.223353 1.      ]
 [0.993248 0.906157 0.143936 1.      ]]

カラーマップはルックアップ テーブルであるため、カラーマップを「オーバーサンプリング」すると最近傍補間が返されます (以下のリストで繰り返される色に注意してください)。

print('viridis(np.linspace(0, 1, 12))', viridis(np.linspace(0, 1, 12)))
viridis(np.linspace(0, 1, 12)) [[0.267004 0.004874 0.329415 1.      ]
 [0.267004 0.004874 0.329415 1.      ]
 [0.275191 0.194905 0.496005 1.      ]
 [0.212395 0.359683 0.55171  1.      ]
 [0.212395 0.359683 0.55171  1.      ]
 [0.153364 0.497    0.557724 1.      ]
 [0.122312 0.633153 0.530398 1.      ]
 [0.288921 0.758394 0.428426 1.      ]
 [0.288921 0.758394 0.428426 1.      ]
 [0.626579 0.854645 0.223353 1.      ]
 [0.993248 0.906157 0.143936 1.      ]
 [0.993248 0.906157 0.143936 1.      ]]

LinearSegmentedColormap #

LinearSegmentedColormap.colorss には属性がありません。ただし、整数配列または 0 ~ 1 の float 配列を使用してカラーマップを呼び出すことはできます。

copper = mpl.colormaps['copper'].resampled(8)

print('copper(range(8))', copper(range(8)))
print('copper(np.linspace(0, 1, 8))', copper(np.linspace(0, 1, 8)))
copper(range(8)) [[0.         0.         0.         1.        ]
 [0.17647055 0.1116     0.07107143 1.        ]
 [0.35294109 0.2232     0.14214286 1.        ]
 [0.52941164 0.3348     0.21321429 1.        ]
 [0.70588219 0.4464     0.28428571 1.        ]
 [0.88235273 0.558      0.35535714 1.        ]
 [1.         0.6696     0.42642857 1.        ]
 [1.         0.7812     0.4975     1.        ]]
copper(np.linspace(0, 1, 8)) [[0.         0.         0.         1.        ]
 [0.17647055 0.1116     0.07107143 1.        ]
 [0.35294109 0.2232     0.14214286 1.        ]
 [0.52941164 0.3348     0.21321429 1.        ]
 [0.70588219 0.4464     0.28428571 1.        ]
 [0.88235273 0.558      0.35535714 1.        ]
 [1.         0.6696     0.42642857 1.        ]
 [1.         0.7812     0.4975     1.        ]]

リストされたカラーマップの作成#

ListedColormapカラーマップの作成は、基本的に、新しいカラーマップを作成するためにカラー仕様のリストまたは配列を提供する上記の逆の操作です。

チュートリアルを続ける前に、1 つ以上のカラーマップを入力として取り、ランダム データを作成し、カラーマップをそのデータセットの画像プロットに適用するヘルパー関数を定義しましょう。

def plot_examples(colormaps):
    """
    Helper function to plot data with associated colormap.
    """
    np.random.seed(19680801)
    data = np.random.randn(30, 30)
    n = len(colormaps)
    fig, axs = plt.subplots(1, n, figsize=(n * 2 + 2, 3),
                            constrained_layout=True, squeeze=False)
    for [ax, cmap] in zip(axs.flat, colormaps):
        psm = ax.pcolormesh(data, cmap=cmap, rasterized=True, vmin=-4, vmax=4)
        fig.colorbar(psm, ax=ax)
    plt.show()

最も単純なケースでは、色名のリストを入力して、それらからカラーマップを作成します。

cmap = ListedColormap(["darkorange", "gold", "lawngreen", "lightseagreen"])
plot_examples([cmap])
カラーマップ操作

実際、そのリストには有効な Matplotlib color specificationが含まれている可能性があります。カスタム カラーマップの作成に特に役立つのは、Nx4 numpy 配列です。このような配列に対して実行できるさまざまな numpy 操作により、既存のカラーマップから新しいカラーマップを大工作業することは非常に簡単になります。

たとえば、何らかの理由で長さ 256 の「viridis」カラーマップの最初の 25 エントリをピンクにしたいとします。

viridis = mpl.colormaps['viridis'].resampled(256)
newcolors = viridis(np.linspace(0, 1, 256))
pink = np.array([248/256, 24/256, 148/256, 1])
newcolors[:25, :] = pink
newcmp = ListedColormap(newcolors)

plot_examples([viridis, newcmp])
カラーマップ操作

カラーマップのダイナミック レンジを減らすことができます。ここでは、カラーマップの中央半分を選択します。ただし、viridis はリストされたカラーマップであるため、元のカラーマップにあった 256 の値ではなく、128 の離散値になることに注意してください。このメソッドは、新しい色を追加するために色空間を補間しません。

viridis_big = mpl.colormaps['viridis']
newcmp = ListedColormap(viridis_big(np.linspace(0.25, 0.75, 128)))
plot_examples([viridis, newcmp])
カラーマップ操作

2 つのカラーマップを簡単に連結できます。

top = mpl.colormaps['Oranges_r'].resampled(128)
bottom = mpl.colormaps['Blues'].resampled(128)

newcolors = np.vstack((top(np.linspace(0, 1, 128)),
                       bottom(np.linspace(0, 1, 128))))
newcmp = ListedColormap(newcolors, name='OrangeBlue')
plot_examples([viridis, newcmp])
カラーマップ操作

もちろん、名前付きカラーマップから開始する必要はありません。渡す Nx4 配列を作成するだけで済みますListedColormap。ここでは、茶色 (RGB: 90、40、40) から白 (RGB: 255、255、255) までのカラーマップを作成します。

N = 256
vals = np.ones((N, 4))
vals[:, 0] = np.linspace(90/256, 1, N)
vals[:, 1] = np.linspace(40/256, 1, N)
vals[:, 2] = np.linspace(40/256, 1, N)
newcmp = ListedColormap(vals)
plot_examples([viridis, newcmp])
カラーマップ操作

線形セグメント化されたカラーマップの作成#

このLinearSegmentedColormapクラスは、RGB(A) 値が補間されるアンカー ポイントを使用してカラーマップを指定します。

これらのカラーマップを指定する形式では、アンカー ポイントでの不連続が許容されます。各アンカー ポイントは、 の形式の行列の行として指定されます。ここで、 はアンカー、 および はアンカー ポイントの両側の色の値です。[x[i] yleft[i] yright[i]]x[i]yleft[i]yright[i]

不連続がない場合、次のようになります。yleft[i] == yright[i]

cdict = {'red':   [[0.0,  0.0, 0.0],
                   [0.5,  1.0, 1.0],
                   [1.0,  1.0, 1.0]],
         'green': [[0.0,  0.0, 0.0],
                   [0.25, 0.0, 0.0],
                   [0.75, 1.0, 1.0],
                   [1.0,  1.0, 1.0]],
         'blue':  [[0.0,  0.0, 0.0],
                   [0.5,  0.0, 0.0],
                   [1.0,  1.0, 1.0]]}


def plot_linearmap(cdict):
    newcmp = LinearSegmentedColormap('testCmap', segmentdata=cdict, N=256)
    rgba = newcmp(np.linspace(0, 1, 256))
    fig, ax = plt.subplots(figsize=(4, 3), constrained_layout=True)
    col = ['r', 'g', 'b']
    for xx in [0.25, 0.5, 0.75]:
        ax.axvline(xx, color='0.7', linestyle='--')
    for i in range(3):
        ax.plot(np.arange(256)/256, rgba[:, i], color=col[i])
    ax.set_xlabel('index')
    ax.set_ylabel('RGB')
    plt.show()

plot_linearmap(cdict)
カラーマップ操作

アンカー ポイントで不連続性を作成するために、3 番目の列は 2 番目の列とは異なります。「赤」、「緑」、「青」、およびオプションで「アルファ」の各マトリックスは、次のように設定されます。

cdict['red'] = [...
                [x[i]      yleft[i]     yright[i]],
                [x[i+1]    yleft[i+1]   yright[i+1]],
               ...]

と の間のカラーマップに渡される値の場合、補間は と のx[i]間です。x[i+1]yright[i]yleft[i+1]

以下の例では、0.5 で赤色の不連続性があります。0 と 0.5 の間の補間は0.3から 1 になり、0.5 と 1 の間では 0.9 から 1 になります。すなわち、) は 1 の右側の値で、カラー マッピング ドメインの外側にあります。red[0, 1]red[2, 2]red[0, 1]yleft[0]red[2, 2]yright[2]

cdict['red'] = [[0.0,  0.0, 0.3],
                [0.5,  1.0, 0.9],
                [1.0,  1.0, 1.0]]
plot_linearmap(cdict)
カラーマップ操作

リストからセグメント化されたカラーマップを直接作成する#

上記のアプローチは非常に汎用性がありますが、実装が少し面倒です。一部の基本的なケースでは、 を使用した LinearSegmentedColormap.from_list方が簡単な場合があります。これにより、指定された色のリストから等間隔のセグメント化されたカラーマップが作成されます。

colors = ["darkorange", "gold", "lawngreen", "lightseagreen"]
cmap1 = LinearSegmentedColormap.from_list("mycmap", colors)

必要に応じて、カラーマップのノードを 0 ~ 1 の数値として指定できます。たとえば、カラーマップ内で赤みがかった部分により多くのスペースを占めるようにすることができます。

nodes = [0.0, 0.4, 0.8, 1.0]
cmap2 = LinearSegmentedColormap.from_list("mycmap", list(zip(nodes, colors)))

plot_examples([cmap1, cmap2])
カラーマップ操作

参考文献

この例では、次の関数、メソッド、クラス、およびモジュールの使用が示されています。

スクリプトの合計実行時間: ( 0 分 4.802 秒)

Sphinx-Gallery によって生成されたギャラリー