matplotlibで日本語

matplotlibで日本語を扱う場合の問題点をまとめてみます。

1. matplotlibでは既定のフォントが DejaVu Serif になっており、日本語は豆腐になってしまう。英語フォントの足りない部分を日本語フォントにリンクする機能がないので、日本語を表示しようと思ったら、日本語フォントを指定する必要があります。

2. ~~日本語用フォントの殆どがttcフォントファイルであるが、matplotlibではttcフォントファイルに対応していない。例えば、Windowsの場合だと、MSゴシック、MS明朝、メイリオ、游ゴシックというよく使われているフォントがttcである。~~ ver 3.1.0 から、ttcフォントファイルに対応したので PC だと新しくフォントをインストールする必要はなくなりました。ただし、次の問題は残っています。(2019/4/29 5/19 修正、以下についても大幅に修正しています。)

- TTCファイルには複数のフォントを含めることができるが、そのコレクションの最初のフォントだけをサポートしている。
- pdf や ps のフォント埋め込みには対応していない。
- フォントの weight を正しく取得できていない場合があって、予期していない太さのフォントが表示される場合がある。

以下、対応方法を自分のメモ書きを兼ねて書いておきます。

## 1. フォントを準備する
~~matplotlibは、現時点ではttfフォントファイルとotfフォントファイルに対応しています。~~利用可能なフォントの一覧は以下で表示できます。

```shell
python3
>>> import matplotlib.font_manager as fm
>>> fm.findSystemFonts()
```
また、フォントリストのキャシュファイルが、ホームディレクトリ−の Mac と Windows では `.matplotlib`に、Linux では`.cache/matplotlib`に、`fontlist-v310.json`というようにバージョンを付けた名前で作成されます。そこには、利用可能なフォントの一覧があって、フォント名 (name) の項目もあるので、設定のときにはその名前を使うといいです。なお、フォントリストがキャッシュされているので、新しくフォントをインストールした時は、新しいフォントを認識させるためにはそのキャッシュファイルを削除してやる必要があります。

### 利用しやすいフォント
最初に書いたように現状で問題が残っているので、各OSを利用しやすいフォントの例を以下に示しておきます。例えば、昨年の秋から Windows10 に標準で搭載されている BIZ UD フォントはコレクションの最初のフォントが BIZ UDGothic なので等幅フォントとしてしか使えないので外しています。詳しくは、[Matplotlib が PC で追加のフォントをインストールしなくても日本語を表示できるようになった](https://qiita.com/yniji/items/2f0fbe0a52e3e067c23c)の方をみてください。

- Windows  
  - ゴシック系 (sans-serif) - 遊ゴシック (Yu Gothic)、メイリョウ (Meirio)
  - 明朝系(serif) - 遊明朝 (Yu Mincho)
- Mac  
  - ゴシック系 (sans-serif) - ヒラギノ丸ゴシック (Hiragino Maru Gothic Pro)
  - 明朝系(serif) - ヒラギノ明朝 ProN ('Hiragino Mincho ProN')  
- Ubuntu  
  - ゴシック系 (sans-serif) - Noto Sans CJK JP ('Noto Sans CJK JP')、TakaoGothic ('TakaoGothic')
  - 明朝系(serif) - Noto Serif CJK JP ('Noto Serif CJK JP')、TakaoPMincho ('TakaoPMincho')  
  ※ ( ) 内が matplotlib で使う場合のフォント名
  
なお、Ubuntu のサーバー版では、フォントがデフォルトではインストールされていないので、apt でインストールします。

```bash
# Ubuntu-18.04 の場合
sudo apt install fonts-noto-cjk
# Ubuntu-16.04 の場合
sudo apt install fonts-takao-pgothic fonts-takao-mincho
```

なお、matplotlib が ver3.1.0 よりも前のバージョンであれば、次のどちらかのフォントをダウンロードしてインストールすればいいでしょう。

+ [Noto Sans CJK JP、Noto Serif CJK JP](https://www.google.com/get/noto/)
+ [IPAexゴシック、IPAex明朝](http://ipafont.ipa.go.jp/node26)

フォントのインストール方法としては、それぞれのOSの通常のフォントのインストール方法でインストールします。

Windows 10の場合、インストールは、「コントロールパネル」→「デスクトップのカスタマイズ」→「フォント」で、フォントのコントロールパネルを表示して、そこに解凍したフォントをドラッグドロップすればいいです。

Ubuntu-18.04のデスクトップ版では、Notoフォントがデフォルトでインストールされていますが、ttcフォントファイルです。Ubuntu 16.04 の場合には、デフォルトがTakaoフォントでそれが ttf フォントファイルなのでそれを使います。Ubuntu 18.04 の場合もTakaoフォントを使えばいいです。もし、インストールできていなければ、`sudo apt install fonts-takao-pgothic fonts-takao-mincho`でインストールできます。

なお、フォントをmatplotlib専用としてmatplotlibのインストールディレクトリーにあるfontsディレクトリにインストールすることも可能ですが、matplotlibをバージョンアップすると消える可能性があることと、仮想環境を使っている場合は仮想環境毎にインストールする必要があることが欠点です。ただし、特定の仮想環境のみで使用したい場合には便利です。

## 2. 日本語フォントを使う設定をする
やり方は以下の3つ

+ 個別にフォントの設定をする
+ スクリプトの最初でフォント変更の宣言をする
+ 設定ファイルmatplotlibrcを修正して既定のフォントを変更する

それぞれメリット、デメリットがあるので、個別の案件で適当な方法を使ってください。

### 個別にフォントの設定をする
matplotlibでは、タイトルやラベルを描く毎にフォントを設定することができます。

```py
igfont = {'family':'IPAexGothic'}
plt.title('title',**igfont)
plt.show()
```
[本家マニュアル](https://matplotlib.org/gallery/api/font_file.html)

### スクリプトの最初でフォント変更の宣言

以下のようにスクリプトの最初でフォント変更の宣言をすることで可能です。

```py
from matplotlib import rcParams
rcParams['font.family'] = 'sans-serif'
rcParams['font.sans-serif'] = ['Hiragino Maru Gothic Pro', 'Yu Gothic', 'Meirio', 'Takao', 'IPAexGothic', 'IPAPGothic', 'VL PGothic', 'Noto Sans CJK JP']
```
[本家マニュアル](https://matplotlib.org/gallery/api/font_family_rc_sgskip.html)

### matplotlibrcを修正する
既定のフォントファミリーは'sans-serif'、'sans-serif'の既定のフォントは`DejaVu Sans`に設定されています。それを日本語が表示できるフォントに変更するようにします。
[本家マニュアル](https://matplotlib.org/users/customizing.html)
#### Windows10の場合
matplotlibrcがどこにあるかは、以下のコードで調べることができます。

```python
>>> import matplotlib as mpl
>>> mpl.matplotlib_fname()
'D:\\projects\\pyeprog\\env\\Lib\\site-packages\\matplotlib\\mpl-data\\matplotlibrc'
```
そのファイルを直接修正することも、ホームディレクトリー（C:\Users\\(ユーザー名)）の.matplotlib ディレクトリーにコピーして修正することも可能です。matplotlibrcが両方にある場合は、ホームディレクトリーの.matplotlib ディレクトリーにある方が優先されます。コピーした場合は、`mpl.matplotlib_fname()`を再度実行して`matplotlibrc`の場所が変更されているか確認しておきます。

修正は、FONTセクションで以下のように、font.sans-serifの先頭に日本語フォント（以下の場合は Noto Serif CJK JP） を追加します。

```
font.serif      : Noto Serif CJK JP, DejaVu Serif, Bitstream Vera Serif, New Century Schoolbook, Century Schoolbook L, Utopia, ITC Bookman, Bookman, Nimbus Roman No9 L, Times New Roman, Times, Palatino, Charter, serif
font.sans-serif : Noto Sans CJK JP, DejaVu Sans, Bitstream Vera Sans, Lucida Grande, Verdana, Geneva, Lucid, Arial, Helvetica, Avant Garde, sans-serif
```
#### Ubuntu 16.04の場合
linuxでもmatplotlibrcがどこにあるかは、同じようにして調べることができます。

```python
python
>>> import matplotlib as mpl
>>> mpl.matplotlib_fname()
'/home/niji/opt/gfsmap/.venv/lib/python3.6/site-packages/matplotlib/mpl-data/matplotlibrc'
```

そのファイルを直接修正することも、`~/.config/matplotlib`ディレクトリーにコピーして修正することも可能です。コピーした場合は、`mpl.matplotlib_fname()`を再度実行して`matplotlibrc`の場所が変更されているか確認しておきます。

サーバー版ではTkがインストールされていないので、そのそもの問題としてデフォルトのままでグラフを表示させようとするとエラーになります。その場合は matplotlibrc の以下の記述をコメントアウトします。

```
backend      : TkAgg
```

既定のフォントの修正は、FONTセクションで以下のように、font.sans-serifの先頭に日本語フォント（以下の場合は TakaoPGothic） を追加します。

```
font.serif      : TakaoPMincho, DejaVu Serif, Bitstream Vera Serif, New Century Schoolbook, Century Schoolbook L, Utopia, ITC Bookman, Bookman, Nimbus Roman No9 L, Times New Roman, Times, Palatino, Charter, serif
font.sans-serif : TakaoPGothic, DejaVu Sans, Bitstream Vera Sans, Lucida Grande, Verdana, Geneva, Lucid, Arial, Helvetica, Avant Garde, sans-serif
```

## 3. キャッシュの削除

フォントを追加したり設定を変更したのにうまく反映されない場合には、キャッシュが影響している場合があります。キャシュファイルは、Windowsの場合はホームディレクトリーの`.matplotlib`ディレクトリーに、Linuxの場合には'~/.cache/matplotlib'ディレクトリーにデフォルトでは作成されています。それを削除してから実行してみてください。キャシュファイルは、再生されるので削除しても問題ありません。

また、以下のPythonスクリプトを実行させてキャッシュを再構築するのも方法です。

```python
matplotlib.font_manager._rebuild()
```