matplotlibの日本語フォントについて（Macの場合）

# 結論
こうすれば良いはず。
もっと良いものや、考慮漏れがあれば追記します。

```python
# フォント設定
plt.rcParams['font.family'] = 'Hiragino Sans'
# 太さ設定
plt.rcParams['font.weight'] = 'bold'

"""
fig,ax = plt.subplots()
ax.plot()...
などのプロット
"""

# legend使うとき
#legend_properties = {'size':14,'weight':'bold'}
#ax.legend(prop=legend_properties)


# plt.draw()が無いとget_ticklabels()で帰ってくるtextが空文字になる
plt.draw()
# ticklabelのフォントはrc設定では変えられないっぽい
ax.set_xticklabels(ax.get_xticklabels(),fontsize=14,fontweight='bold')
ax.set_yticklabels(ax.get_yticklabels(),fontsize=14,fontweight='bold')

```


# 導入
```python
import matplotlib.font_manager
[f.name for f in matplotlib.font_manager.fontManager.ttflist]

# >['DejaVu Serif Display',
# 'STIXGeneral',
# ...]
```

となりますが、よくよく見てみると、同じ文字列が複数存在していることがわかります。
例えばMacの場合

```python
l = [f.name for f in matplotlib.font_manager.fontManager.ttflist]
l.count("Hiragino Sans")
#> 10
```

となります。何故10もあるのでしょうか。
それを知るために上のリスト内包表記でf.nameとしているころを、一旦fにして、fについて調べてみましょう。

```python
l = [f for f in matplotlib.font_manager.fontManager.ttflist]
type(l[0])
# > matplotlib.font_manager.FontEntry
```
となるので、この各項目はmatplotlib.font_manager.FontEntryクラスのオブジェクトであることがわかります。
matplotlib.font_manager.FontEntryのクラス変数を見てましょう。

```python
l_hiragino= [f for f in matplotlib.font_manager.fontManager.ttflist if f.name == 'Hiragino Sans']
```
として、Hiragino Sansのものだけを比較してみます。

## matplotlib.font_manager.FontEntry.name

* 詳しく書くまでもないので、これはl_hiraginoの全ての項目で"Hiragino Sans"になります。

## matplotlib.font_manager.FontEntry.fname

```python
[f.fname for f in l_hiragino]
"""
 >['/System/Library/Fonts/ヒラギノ角ゴシック W5.ttc',
 '/System/Library/Fonts/ヒラギノ角ゴシック W0.ttc',
 '/System/Library/Fonts/ヒラギノ角ゴシック W6.ttc',
 '/System/Library/Fonts/ヒラギノ角ゴシック W3.ttc',
 '/System/Library/Fonts/ヒラギノ角ゴシック W9.ttc',
 '/System/Library/Fonts/ヒラギノ角ゴシック W2.ttc',
 '/System/Library/Fonts/ヒラギノ角ゴシック W8.ttc',
 '/System/Library/Fonts/ヒラギノ角ゴシック W1.ttc',
 '/System/Library/Fonts/ヒラギノ角ゴシック W4.ttc',
 '/System/Library/Fonts/ヒラギノ角ゴシック W7.ttc'] 
"""
```

これを見ると、各要素は全てヒラギノ角ゴシックで、太さの違うもの[^1]になっていることがわかります。
ヒラギノ丸ゴシックについても見てみると

```python
l_hiragino_maru= [f for f in matplotlib.font_manager.fontManager.ttflist if f.name == 'Hiragino Maru Gothic Pro']
[f.fname for f in l_hiragino_maru]
# > ['/System/Library/Fonts/ヒラギノ丸ゴ ProN W4.ttc']
```
となり太さが一種類のものしか用意されていないことがわかります。
これでどのような影響が出るのかを見てみましょう。
matplotlib.font_manager.FontEntryの他のクラス変数はそこまで大きな発見などないので、後ろの方に載せておきます。

# ウェイト設定による違い

## ウェイト設定出来るヒラギノ角ゴシック
まずヒラギノ角ゴシックで例を見てみましょう

```python
# フォントをヒラギノ角ゴシックで
plt.rcParams['font.family'] = 'Hiragino Sans'  
```

### fontsize=default, fontweight=default
```python
fig,ax = plt.subplots(figsize=(3,3))
ax.annotate("テスト",xy=(0.5,0.5))
```
![font_test1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/196857/66fb3adb-78ab-d9df-6f03-ec8d1e873355.png)

うっす！！
ということでフォントのサイズを変えてみましょう
### fontsize=18, fontweight=default

```python
fig,ax = plt.subplots(figsize=(3,3))
ax.annotate("テスト",xy=(0.5,0.5),fontsize=18)
```
![font_test2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/196857/e3adb43d-6c81-000b-c9ae-486f633314b1.png)
まあ読めるようにはなりましたが、解像度が高くないような印象を受けます。
そこで太さを変更してみましょう。

### fontsize=default, fontweight="bold"

```python
fig,ax = plt.subplots(figsize=(3,3))
ax.annotate("テスト",xy=(0.5,0.5),weight="bold")
```
![font_test3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/196857/6890099a-7288-5988-077c-5bf665a8270d.png)

フォントサイズを大きくしなくても読みやすい印象を受けます。
fontweightについてはここ[^4]を参照すると
> 0-1000の数値で設定、もしくは' 'ultralight', 'light', 'normal', 'regular', 'book', 'medium', 'roman', 'semibold', 'demibold', 'demi', 'bold', 'heavy', 'extra bold', 'black'から選択

とあります。
この差を見てみましょう

```python
fig,ax = plt.subplots(figsize=(3,3))
ax.annotate("テスト",xy=(0.1,0.1),weight="ultralight",fontsize=18)
ax.annotate("テスト",xy=(0.1,0.2),weight="light",fontsize=18)
ax.annotate("テスト",xy=(0.1,0.3),weight="normal",fontsize=18)
ax.annotate("テスト",xy=(0.1,0.4),weight="regular",fontsize=18)
ax.annotate("テスト",xy=(0.1,0.5),weight="book",fontsize=18)
ax.annotate("テスト",xy=(0.1,0.6),weight="medium",fontsize=18)
ax.annotate("テスト",xy=(0.1,0.7),weight="roman",fontsize=18)
ax.annotate("テスト",xy=(0.1,0.8),weight="semibold",fontsize=18)
ax.annotate("テスト",xy=(0.1,0.9),weight="demibold",fontsize=18)
ax.annotate("テスト",xy=(0.5,0.9),weight="demi",fontsize=18)
ax.annotate("テスト",xy=(0.5,0.8),weight="bold",fontsize=18)
ax.annotate("テスト",xy=(0.5,0.7),weight="heavy",fontsize=18)
ax.annotate("テスト",xy=(0.5,0.6),weight="extra bold",fontsize=18)
ax.annotate("テスト",xy=(0.5,0.5),weight="black",fontsize=18)
```

![font_test4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/196857/7a663082-2eab-0c5e-f375-2ccaa8e30702.png)

2種類しか種類がないように見えます…
また、もう少し調べてみると
>fontweightは細かく指定しても反映されない
引用元：http://ebcrpa.jamstec.go.jp/~yyousuke/matplotlib/options.html

との記述もあります。

それでは、これらを踏まえてデフォルトのrc設定を変更しましょう。[^5],[^6]

```python
# フォント設定
plt.rcParams['font.family'] = 'Hiragino Sans'
# 太さ設定
plt.rcParams['font.weight'] = 'bold'

"""
fig,ax = plt.subplots()
ax.plot()...
などのプロット
"""

# legend使うとき
#legend_properties = {'size':14,'weight':'bold'}
#ax.legend(prop=legend_properties)


# plt.draw()が無いとget_ticklabels()で帰ってくるtextが空文字になる
plt.draw()
# ticklabelのフォントはrc設定では変えられないっぽい
ax.set_xticklabels(ax.get_xticklabels(),fontsize=14,fontweight='bold')
ax.set_yticklabels(ax.get_yticklabels(),fontsize=14,fontweight='bold')

```




# 以下蛇足

## matplotlib.font_manager.FontEntry.size
```python
[f.size for f in l_hiragino]

"""
> ['scalable',
 'scalable',
 'scalable',
 'scalable',
 'scalable',
 'scalable',
 'scalable',
 'scalable',
 'scalable',
 'scalable']
"""
```

となり全て'scalable'となります。これについては公式doc[^2]に

> If size2 (the size specified in the font file) is 'scalable'

という記述があることから、'saclable'であるとは、サイズがフォントファイルによって指定されるものである、ということがわかります。
私の環境でヒラギノ以外のフォントも見てみましたが、全てscalableとなったのであまり良くわかりませんが、太さが指定されるということなのでしょうか…



## matplotlib.font_manager.FontEntry.stretch

```python
[f.stretch for f in l_hiragino]
"""
> ['normal',
 'normal',
 'normal',
 'normal',
 'normal',
 'normal',
 'normal',
 'normal',
 'normal',
 'normal']
"""
```

ヒラギノでは全てnormalでしたが、condensedになっているものも確認できました。

公式doc[^2]に
> The result is the absolute value of the difference between the CSS numeric values of stretch1 and stretch2

とあるので、CSSのfont-stretch[^3]を参照するとフォントの幅を言っているのだと思います。

## matplotlib.font_manager.FontEntry.style

```python
[f.style for f in l_hiragino]
"""
> ['normal',
 'normal',
 'normal',
 'normal',
 'normal',
 'normal',
 'normal',
 'normal',
 'normal',
 'normal']
"""
```

これもヒラギノでは全てnormalになりましたが、なかにはitalicになっているものも確認できました。
これは斜体などの書体の情報でしょう。







[^1]: https://fontnavi.jp/zakkuri/206-font_weight.aspx
[^2]: https://matplotlib.org/3.1.1/api/font_manager_api.html
[^3]: https://dekiru.net/article/13115/
[^4]: https://qiita.com/eriho/items/21302ab7e95a2721b9f8
[^5]: https://stackoverflow.com/questions/32700935/get-xticklabels-contains-empty-text-instances
[^6]: https://stackoverflow.com/questions/35537895/matplotlib-legend-how-to-specify-font-weight