はじめに
普段業務ではWindows PCを用いていますが、演算はLinuxサーバーで実行することが多く、その際に日本語が入ったグラフをmatplotlibで可視化しようとしたときに文字化けしてしまいました。
通常、Windowsのように日本語のフォントが環境にインストールされているのであれば plt.rcParams["font.family"] = "日本語のフォント名称"
とすることでこの文字化けは解消できるのですが、日本語のフォントがインストールされていない(or むやみにインストールしてはいけない)環境では、この方法では解決できません。
よって当該記事では、日本語フォントがインストールされていないLinux環境のmatplotlibにおける日本語の文字化けの治し方について、備忘として残します。
結論
端的に言うと、次の3点を実施することで日本語の文字化けが解消できます。
- フォントファイルをダウンロードする
- フォントファイルのパスを
fontManager.addfont()
する -
plt.rcParams["font.family"]
にFontProperties().get_name()
でフォントの名称を渡す
以下、手順など詳細を記載します。
手順
1. フォントファイルをダウンロードする
今回は、フリーのフォントが色々提供されている Google Fonts (https://fonts.google.com/) から好きなフォントをダウンロードします。
例えばWindows環境で用いるような"Meiryo"相当であれば、フォントは王道の"Noto Sans Japanese"あたりが良いかと思います(今回の例では個人的な好みにより、等幅フォントの"BIZ UDGothic"を用います)。
ダウンロード手順は以下です。
- https://fonts.google.com/ にアクセス
- 検索窓にフォント名称を記載(今回は"BIZ UDGothic")
- "Get font" をクリック
- "Download all" をクリック
- .zipファイルがダウンロードされるので展開しておく
ダウンロードが完了したら、.zipから展開したフォルダを文字化けを解消したい環境に移動させましょう。
例えば、あるLinuxサーバーを複数人で使用することを想定すると、homeの階層(~/
)にfonts/
といったフォルダを作り、そこに展開したフォルダを入れておくと他の人も使えるので良いでしょう。
2. フォントファイルのパスをfontManager.addfont()
する
3. plt.rcParams["font.family"]
にFontProperties().get_name()
でフォントの名称を渡す
ここからはPythonのコードの説明に移りますが、コード量少ないので、2つの章をここで消化します。
今回の検証環境は、
- Windows 11 Home 64 bit(10.0,ビルド26100)・・・・PC自体
- WSL2 (Ubuntu-24.04)・・・・Linuxサーバーに見立てて使用
- miniconda3・・・・condaの仮想環境を使用
- python3.12.9・・・・conda create時に新しめのバージョン指定
としています。
また、下記コードは.ipynbで実行されることを想定しています。
まずは使用するライブラリをインポートします。
fontManager
, FontProperties
はフォント設定で使います。
import datetime
import gc
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from matplotlib.font_manager import fontManager, FontProperties
次に、テキトーにデータを作って、フォントが適用されているかどうかを確認するための可視化の関数を作っておきます。
def plot_example():
df: pd.DataFrame = (
pd.date_range(
start=datetime.datetime(2025,1,1,0,0,0),
end=datetime.datetime(2025,1,8,0,0,0),
freq="1s",
inclusive="left",
)
.to_frame(index=False, name="date_time")
.assign(
time_id=lambda d: d.index,
x_axis=lambda d: 0.2*np.sin(2*np.pi*d["time_id"]*1e-5),
y_axis=lambda d: 0.3*np.cos(2*np.pi*d["time_id"]*2e-5),
)
)
fig = plt.figure(figsize=(8, 8*9/16), facecolor="white", dpi=100)
ax = fig.add_subplot(1, 1, 1)
ax.plot(df["time_id"], df["x_axis"], label="X軸")
ax.plot(df["time_id"], df["y_axis"], label="Y軸")
ax.grid(color="gray", linestyle="--")
ax.legend(loc="upper right")
ax.set_ylabel("振幅[m]")
plt.show()
plt.clf()
plt.close()
gc.collect()
まだフォント設定とかは何もしていませんが、現状どうなるかグラフ描画して確認してみましょう。
print(f'font.family = {plt.rcParams["font.family"]}')
plot_example()
font.familyは["sans-serif"]となっており、赤丸で強調したところのように、"軸"と"振幅"がどちらも文字化けし、通称:豆腐("□")になっていますね。
画像では見切れていますが、エラー文の右側を見ると、UserWarning: Glyph 25391 (\N{CJK UNIFIED IDEOGRAPH-632F}) missing from font(s) DejaVu Sans.
と記載されており、規定値の"DejaVu Sans"が用いられているようです。
そこで、先ほどダウンロードして環境に持ってきたフォントファイルを参照し、matplotlibの設定値を以下のように変更します。
path_font = Path("../../.fonts/BIZ_UDGothic/BIZUDGothic-Regular.ttf")
assert path_font.exists(), f"{path_font.resolve()} のファイルは見つかりません。"
fontManager.addfont(path_font)
plt.rcParams["font.family"] = (
FontProperties(fname=str(path_font))
.get_name()
)
それでは、もう一度描画してみましょう。
print(f'font.family = {plt.rcParams["font.family"]}')
plot_example()
先ほど豆腐だった日本語が文字化けせず表示されるようになりました。
補足
もし上記手順で上手くいかなかった場合は、以下をお試しください。
-
rm ~/.cache/matplotlib/
でキャッシュを削除 - .ipynbであればカーネルを再起動して実行