matplotlibのfontsizeで指定する相対サイズの定義と利便性

# fontsizeオプション

matplotlibを用いた描画において，labelやtitle，ticklabelなどの文字の大きさはfontsizeオプションによって指定できる．これら文字に関連する要素のオプションは，matplotlib.text.Textクラスで定義されるものを引き継いでいる（[公式リンク](https://matplotlib.org/api/text_api.html#matplotlib.text.Text)）．
matplotlib.text.Textクラスにおいて定義される変数fontsizeは，point単位（約0.35278mm，1インチの72分の1）での絶対サイズ指定以外に，下記の相対サイズ指定ができる．

```py:
{'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large'}
```

# ソースコードの解説

これらは，デフォルトの文字サイズ（rcParams['font.size']）に対する倍率を表している．
具体的な値は，matplotlib.font_managerクラスのクラス変数で定義されている（[ソースコード](https://matplotlib.org/_modules/matplotlib/font_manager.html)）．

```py:相対クラスの変換倍率（matplotlib.font_managerクラスのソースコードより）
font_scalings = {
    'xx-small' : 0.579,
    'x-small'  : 0.694,
    'small'    : 0.833,
    'medium'   : 1.0,
    'large'    : 1.200,
    'x-large'  : 1.440,
    'xx-large' : 1.728,
    'larger'   : 1.2,
    'smaller'  : 0.833,
    None       : 1.0}
```

これを，同クラスのset_size()において参照し，相対サイズを適用する．

```py:set_size（matplotlib.font_managerクラスのソースコードより）
def set_size(self, size):
        #（中略）
        if size is None:
            size = rcParams['font.size']
        try:
            size = float(size)                # <--数字指定の場合
        except ValueError:
            try:
                scale = font_scalings[size]   # <--相対指定の場合
                                              #    font_scalingsから倍率取得
            except KeyError:
                raise ValueError(
                    "Size is invalid. Valid font size are "
                    + ", ".join(map(str, font_scalings)))
            else:  # <--try成功時 (相対指定)
                size = scale * FontManager.get_default_size() # defaultのsizeに倍率を乗じて使用
        if size < 1.0:
            _log.info('Fontsize %1.2f < 1.0 pt not allowed by FreeType. '
                      'Setting fontsize = 1 pt', size)
            size = 1.0
        self._size = size
```

# 図中の各パーツのデフォルト文字サイズ

matplotlib.rcParamsを参照すると，描画に必要なパラメータのデフォルト値の一覧を確認できる．そのうち，パーツごとの文字サイズに関するパラメータは下記のように確認できる（値は異なる可能性がある）．

```py:matplotlib.rcParamsの一部
'font.size': 10.0

'axes.titlesize': u'large'
'axes.labelsize': u'medium'
'legend.fontsize': u'medium'
'xtick.labelsize': u'medium'
'ytick.labelsize': u'medium'
```

上記のデフォルト値であり，かつfontsize指定をしなかった場合，タイトルは10.0×1.200=12pt，その他は10ptで描画が行われる．

# 図中の各パーツの文字サイズ確認

本当にそうなっているかを確認したい場合，各パーツに割り当てられているget_fontsize()メソッドを用いて実際に使用されている値を参照できる（代わりにset_fontsize(n)とすればfontsizeを変更することができる）．

```py:matplotlib.rcParamsの一部
# 適当に描画
fig = plt.figure()
ax  = fig.add_subplot()
ax.plot([0,1],[0,1],label='line_1')
ax.plot([0,1],[1,0],label='line_2')
ax.legend(title='legend')
ax.set_title('title')
ax.set_xlabel('x')
ax.set_ylabel('y')

# フォントサイズの取得
print ax.title.get_fontsize()
print ax.xaxis.label.get_fontsize()
print ax.yaxis.label.get_fontsize()
print ax.get_legend().get_title().get_fontsize()
### legendは，各プロットごとにパーツがわかれる
lgd_txts = ax.get_legend().get_texts()
print lgd_txts[0].get_fontsize()
### ticklabelは，各目盛ごとにパーツがわかれる
tcks = ax.xaxis.get_major_ticks()
print tcks[0].label.get_fontsize()
```

# おわりに

自分で一番お気に入りのfontsizeをpoint単位で各パーツごとに決めておくのが最善だと思いますが，図の縮尺に応じてそれを変更させるが面倒くさい場合は，コード中で

```py:
plt.rcParams['font.size'] = 18
```

のようにデフォルトのfont.sizeだけ変更して，ほかは相対指定にすると結構便利だと思います．