あなたのデータ可視化、本当に「伝わって」いますか? もし、作成したグラフが「なんとなく見にくい」「メッセージが弱い」と感じるなら、それは配色に課題があるかもしれません。Matplotlibを用いたデータ可視化において、配色はメッセージを強力に伝える核心的な要素です。このガイドでは、Matplotlibで伝わるグラフを作成するための配色術を徹底解説します。基本的な色の指定方法から、連続値カラーマップとNormalizeによる高度なPythonグラフ表現、さらにはすべての人に情報が届く色覚バリアフリーなデザインまで、実践的なアプローチを分かりやすくご紹介します。
- この記事で学べること:Matplotlibの配色術で「伝わるグラフ」を作る
- 1. Matplotlibの基本的な色の指定:単色からカテゴリ色まで
- 2. 連続値データのカラーマップとNormalize:Pythonグラフでの高度な配色
- 3. 特殊なデータ分布への対応:LogNormとTwoSlopeNorm
- 4. カラーバーの正しい使い方:データ可視化における色の凡例
- 5. グラフ色識別の強化:ハッチとマーカーでカテゴリを分ける
- 6. 色覚バリアフリー対応のグラフ:アクセシブル データ可視化の基本
- 7. Matplotlibカラーマップの応用例:ヒストグラムと複数グラフ
- まとめ:Matplotlib配色とカラーマップで伝わるグラフへ
この記事で学べること:Matplotlibの配色術で「伝わるグラフ」を作る
1. Matplotlibの基本的な色の指定:単色からカテゴリ色まで
MatplotlibでPythonグラフに色を指定する方法はいくつかあります。これにより、グラフの要素を明確に区別し、データ可視化の効果を高めることができます。例えば、
- 色の名前で指定する(例:「blue」、List of named colors)
- ウェブで一般的な16進数カラーコード(例:「#FF7F0E」、原色大辞典)を使用する、
- 光の三原色を示すRGBタプル(例:「(0.2, 0.7, 0.3)」)で指定する、つまり、赤、緑、青の各要素が、それぞれの最大強度(1.0)に対してどれだけの割合(0.0~1.0)で含まれているかを指定する、
- Matplotlibが提供するカラースキームのインデックス(例:「C0」「C1」など。Specifying colors)
を利用することが可能です。これらはすべて、Matplotlib カラーコードとして利用できる基本的な方法です。特に複数のカテゴリを色分けする際には、tab10やPairedといったカテゴリカルカラーマップをcmap引数に指定することで、色覚バリアフリーにも配慮した識別しやすい色を自動で割り当てることができます。(Colormap reference)
import matplotlib.pyplot as plt
!pip install japanize-matplotlib > /dev/null # Google Colab の機能を使って日本語フォントをインストール・インポート
import japanize_matplotlib
fig, ax = plt.subplots()
ax.plot([0,1,2],[1,3,2], color="steelblue", label="色名") # 色名で指定
ax.plot([0,1,2],[2,2,3], color="#ff7f50", label="16進数") # 16進数で指定
ax.plot([0,1,2],[1.5,1.8,2.5], color=(0.2, 0.7, 0.3), label="RGB") # RGBタプルで指定
ax.plot([0,1,2],[2.6,1.6,2.0], color="C3", label="カラースキーム") # カラースキームのインデックスで指定
ax.plot([0,1,2],[3.2,0.8,1.5], color=plt.cm.tab10(4), label="tab10(4)") # カテゴリカルカラーマップのインデックスで指定
ax.legend()
ax.set_title("色の指定いろいろ")
plt.show()
2. 連続値データのカラーマップとNormalize:Pythonグラフでの高度な配色
データが連続的な数値(例:温度、標高、頻度など)である場合、その数値の大小や変化を色のグラデーションで表現すると、パターンや傾向を一目で把握しやすくなります。Matplotlibでこのような連続値表現をPythonグラフで行うには、主にc(色用の配列)、cmap(カラーマップ)、そしてNormalize(正規化)の3つの要素を組み合わせて使います。これらはデータ可視化において、伝わるグラフを作成するための重要な技術です。
カラーマップはこちら
2.1. c引数:連続値カラーマップに割り当てる数値データ
グラフ上の各データポイント(散布図の点やヒートマップのセルなど)に、どの数値を基に色を付けるかを指定します。例えば、散布図で点の高さ(y軸の値)に応じて色を変えたい場合は、c引数にそのy軸の値の配列を渡します。
2.2. cmap:Matplotlibカラーマップの選び方と利用
cmapはMatplotlibカラーマップの略で、入力された数値の大小を特定の色(グラデーション)に変換するための「設計図」のようなものです。例えば、viridisというカラーマップは、小さい値を濃い紫に、大きい値を明るい黄色に対応させます。jetのような虹色のカラーマップもありますが、データ可視化の誤解を招きやすいため、viridisやplasmaなどの「知覚的に均一な(Perceptually Uniform)」カラーマップが推奨されます。Matplotlib viridisは特に色覚バリアフリーの観点からも優れています。
2.3. Normalize:Matplotlib Normalizeで色の範囲を正確に制御
Normalizeは、cで指定された数値データを、カラーマップが扱う標準的な範囲(通常は0から1)に変換する役割を持ちます。特に重要なのは、Normalize(vmin=最小値, vmax=最大値)のように、色のマッピングに使われる値の最小値(vmin)と最大値(vmax)を明示的に指定できる点です。Matplotlib Normalizeの利用は、再現性の高いグラフ作成に不可欠です。
- なぜ
Normalizeが重要か?
* 再現性: vminとvmaxを固定することで、データの値が多少変わっても、同じ値は常に同じ色で表現されます。これにより、複数のPythonグラフ間での比較や、時間経過による変化の追跡が非常にしやすくなります。 * 一貫性: 異なるデータセットや異なるプロットであっても、同じvminとvmaxを使ってNormalizeを設定すれば、色の意味合いを統一できます。 * 解釈のしやすさ: ユーザーがカラーバーを見たときに、色がどの数値範囲に対応しているのかを正確に理解できます。
これらの要素を組み合わせることで、どのデータポイント(c)を、どのような色のグラデーション(cmap)で、どの数値範囲(Normalize)に基づいて表現するかを細かくコントロールし、データのメッセージをより効果的に伝えることができるのです。
import numpy as np
import matplotlib.pyplot as plt
!pip install japanize-matplotlib > /dev/null # Google Colab の機能を使って日本語フォントをインストール・インポート
import japanize_matplotlib
from matplotlib import cm, colors
np.random.seed(0)
x = np.linspace(0, 10, 150)
y = np.sin(x) + np.random.normal(scale=0.2, size=len(x))
val = (y - y.min()) / (y.max() - y.min()) # データを0〜1の範囲に収まる(=正規化)
norm = colors.Normalize(vmin=0, vmax=1) # 値範囲を固定
cmap = cm.viridis # 色覚配慮の推奨CMAP
fig, ax = plt.subplots()
sc = ax.scatter(x, y, c=val, cmap=cmap, norm=norm, s=60, alpha=0.8) #s=60,alpha=0.8:色のサイズと透明度を設定
ax.set_title("連続値の色分け(Normalize指定)")
cbar = plt.colorbar(sc, ax=ax) # カラーバーは後述
cbar.set_label("正規化された値 (0-1)")
plt.show()
2.4. 推奨と非推奨:viridisとjetカラーマップ比較
データ可視化において、カラーマップの選定は非常に重要です。jetのような古典的な虹色カラーマップは、色の変化が知覚的に均一でないため、データの大小関係を誤解してしまう可能性があります。例えば、途中の特定の色が実際よりも強調されて見えたり、逆に変化が分かりにくくなったりすることがあり、これは「知覚的な変化が等しくない」ことを意味します。このため、一般的にjet cmap は避けるべきとされています。
一方、viridisは「知覚的に均一な(Perceptually Uniform)」カラーマップと呼ばれ、色の変化が数値の増減と釣り合っているため、データが正しく伝わります。また、色覚多様性を持つ方にも配慮されており、すべての人にとって情報が分かりやすいという利点があります。このため、Matplotlib viridisは色覚バリアフリーグラフを作成する上で強く推奨されるカラーマップです。同じデータでこのカラーマップ比較の効果を見てみましょう。
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
# viridis カラーマップ
sc1 = axes[0].scatter(x, y, c=val, cmap=cm.viridis, norm=norm, s=60, alpha=0.8)
axes[0].set_title("viridis (推奨)")
plt.colorbar(sc1, ax=axes[0], label="正規化された値 (0-1)")
# jet カラーマップ
sc2 = axes[1].scatter(x, y, c=val, cmap=cm.jet, norm=norm, s=60, alpha=0.8)
axes[1].set_title("jet (非推奨)")
plt.colorbar(sc2, ax=axes[1], label="正規化された値 (0-1)")
plt.tight_layout()
plt.show()
3. 特殊なデータ分布への対応:LogNormとTwoSlopeNorm
データ可視化において、データ分布には様々な形があり、ただ均等に色を割り当てるだけでは、データの特徴が見えにくくなることがあります。
例えば、
- 値の範囲が極端に広い場合:ごく小さな値から非常に大きな値までが混在しているとき。
- 特定の値にデータが集中している場合:多くのデータがある範囲に固まっていて、外れ値が少しだけ離れているとき。
- ゼロを基準に正負に広がる場合:増減や偏差のように、プラスの値とマイナスの値が混在していて、ゼロが意味を持つ基準点であるとき。
このような特別なデータ分布の場合には、Matplotlibの配色スケーリング方法を工夫することで、よりデータの変化を効果的な配色で表現し、見る人に正確な情報と深い洞察を提供できます。それがLogNormやTwoSlopeNormといった特別なNormalizeの出番です。
3.1. 対数スケールで表現:Matplotlib LogNormの活用
データ可視化においては、ごく小さな値から非常に大きな値まで、桁違いに幅広い範囲に分布しているデータ(例えば、地震のマグニチュードや、ある現象の発生頻度など)がしばしば存在します。このようなデータを通常の(線形の)スケールで配色しようとすると、小さな値の変化はほとんど見えず、大きな値ばかりが強調されてしまいます。
そこで役立つのがLogNorm(対数正規化)です。Matplotlib LogNormは、データの値を直接色に変換するのではなく、一度「対数」という尺度に変換してから色を割り当てます。対数に変換すると、値が10倍、100倍、1000倍と大きく変化しても、スケール上では同じ間隔として扱われるため、小さい値の微妙な変化も、大きな値の変化も、どちらも平等に色の違いとして表現できるようになります。
例えるなら、0〜1000の範囲で、0〜10と900〜1000の変化を、同じ色のグラデーションの幅で表示できるようになるイメージです。これにより、データ全体の傾向や隠れたパターンを見つけやすくなり、効果的な配色を実現します。
import numpy as np
import matplotlib.pyplot as plt
!pip install japanize-matplotlib > /dev/null # Google Colab の機能を使って日本語フォントをインストール・インポート
import japanize_matplotlib
from matplotlib import colors
# 0に近い値〜大きな値までを同じ図で見たい
z = np.random.lognormal(mean=0.0, sigma=1.0, size=(60, 90))
fig, ax = plt.subplots()
im = ax.imshow(z, cmap="magma", norm=colors.LogNorm(vmin=max(z.min(), 1e-3), vmax=z.max()))
plt.colorbar(im, ax=ax, label="対数スケール値") # より詳細な日本語ラベルに変更
ax.set_title("LogNorm(対数スケール)")
plt.show()
3.2. ゼロ中心の配色:Matplotlib TwoSlopeNorm
データの値が、増減や偏差のようにゼロを基準にプラス(正)とマイナス(負)の両方に広がる場合、TwoSlopeNorm(vmin, vcenter, vmax)が非常に便利です。例えば、平均からの「差」や、基準年からの「変化率」などをデータ可視化する際に役立ちます。この機能により、Matplotlib TwoSlopeNormは、効果的な配色を可能にします。
通常のカラーマップでは、最小値から最大値までを一律にグラデーションで表現するため、ゼロ点が必ずしも明確に表現されるとは限りません。しかし、TwoSlopeNormを使うと、vcenter引数で「中央となる値」を指定できるため、この中央値を色のグラデーションの基準点(例えば、中立的な白や灰色)として明確に設定できます。
これにより、
- ゼロからの変化: プラス方向の変化とマイナス方向の変化が、異なる色合い(例:暖色系と寒色系)で視覚的に区別しやすくなります。
- 変化の度合い: ゼロから離れるほど色が濃くなるように設定することで、変化の大小が一目で理解できるようになります。
このように、TwoSlopeNormは、ゼロを中心としたデータ分布の特性を、より直感的かつ効果的な配色で伝えるための強力なツールです。
import numpy as np
import matplotlib.pyplot as plt
!pip install japanize-matplotlib > /dev/null # Google Colab の機能を使って日本語フォントをインストール・インポート
import japanize_matplotlib
from matplotlib import colors
x = np.linspace(-3, 3, 200)
y = np.linspace(-3, 3, 200)
X, Y = np.meshgrid(x, y)
Z = X + np.sin(Y) # 正負が混在するデータ
norm = colors.TwoSlopeNorm(vmin=Z.min(), vcenter=0.0, vmax=Z.max())
fig, ax = plt.subplots()
im = ax.imshow(Z, cmap="coolwarm", norm=norm, origin="lower")
plt.colorbar(im, ax=ax, label="ゼロからの偏差") # より詳細な日本語ラベルに変更
ax.set_title("TwoSlopeNorm(ゼロ中心の配色)")
plt.show()
4. カラーバーの正しい使い方:データ可視化における色の凡例
Matplotlibグラフに色を使ってデータを表現する際、その「色が何を示しているのか」を説明するために欠かせないのがカラーバーです。カラーバーは、色のグラデーションがどの数値範囲に対応しているかを示し、データ可視化の情報を正しく読み取るための「凡例」のような役割を果たします。
Matplotlibでカラーバーを追加するには、plt.colorbar()関数を使います。この関数には、imshowやscatterといった色付けされたプロットの戻り値(これをScalarMappableと呼びます。つまり、色の情報を持つオブジェクトのことです)を渡します。これによって、カラーバーがどの色の情報に対応しているかをMatplotlibが理解し、適切に表示してくれます。
また、カラーバーの位置、サイズ、目盛りのラベルなども、オプション引数を設定することで細かく調整できます。このカラーバーの使い方を習得することで、伝わるグラフ作成に大きく貢献します。
import numpy as np
import matplotlib.pyplot as plt
!pip install japanize-matplotlib > /dev/null # Google Colab の機能を使って日本語フォントをインストール・インポート
import japanize_matplotlib
from matplotlib import cm, colors
x = np.random.rand(100); y = np.random.rand(100); v = x**2 + y**2
norm = colors.Normalize(vmin=0, vmax=2); cmap = cm.plasma
fig, ax = plt.subplots(figsize=(5.5, 4))
sc = ax.scatter(x, y, c=v, cmap=cmap, norm=norm)
ax.set_title("colorbarの基本")
# 右側に縦で配置(既定)
cbar = plt.colorbar(sc, ax=ax) # orientation="vertical" が既定
cbar.set_label("値の強度") # より詳細な日本語ラベルに変更
# 下部に横で配置する例:
# cbar = plt.colorbar(sc, ax=ax, orientation="horizontal", pad=0.12, fraction=0.05, aspect=30)
plt.tight_layout()
plt.show()
5. グラフ色識別の強化:ハッチとマーカーでカテゴリを分ける
Matplotlibグラフで複数のカテゴリ(商品の種類、地域、アンケートの回答など)を表現する際、色は基本的なデータ可視化の手法です。しかし、色だけではカテゴリの数が多くなると区別が難しくなったり、色覚バリアフリーの観点から特定の色の組み合わせが見分けにくいといった課題が生じることがあります。
これらのグラフ色識別の課題を解決し、すべての人がグラフの情報を正確に読み取れるようにするためには、色だけに頼らず、他の視覚的な要素と組み合わせることが非常に有効です。
例えば、棒グラフではハッチ(模様:
種類はこちら)を、散布図ではマーカーの形(marker="o","s","^"など:
種類はこちら
)を、線グラフでは線種(実線 -、点線 --、破線 :など:
種類はこちら )を併用することで、カテゴリの識別性を大幅に向上させることができます。これにより、色が区別しにくい状況でも、別の情報で各カテゴリを識別できるようになり、より堅牢で分かりやすいMatplotlibグラフを作成できます。
import matplotlib.pyplot as plt
!pip install japanize-matplotlib > /dev/null # Google Colab の機能を使って日本語フォントをインストール・インポート
import japanize_matplotlib
import numpy as np
labels = ["A","B","C","D"]
values = [5, 7, 3, 6]
colors = ["tab:blue","tab:orange","tab:green","tab:red"]
hatches = ["", "//", "\\", "xx"] # 模様
fig, ax = plt.subplots()
bars = ax.bar(labels, values, color=colors)
for bar, h in zip(bars, hatches):
bar.set_hatch(h)
ax.set_title("色とハッチで識別性を高める")
plt.show()
6. 色覚バリアフリー対応のグラフ:アクセシブル データ可視化の基本
グラフを作成する際には、すべての人にとって情報が分かりやすいように「色覚バリアフリー」の視点を取り入れることが重要です。色覚の多様性を持つ方も含め、誰もがグラフから正しい情報を読み取れるようにするためのポイントを解説します。
- 推奨カラーマップの利用:
viridis、plasma、cividisといったカラーマップは、色の変化が知覚的に均一で、かつ色覚多様性を持つ方にも配慮されています。これにより、色の濃淡がデータの大小関係を正確に伝えることができます。
- 避けるべきカラーマップ:
jetのような古典的な虹色のカラーマップは、特定の色が強調されて見えたり、色の変化が均一に感じられなかったりするため、データの誤解を招きやすいです。また、色覚多様性を持つ方には特に区別が難しい色の組み合わせが含まれることがあります。
- 情報の重複表現: 色だけに頼らず、形(マーカーの種類)、線種(実線、点線など)、ハッチ(模様)など、複数の視覚要素を組み合わせて情報を伝達しましょう。これにより、色が区別しにくい場合でも、別の方法で情報を識別できるようになります。
- 十分なコントラスト: 背景色とグラフの要素(線、棒、テキストなど)の間には、十分な明度差(明るさの差)を確保しましょう。色が似ていて見分けがつきにくいと、情報が伝わりにくくなります。
- グレースケールでの検証: グラフが白黒印刷されたり、グレースケールで表示されたりする場合でも、情報が正しく伝わるかを確認しましょう。濃淡だけでデータの区別ができるかを確認することで、どのような環境でも情報が失われない堅牢なグラフになります。
7. Matplotlibカラーマップの応用例:ヒストグラムと複数グラフ
カラーマップは単一のプロットだけでなく、複数のプロットや異なる視覚化タイプにわたってデータを効果的に表現するために利用できます。
7.1. ヒストグラムへのカラーマップ適用
ヒストグラムの各棒にカラーマップを適用することで、頻度や他の数値に基づいて色のグラデーションを表現できます。これは、データの分布に追加の情報を視覚的に統合するのに役立ちます。例えば、plt.histのweightsやc引数を利用して、各ビンに色を割り当てることが可能です。cmapとnormを組み合わせることで、色の範囲を正確に制御できます。
import numpy as np
import matplotlib.pyplot as plt
!pip install japanize-matplotlib > /dev/null # Google Colab の機能を使って日本語フォントをインストール・インポート
import japanize_matplotlib
from matplotlib import cm, colors
np.random.seed(42)
data = np.random.randn(1000) * 10 + 20 # 平均20、標準偏差10の正規分布データ
fig, ax = plt.subplots(figsize=(8, 5))
# ヒストグラムの計算
n, bins, patches = ax.hist(data, bins=20, density=True)
# Normalizeを作成(ここでは頻度に基づいて色付けする)
norm = colors.Normalize(bins.min(), bins.max())
cmap = cm.viridis
# 各棒に色を適用
for patch, x_val in zip(patches, bins):
color = cmap(norm(x_val))
patch.set_facecolor(color)
ax.set_title("ヒストグラムへのカラーマップ適用")
ax.set_xlabel("値")
ax.set_ylabel("密度")
cbar = fig.colorbar(cm.ScalarMappable(norm=norm, cmap=cmap), ax=ax)
cbar.set_label("ビン範囲の始点")
plt.tight_layout()
plt.show()
7.2. 複数グラフでの一貫したカラーマップ適用
複数のサブプロットや異なる種類のグラフ(例:散布図とヒートマップ)で同じデータセットや関連するデータを可視化する際、カラーマップの一貫性を保つことは比較を容易にし、誤解を防ぎます。
- 同じ
cmapとnormオブジェクトを共有する:cmapとnormのインスタンスを一度作成し、それを複数のプロット関数に渡すことで、視覚的な一貫性を保証できます。 vmin,vmaxを明示的に指定する:Normalizeを使用する場合、すべてのプロットで同じvminとvmaxを設定することで、カラーバーの範囲が一致し、色の解釈が統一されます。
# 複数グラフでの一貫したカラーマップ適用例
import numpy as np
import matplotlib.pyplot as plt
!pip install japanize-matplotlib > /dev/null # Google Colab の機能を使って日本語フォントをインストール・インポート
import japanize_matplotlib
from matplotlib import cm, colors
np.random.seed(1)
x_multi = np.random.rand(50)
y_multi = np.random.rand(50)
z_multi = x_multi * y_multi + np.random.rand(50) * 0.1
# 同じnormとcmapを定義
shared_norm = colors.Normalize(vmin=0, vmax=1)
shared_cmap = cm.plasma
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
# 1つ目のサブプロット:散布図
sc1 = axes[0].scatter(x_multi, y_multi, c=z_multi, cmap=shared_cmap, norm=shared_norm, s=100, alpha=0.8)
axes[0].set_title("散布図 (一貫したCMAP)")
fig.colorbar(sc1, ax=axes[0], label="値")
# 2つ目のサブプロット:別のデータだが同じカラーレンジで表示
matrix_data = np.random.rand(10, 10)
# ここではmatrix_dataの範囲が0-1なので、shared_normがそのまま使える
im = axes[1].imshow(matrix_data, cmap=shared_cmap, norm=shared_norm, origin="lower")
axes[1].set_title("ヒートマップ (一貫したCMAP)")
fig.colorbar(im, ax=axes[1], label="値")
plt.tight_layout()
plt.show()
このように、Normalizeとcmapオブジェクトを適切に管理することで、複雑な可視化でもデータの比較可能性と理解度を大幅に向上させることができます。
まとめ:Matplotlib配色とカラーマップで伝わるグラフへ
- 連続値の配色:データの数値の範囲を
Normalizeで固定することで、グラフ間の比較がしやすくなり、常に同じ値が同じ色で表現されるため、再現性の高いグラフが作成できます。 - LogNorm/TwoSlopeNorm:データの分布が極端に広かったり(
LogNorm)、ゼロを基準に正負に広がっている場合(TwoSlopeNorm)には、これらの特別な正規化を使うことで、データの特徴をより効果的に可視化できます。 - カラーバーの正しい使い方:
plt.colorbar()には、色情報を持つオブジェクト(ScalarMappable)を渡すことで、色が何を示しているかを明確にできます。また、位置やラベルの調整も重要です。 - カテゴリの識別:複数のカテゴリがある場合、色だけに頼らず、ハッチ(模様)、マーカーの形、線種などを組み合わせることで、グラフの識別性を大幅に向上させ、色覚多様性にも配慮できます。
- 色覚配慮のカラーマップ:
viridisのような知覚的に均一なカラーマップを基本にすることで、すべての人にとって分かりやすく、データが誤解なく伝わるグラフを作成できます。
コメント