環境システム株式会社公式HP

〒660-0083 兵庫県尼崎市道意町7-1-3
尼崎リサーチ・インキュベーションセンター512

アイコン06-6657-5130

アイコンsales@hydrolab.co.jp

お問い合わせ

アイコン06-6657-5130

アイコンsales@hydrolab.co.jp

お問い合わせ

蛇使いな彼女BLOG

【第74回】 グラフ編#2 Seabornのスタイルを使う~グラフ文字化けでハマった時のお話~

2022.12.16

皆様こんにちは。
前回はmatplotlibrcとフォント設定をメインにお話しました。
今日はmatplotlibrcのfont.familyを'serif'に設定した状態からseabornのスタイルを使用するとどうなるか、その挙動を説明します。

seabornは美しい見た目のグラフを描くときに便利ですが、描画は基本的にmatplotlibの軸システムを使用しています。
当然フォントもmatplotlibrcの設定から適応されるのか?
seaborn側のシステムの確認もしながら、seabornスタイルを使用する2パターンの方法を【1】【2】で試してみます。

パターン【1】

使用するserifフォント群に関しては、私の場合利便性を考えて仲間外れですがリストにIPAexGothicを追加しています。
(matplotlibrcからフォント群をカスタマイズできます)

>>> plt.rcParams[ 'font.serif']
['DejaVu Serif', 'Bitstream Vera Serif', 'Computer Modern Roman', 'New Century Schoolbook', 'Century Schoolbook L', 'Utopia', 'ITC Bookman', 'Bookman', 'Nimbus Roman No9 L', 'Times New Roman', 'Times', 'Palatino', 'Charter', 'IPAexGothic', 'serif']>>


前回の基本の実行コードにplt.style.use()を追加してスタイルを変更した場合です。
matplotlib.style.useはseabornをインポートせずにスタイルだけを使用する際に便利です。が……

実行すると軸のスタイルがseabornのwhitegridに変化しましたが、フォントに関してはoutoput以下のように見事にエラー表記が出ます。
しかもフォントはTimes New Romanになっていません(笑)
ではなぜうまくフォントが変更されないのでしょうか?

※、℃、▽は文字化けしてしまいました。(ちなみに日本語も文字化け起こします)

実行したコードからフォントを確認するとセリフが何故かサンセリフに変わっていました。エエ!!

その後何回か検証してみましたが、
●plt.style.use('seaborn-whitegrid') 
この1行でmatplotlibからseabornのスタイルを呼び出したときに、それ以前のmatplotlibのフォント設定がseabornによって上書きされているのか、もしかしたらmatplotlibの設定が初期値に戻ったのか、どちらかじゃないかな~?予想しました。

そこでこの原因を確認する方法として、seaborn 側の設定を見直しました。
seabornパッケージ内のrcmod.pyにはseabornのスタイルやテーマに関するデフォルト値が以下のように指定されており、このフォント部分を変更することで文字化けの改善を試みました。

【変更前】
def set_theme(context="notebook", style="darkgrid", palette="deep",
font="sans-serif", font_scale=1, color_codes=True, rc=None):
※sans-serifはmatplotlibとseabornのデフォルトフォント郡

【変更後】
def set_theme(context="notebook", style="darkgrid", palette="deep",
font=" serif ", font_scale=1, color_codes=True, rc=None):

【変更前】
def axes_style(style=None, rc=None):
"text.color": dark_gray,
"font.family": ["sans-serif"],
"font.sans-serif": ["Arial", "DejaVu Sans", "Liberation Sans", "Bitstream Vera Sans", "sans-serif"],

【変更後】
def axes_style(style=None, rc=None):
"text.color": dark_gray,
"font.family": ["serif "],
"font.serif": ["Times New Roman", "DejaVu Serif", "Times",
"Bitstream Vera Serif", "serif",'IPAexGothic'],

フォントリストまで(適当に)ガッツリ変更加えましたがrcParamsのフォントはsans-serif のままでした。
ということは、matplotlibの初期値に戻されるようですね(?)。
style.useを使う場合はコーディングの順番を考えないといけないようです。

パターン【2】

2つ目の方法として、sns.set_theme()を使ってスタイル変更する場合です。
sns.set_themeはseabornをインストールして使用します。rcmod.pyで変更したfont.familyはrcParamsやsns.set_theme のfont引数で指定がなかった場合に適応されます。
rcmod.py のaxes_style ()のfont.serifリストの変更はどこに影響しているのか今回はわかりませんでした。

上記コードの実行結果では軸のスタイル、フォントの表示も完璧です。
rcParams で指定したフォントは、sns.set_themeで新たにフォントを指定するとその値が上書きされます。
当たり前ですがmatplotlibで作成したグラフに関してfont.familyで指定したフォントは基本的に一括設定扱いになるので、表示フォントは1つしか選べませんが、一部分だけ別のフォントに置き換えることも可能です。
フォントに含まれていない記号や文字は文字化けを起こすので、こういった場合フォントの置き換えは有効です。
これについて詳しくは次回紹介します。

タイトル拡大↓

Times New Roman(フォントに無い記号)だと「▽」が「□」に文字化けします。
グラフ内に記号や注釈入れたいときに、こうなると歯がゆいですね..

今日のまとめ

matplotlibでseabornのテーマやスタイルを使う際はplt.style.use()ではなくsns.set_theme()の方がフォントが勝手にデフォルトに置き換わるトラブルもなく作業できるようでした。
そして、この方法ならaxesの軸を生成する過程でwith構文を使えば軸ごとにテーマ既定の設定をオーバーライドすることも可能だと公式ガイドラインに書いてありました。
構文例→)with sns.set_style({ 'xtick.bottom': True,'ytick.left': True}):

では今回はここまで。後半は年明けに続きます。

pagetop