こんにちは、グロースハッカーの たぬ ( @tanuhack )です。
matplotlib は自由度が高すぎるがゆえに、何をどういじれば思い描いたグラフを作ることができるのか、今日も多くの人が細かい調整に多大な時間を奪われているに違いありません。かく言う私もその一人でした。
グラフの専門用語もあいまいで、そもそも自分がやりたい視覚化は 何という箇所をいじれば良いのか? を調べるところから始まります。公式リファレンスを覗こうにも、英語で書かれたグラフの専門用語の洗礼を受けるので十中八九挫折するでしょう。
まずは 日本語と英語の専門用語を結びつけること からはじめてみてください。そして、次に matplotlib の中核をなす Artist について理解して、少しずつ慣れていきましょう。
本記事では、以下のモジュールを読み込んで進めるものとします。
import matplotlib as mpl
import matplotlib.pyplot as plt
import seaborn as sns
図の構成要素
matplotlib の解剖図
まずは、公式の Usage Guide でも紹介されている matplotlib の解剖図を、英語と日本語で交互に対応付けしながら確認しましょう。はじめのころは Tick(目盛り)とか Spines(枠線)とか知りませんでした。
matplotlib の階層構造
matplotlibは、基本的に下から順番にFigure
、Axes
、Axis
、Tick
の4層のオブジェクトから構成されています。(土台となるレイヤーを下から順番に重ねていくイメージです。)
上の画像には目盛りを意味するTick
が省略されていますが、下の構造をみれば理解できるでしょう。
Figure
┗ Axes
┣ XAxis
┃ ┗ XTick
┗ YAxis
┗ XTick
ちょっと補足をすると、Axis
は軸なので x軸 と y軸 の2つが存在します。2つの軸が存在するということは、2つの目盛り(Tick
)が存在するという訳ですね。
また、Axis
の複数形である Axes
は 座標軸 という意味合いで matplotlib に登場し、 x軸 と y軸 の両軸からなる実際に グラフをプロットする場所 になっています。
Figure と Axes の違い
一見わかりづらいFigure
と Axes
の違いですが、Figure
はグラフの部品を全て格納する コンテナ 、Axes
はグラフをプロットしたり、その他の装飾を施したりする アートボード みたいなものと覚えておくと良いでしょう。
それでもまだイメージが掴みにくいという方は、サブプロット(複数のAxes
があるFigure
)を見ると腑に落ちるかもしれません。下の画像は1つのFigure
に対して2つのAxes
が存在します。そしてAxes
のそれぞれにヒストグラムがプロットされています。
Figure
┣ Axes1
┃ ┣ XAxis1
┃ ┃ ┗ XTick1
┃ ┗ YAxis1
┃ ┗ YTick1
┗ Axes2
┣ XAxis2
┃ ┗ XTick2
┗ YAxis2
┗ YTick2
Artist について
図やx軸、y軸、線、点、矩形、文字など、matplotlib で描画される 全ての要素(オブジェクト) のことをArtist
と言います。
この章は、公式の Artist tutorial を理解しやすいように簡潔にまとめたものになります。
Artist の構成要素
下の画像を見るとArtist
の全容と関係性を知ることができます。
Artist
は、 containers(コンテナ:容器) と primitives(プリミティブ:複雑な構造を形作る際の要素) の2つに分類されます。要は、グラフの土台か、実際に作成される要素か、といった感じですね。
containers
- Figure
- Axes
- Axis(XAxis、YAxis)
- Tick(XTick、YTick)
primitives
- Line2D
- Rectangle
- PolyCollection
- Annotation
- Spine
- Legend
など
Artist を取得する
matplotlib や seaborn でFigure
とAxes
オブジェクトを、以下のように定義した場合、
# オブジェクト指向スタイル
fig, ax = plt.subplots()
ax.**plot()
# Figure-level関数
g = sns.**plot()
fig, ax = (g.fig, g.ax)
# Axes-level関数
fig, ax = plt.subplots()
sns.**plot(ax=ax)
Figure
やAxes
オブジェクトの属性からArtist
を取得することが出来ます。
属性 | 説明 |
---|---|
fig.axes | Axes オブジェクトのリスト |
fig.patch | Figure の背景用のRectangle オブジェクト |
fig.texts | Axes の外側にあるText オブジェクトのリスト |
fig.legends | Axes の外側にあるLegend オブジェクトのリスト |
ax.patch | Axes の背景用のRectangle オブジェクト |
ax.title | Axes title のText オブジェクト |
ax.texts | Axes の内側にあるText オブジェクトのリスト |
ax.legends | Axes の内側にあるLegend オブジェクトのリスト |
ax.spines | Spine オブジェクトの順序付き辞書 |
ax.patches | patch オブジェクトのリスト、棒グラフなど |
ax.lines | Line2D オブジェクトのリスト、線グラフやエラーバーなど |
ax.collections | Collection オブジェクトのリスト、散布図や推定領域など |
ax.xaxis | XAxis オブジェクト(XAxis label 、XAxis tick 、XAxis tick label を子として含む) |
ax.yaxis | YAxis オブジェクト(YAxis label 、YAxis tick 、YAxis tick label を子として含む) |
Axis
の子要素のArtist
を取得したいときは、アクセサ・メソッドを使用します。
アクセサ・メソッド | 説明 |
---|---|
ax.xaxis.get_label() | XAxis label オブジェクト |
ax.xaxis.get_ticklines() | XAxis tick オブジェクトのリスト、ヘルパーメソッドのax.get_xticklines() でも同様 |
ax.xaxis.get_ticklabels() | XAxis tick label オブジェクトのリスト、ヘルパーメソッドのax.get_xticklabels() でも同様 |
ax.yaxis.get_label() | YAxis label オブジェクト |
ax.yaxis.get_ticklines() | YAxis tick オブジェクトのリスト、ヘルパーメソッドのax.get_yticklines() でも同様 |
ax.yaxis.get_ticklabels() | YAxis tick label オブジェクトのリスト、ヘルパーメソッドのax.get_yticklabels() でも同様 |
プロパティ値を調査する
matplotlib.artist
のgetp
メソッドを使うと、Artist
の全てのプロパティ値をまとめて出力できます。デフォルト値を知ると、ピクセルや色の調整が捗るのでオススメです。
https://matplotlib.org/stable/api/_as_gen/matplotlib.artist.getp.html
mpl.artist.getp(Artist)
例えば、簡単な折れ線グラフをプロットして 描画された線のプロパティ値がどうなっているか調べたい とします。
fig, ax = plt.subplots()
ax.plot([1, 2, 4, 8])
線はLine2D
オブジェクトです。Line2D
オブジェクトはAxes
のlines
属性で取得することができると前節の表で紹介しました。今回、折れ線グラフは1本だけ描画されているので、リストの番地は 0
になります。
print(mpl.artist.getp(ax.lines[0]))
# agg_filter = None
# alpha = None
# animated = False
# antialiased or aa = True
# children = []
# clip_box = TransformedBbox( Bbox(x0=0.0, y0=0.0, x1=1.0, ...
# clip_on = True
# clip_path = None
# color or c = #1f77b4
# contains = None
# dash_capstyle = butt
# dash_joinstyle = round
# data = (array([0., 1., 2., 3.]), array([1, 2, 4, 8]))
# drawstyle or ds = default
# figure = Figure(432x288)
# fillstyle = full
# gid = None
# in_layout = True
# label = _line0
# linestyle or ls = -
# linewidth or lw = 1.5
# marker = None
# markeredgecolor or mec = #1f77b4
# markeredgewidth or mew = 1.0
# markerfacecolor or mfc = #1f77b4
# markerfacecoloralt or mfcalt = none
# markersize or ms = 6.0
# markevery = None
# path = Path(array([[0., 1.], [1., 2.], [2.,...
# path_effects = []
# picker = None
# pickradius = 5
# rasterized = None
# sketch_params = None
# snap = None
# solid_capstyle = projecting
# solid_joinstyle = round
# transform = CompositeGenericTransform( TransformWrapper( ...
# transformed_clip_path_and_affine = (None, None)
# url = None
# visible = True
# xdata = [0. 1. 2. 3.]
# xydata = [[0. 1.] [1. 2.] [2. 4.] [3. 8.]]
# ydata = [1 2 4 8]
# zorder = 2
出力されたものに目を通すと、線の色'#1f77b4'
、線の太さ1.5
、線の種類'-'
、重なり順2
などが分かりますね。この数値を目安に微調整していく感じです。
コメント