【matplotlib】グラフの正負によってグラデーションの色を変えたい【python】

この記事を見てたらプラス側とマイナス側で色を変えるというおしゃれなグラデーションをやっていたのでこれを勉強しておきたくなった。


stackoverflow.com

 

大雑把な解説はこちらを参照ください。

chemstat.hatenablog.com

 

まずはコード全体。

import numpy as np
import matplotlib.pyplot as plt

np.random.seed(1)
x = np.linspace(0, 10, 200)
y = np.random.normal(0.01, 1, 200).cumsum()
               
fig, ax = plt.subplots(figsize=(12, 5))

ax.plot(x, y,color="black")

# 現在のy軸の範囲を取得
ylim = ax.get_ylim()

# 赤いグラデーションをプロットに追加
grad1 = ax.imshow(np.linspace(0, 1, 256).reshape(-1, 1),
                  cmap='OrRd',
                  vmin=-0.5,
                  aspect='auto',
                  extent=[x.min(), x.max(), 0, y.max()],
                  origin='lower')


# 青いグラデーションをプロットに追加
grad2 = ax.imshow(np.linspace(0, 1, 256).reshape(-1, 1),
                  cmap='PuBu',
                  vmin=-0.5,
                  aspect='auto',
                  extent=[x.min(), x.max(), y.min(), 0],
                  origin='upper')

#グラデーションを適用する領域を定義
poly_pos = ax.fill_between(x, y.min(), y, alpha=0.1)
poly_neg = ax.fill_between(x, y, y.max(), alpha=0.1)

# グラデーションを適用
grad1.set_clip_path(poly_pos.get_paths()[0], transform=ax.transData)
grad2.set_clip_path(poly_neg.get_paths()[0], transform=ax.transData)

# 不要になった塗りつぶし部分を削除
poly_pos.remove()
poly_neg.remove()

# y=0に黒い水平線を描画(基準線)
ax.axhline(0, color='black')

# y軸の範囲を元に戻す
ax.set_ylim(ylim)

# プロットを表示
plt.show()

 

グラデーションを貼り付ける

# 赤いグラデーションをプロットに追加
grad1 = ax.imshow(np.linspace(0, 1, 256).reshape(-1, 1),
                  cmap='OrRd',
                  vmin=-0.5,
                  aspect='auto',
                  extent=[x.min(), x.max(), 0, y.max()],
                  origin='lower')


# 青いグラデーションをプロットに追加
grad2 = ax.imshow(np.linspace(0, 1, 256).reshape(-1, 1),
                  cmap='PuBu',
                  vmin=-0.5,
                  aspect='auto',
                  extent=[x.min(), x.max(), y.min(), 0],
                  origin='upper')

 

グラデーションの領域を限定する

# yの値が正の場合にグラデーションを適用する領域を定義
poly_pos = ax.fill_between(x, y.min(), y, alpha=0.1)
poly_neg = ax.fill_between(x, y, y.max(), alpha=0.1)

# 正の領域にのみ青いグラデーションを適用
grad1.set_clip_path(poly_pos.get_paths()[0], transform=ax.transData)
grad2.set_clip_path(poly_neg.get_paths()[0], transform=ax.transData)

 

不要な部分を取り除く

# 不要になった塗りつぶし部分を削除
poly_pos.remove()
poly_neg.remove()


という事で完成しました。自由にグラデーションを割り付けられるのでデザインの自由度が広がっていいですね。

ちなみにコードの解説をChatGPTに解説してもらってるのですが、理解がはかどって素晴らしいです。

参考サイト

python - Gradient fill from zero till a curve - Stack Overflow