MENU

matplotlib の理解が劇的に深まる、図の構成要素と Artist の話

たぬ

こんにちは、グロースハッカーの たぬ ( @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は、基本的に下から順番にFigureAxesAxisTickの4層のオブジェクトから構成されています。(土台となるレイヤーを下から順番に重ねていくイメージです。)

上の画像には目盛りを意味するTickが省略されていますが、下の構造をみれば理解できるでしょう。

Figure
  ┗ Axes
      ┣ XAxis
      ┃   ┗ XTick 
      ┗ YAxis
          ┗ XTick 

ちょっと補足をすると、Axisは軸なので x軸y軸 の2つが存在します。2つの軸が存在するということは、2つの目盛り(Tick)が存在するという訳ですね。

また、Axis の複数形である Axes座標軸 という意味合いで matplotlib に登場し、 x軸 と y軸 の両軸からなる実際に グラフをプロットする場所 になっています。

Figure と Axes の違い

一見わかりづらいFigureAxesの違いですが、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 でFigureAxesオブジェクトを、以下のように定義した場合、

# オブジェクト指向スタイル
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)

FigureAxesオブジェクトの属性からArtistを取得することが出来ます。

スクロールできます
属性説明
fig.axesAxesオブジェクトのリスト
fig.patchFigureの背景用のRectangleオブジェクト
fig.textsAxesの外側にあるTextオブジェクトのリスト
fig.legendsAxesの外側にあるLegend オブジェクトのリスト
ax.patchAxesの背景用のRectangleオブジェクト
ax.titleAxes titleTextオブジェクト
ax.textsAxesの内側にあるTextオブジェクトのリスト
ax.legendsAxesの内側にあるLegend オブジェクトのリスト
ax.spinesSpine オブジェクトの順序付き辞書
ax.patchespatchオブジェクトのリスト、棒グラフなど
ax.linesLine2D オブジェクトのリスト、線グラフやエラーバーなど
ax.collectionsCollectionオブジェクトのリスト、散布図や推定領域など
ax.xaxisXAxisオブジェクト(XAxis labelXAxis tickXAxis tick labelを子として含む)
ax.yaxisYAxisオブジェクト(YAxis labelYAxis tickYAxis 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.artistgetpメソッドを使うと、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オブジェクトはAxeslines属性で取得することができると前節の表で紹介しました。今回、折れ線グラフは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などが分かりますね。この数値を目安に微調整していく感じです。

この記事が気に入ったら
フォローしてね!

シェアしていただけると励みになります
  • URLをコピーしました!

コメント

コメントする

目次
閉じる