Posted at

【Python】matplotlibによるグラフ描画時のColormapのカスタマイズ

More than 3 years have passed since last update.

AdventarPython Advent Calendar 2015 21日目の記事です。

Pythonでグラフを描く時、Matplotlibを使うと思います。また最近はSeabornというグラフを綺麗にしてくれるライブラリがあり、自分はそれを愛用しています。ただ、色をもっと自由に選びたい、設定したいという時に+αでColormapのカスタマイズをすると便利です。今回はこれを紹介します。


準備

まずはいつもの一式インポートです。大体Anacondaにあるものですが、足りないものは pip install <入れたいライブラリ名>で入れることができます。

import numpy as np

import pandas as pd
from sklearn import datasets

import matplotlib.pyplot as plt
import matplotlib.cm as cm
%matplotlib inline
import seaborn as sns

sns.set(style="darkgrid", palette="muted", color_codes=True)

お試しに使うのは、いつものirisデータセットです。

# irisデータのロード

iris = datasets.load_iris()

そのまま素直に、irisの種別ごとに色分けして散布図を描くとこんな感じで、白黒になってしまいます・・・。

# 散布図の表示(色が白黒になってしまう・・・)

plt.figure(figsize=(10,7))
plt.scatter(iris.data[:,0], iris.data[:,1], linewidths=0, alpha=1,
c=iris.target # iris.targetには種別を表す[0, 1, 2]が入っているのでそれで色分け
)
plt.show()

plot_01.png

引数cに個別に色の名前を指定すると色を指定することが出来ます。でもあんまりスマートじゃない感じがします。

# 散布図の表示(ひとつずつ色を指定する)

def set_color(l):
if l == 0:
return "b" # blue
elif l == 1:
return "g" # green
else:
return "r" # red

color_list = map(set_color, iris.target)

plt.figure(figsize=(10,7))
plt.scatter(iris.data[:,0], iris.data[:,1], linewidths=0, alpha=1,
c=iris.target # iris.targetには種別を表す[0, 1, 2]が入っているのでそれで色分け
)
plt.show()

plot_02.png

種別ひとつずつに色を指定するのも大変なので、元々Matplotlibで定義されているカラーマップを使うこともできます。カラーマップについてはここを参考にすると様々なカラーマップの定義を見ることができます。

# 定義されているカラーマップを適用する

# 参考: http://matplotlib.org/examples/color/colormaps_reference.html

fig = plt.figure(figsize=(13,7))
im = plt.scatter(iris.data[:,0], iris.data[:,1], c=iris.target, linewidths=0, alpha=1,
cmap=cm.Accent # ここでカラーマップを指定
)
fig.colorbar(im)
plt.show()

でもちょっと欲しい色にバッチリ合わせるのが難しいですね・・・。

plot_03.png


Colormapのカスタマイズ

そこで、自分でこのカラーマップをカスタマイズして定義してみます。

色名もしくは16進のカラーコードをリストで指定すると、間を滑らかに線形補完しながらカラーマップを作ってくれます。日本語でうまく説明できないので、使用例を見てみましょう。

# colormapをカスタマイズする

from matplotlib.colors import LinearSegmentedColormap

def generate_cmap(colors):
"""自分で定義したカラーマップを返す"""
values = range(len(colors))

vmax = np.ceil(np.max(values))
color_list = []
for v, c in zip(values, colors):
color_list.append( ( v/ vmax, c) )
return LinearSegmentedColormap.from_list('custom_cmap', color_list)

irisデータは3種類なので、3つの色を指定します。使える色名称については、ここを参考にすると一覧で見ることができます。

# 色をカスタマイズ, その1:色名称で指定

# 参考: http://matplotlib.org/examples/color/named_colors.html
unique_value = set(iris.target)
print unique_value
# --> [0, 1, 2]

cm = generate_cmap(['mediumblue', 'limegreen', 'orangered'])

fig = plt.figure(figsize=(13,7))
im = plt.scatter(iris.data[:,0], iris.data[:,1], c=iris.target, linewidths=0, alpha=.8, cmap=cm)
fig.colorbar(im)
plt.show()

plot_04.png

色の名称ではなく、16進表現で指定することもできます。16進表現のカラーコードはこちらが参考になりました

# 色をカスタマイズ, その2:16進で指定

# http://www5.plala.or.jp/vaio0630/hp/c_code.htm

cm = generate_cmap(['#87CEEB', '#2E8B57', '#F4A460'])

fig = plt.figure(figsize=(13,7))
im = plt.scatter(iris.data[:,0], iris.data[:,1], c=iris.target, linewidths=0, alpha=.8, cmap=cm)
fig.colorbar(im)
plt.show()

plot_04-2.png

淡い色を指定した時は、背景がグレーよりも白の方が見やすいです。seabornで変更できるので背景を白にしてみます。

# 色をカスタマイズ, その3:背景を白くする

sns.set(style="whitegrid", palette="muted", color_codes=True)

cm = generate_cmap(['#87CEEB', '#2E8B57', '#F4A460'])

fig = plt.figure(figsize=(13,7))
im = plt.scatter(iris.data[:,0], iris.data[:,1], c=iris.target, linewidths=0, alpha=.8, cmap=cm)
fig.colorbar(im)
plt.show()

plot_05.png

次に、平面座標(2つの変数)を引数に取る関数の値を色で表現してみます。カラーマップのカスタマイズはこういったケースでとても有効ですね。

# 滑らかな塗りつぶし

n = 501
X, Y = np.meshgrid(np.linspace(0, 1, n), np.linspace(0, 1, n))
Z = np.sin(X*30) + np.cos(Y*30)
print np.min(Z), np.max(Z)

cm = generate_cmap(['#00008B', '#aaaaab', '#FFFFFF', '#F4D793', '#F4A460'])

fig =plt.figure(figsize=(10,8))
im = plt.pcolor(X, Y, Z, cmap=cm)

fig.colorbar(im)
plt.xlim(0, 1)
plt.ylim(0, 1)
plt.show()

plot_06.png

最後に、等高線の高さを色で表現してみる例です。こちらもカラーマップでグラデーション含め指定できることがとても有効です。

# 等高線

n = 201
X, Y = np.meshgrid(np.linspace(0, 1, n), np.linspace(0, 1, n))
Z = np.sin(X*20) * np.cos(Y*20)

cm = generate_cmap(['indigo', 'white', 'salmon'])

fig =plt.figure(figsize=(10,8))
interval = [i/10. -1 for i in range(20)]
im = plt.contour(X, Y, Z, interval, alpha=0.5, cmap=cm)

fig.colorbar(im)
plt.xlim(0, 1)
plt.ylim(0, 1)
plt.show()

plot_07.png


本記事のコード

GitHubにコードを掲載しています。

https://github.com/matsuken92/Qiita_Contents/blob/master/General/Matplotlib_color_settings.ipynb


参考

Matplotlib colormaps reference

 http://matplotlib.org/examples/color/colormaps_reference.html

Making a custom colormap using matplotlib in python (stackoverflow)

 http://stackoverflow.com/questions/24997926/making-a-custom-colormap-using-matplotlib-in-python

名前が定義されている色一覧

 http://matplotlib.org/examples/color/named_colors.html

16進カラーコード

 http://www5.plala.or.jp/vaio0630/hp/c_code.htm