💡

Matplotlibでダークモード対応の図をいい感じに作る

commits2 min read

Matplotlibの表示要素に白色のボーダーを追加することで、同一の画像ファイルでライトモード(白背景)とダークモード(黒背景)の両方で見やすい表示となる作図方法をまとめました。以下の例のように、図の背景を透明にしても線やテキストが黒背景に埋もれず、そこそこ見やすい形で両立できるようになります。

darkmode-compatible-figure-light.png darkmode-compatible-figure-dark.png
ライトモード(白背景)での表示 ダークモード(黒背景)での表示

Zennの制限によりHTMLを使って背景色を変えられないため、上の例は画像自体に黒背景を描画しています。実際に背景色に応じて表示が変わる様子はこちらをご覧ください。

Path effects

表示要素(artists)にボーダーを追加するにはpath effects(matplotlib.patheffects)を使用します。名前から分かるように、ボーダーを追加できるのはテキストやラインプロットなど線(パス)を持つ要素のみとなります。今回の場合、withStroke()でボーダーの線の色と線幅を設定したpath effectオブジェクトを作成します。

要素にボーダーを追加する設定
import matplotlib as plt
from matplotlib.patheffects import withStroke


border = withStroke(linewidth=3, foreground="white")

Examples

ボーダーを追加するには、作成したpath effectオブジェクトを(1)rcParamsでグローバルに設定するか、(2)プロット関連の関数やメソッドが持つpath_effectsオプションで個別に設定するか、(3)表示要素が持つset_path_effects()メソッドで個別に設定します。以下では(1)の例を紹介します。

全ての要素にボーダーを追加する場合
with plt.rc_context({"path.effects": [border]}):
    plt.plot([1, 2, 1, 3], label="A")
    plt.plot([2, 1, 3, 2], label="B")
    plt.title("Darkmode-compatible figure")
    plt.legend()

plt.savefig("figure.png", transparent=True)

rcParamsの"path.effects"は複数の設定を受け取るため、[border]のように配列で渡します

rc_context()を使うと、withブロックに書かれた要素のみにボーダーを適用することができます

上の例では図(画像)の外周にもボーダーが追加されてしまうため若干見づらいかもしれません。少し複雑になりますが、以下のように書くことで外周のボーダーを消すことができます。

図の外周のみボーダーを追加しない場合(推奨?)
fig = plt.figure()

with plt.rc_context({"path.effects": [border]}):
    ax = fig.add_subplot()
    ax.plot([1, 2, 1, 3], label="A")
    ax.plot([2, 1, 3, 2], label="B")
    ax.set_title("Darkmode-compatible figure")
    ax.legend()

fig.savefig("figure.png", transparent=True)

References

https://matplotlib.org/stable/tutorials/advanced/patheffects_guide.html

https://matplotlib.org/stable/api/patheffects_api.html#matplotlib.patheffects.withStroke
GitHubで編集を提案

Discussion

ログインするとコメントできます