ノート
完全なサンプルコードをダウンロードするには、ここをクリックしてください
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
.colors
s には属性がありません。ただし、整数配列または 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]
リストからセグメント化されたカラーマップを直接作成する#
上記のアプローチは非常に汎用性がありますが、実装が少し面倒です。一部の基本的なケースでは、 を使用した
LinearSegmentedColormap.from_list
方が簡単な場合があります。これにより、指定された色のリストから等間隔のセグメント化されたカラーマップが作成されます。
colors = ["darkorange", "gold", "lawngreen", "lightseagreen"]
cmap1 = LinearSegmentedColormap.from_list("mycmap", colors)
必要に応じて、カラーマップのノードを 0 ~ 1 の数値として指定できます。たとえば、カラーマップ内で赤みがかった部分により多くのスペースを占めるようにすることができます。
参考文献
この例では、次の関数、メソッド、クラス、およびモジュールの使用が示されています。
スクリプトの合計実行時間: ( 0 分 4.802 秒)