Python/Matplotlibでグラフを描いてみよう01(グラフを作るためのキホン)

Python/Matplotlibでグラフを描いてみよう01(グラフを作るためのキホン)

Matplotlibでグラフを作るためのキホンを身に着けよう




対話的なコードの書き方とオブジェクト指向的なコード書き方を理解する

ナノネ、PythonでMatplotlibを使ったグラフの作り方を学習するよ。今回1回目は復習も兼ねてキホン的なグラフの作り方を練習しよう。

グラフ作り方をすぐ忘れちゃうんだよね。あと思い通りのグラフが描けなかったり...。

グラフはデータの内容把握や分析結果の説明解釈でとても役立つから、いろいろなグラフを作れるようにこれから練習して行こう!

ラジャー。

まずは、必要なパッケージをインポート。決まり文句のコードで。

In [0]:
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
In [0]:
# ********************************
# 動作テスト環境 @2019/05
# ********************************
# Google Colaboratory
# Ubuntu 18.04.2 LTS
# Python 3.6.7
# :: matplotlib 3.0.3
# :: numpy 1.16.3
# :: scikit-learn 0.20.3

Matplotlibを使ってグラフを作るには、コードの書き方が大きく分けて2通りあるんだ。対話的に表記する方法と、オブジェクト指向的にコードを書く方法があるよ。

うん、うん。そこがいつも混乱するんだよね。

どっちの方法(対話形式、オブジェクト指向形式)でも大抵は同じグラフが描けるんだけど、後々のためにも両方の書き方を覚えておいてね。他の人が書いたコードを理解するときにも重要になるから。

公式ドキュメントも、両方の書き方が混在してたかも。使い分けが難しいなぁ...。

どっちを使うかはお好みだけど、サックと簡単なグラフを作るときは対話形式で、少し複雑なグラフを作るときはオブジェクト指向的な書き方がオススメかな。

まず最初は、簡単な対話的なコードの書き方でグラフを作ってみよう。

対話的な書き方でグラフを作成する方法

今回は疑似データを使うことにするね。簡単な放物線のデータでグラフを描いてみよう。plot()メソッドにx,yデータを指定するだけでグラフを描けるよ。

In [3]:
# data for ploting
x = np.arange(-10, 11)
y = x ** 2

# plot
plt.plot(x, y) # プロットメソッド実行
plt.show() # グラフ表示(Jupyter Note Bookインライン表示の場合は省略可能)

Matplotlibのpyplotをpltという名前でインポートしたから、plt.plot(xデータ, yデータ)とすればOKだね。

ちなみにxデータは省略もできて、yデータだけでもグラフを描けるよ。xデータを省略した場合は、xデータに連番が自動設定されるよ(0, 1, 2 ... n-1)。

In [4]:
plt.plot(y) # yデータだけ指定
plt.show()

次は丸いマーカーでプロットしてみよう。丸いマーカーはo(小文字のオー)を文字列で指定してね。

In [5]:
plt.plot(x, y, 'o') # 丸マーカー
plt.show()

四角マーカーはs、三角は^、バツはxとか、いろいろ指定できたよね。

次は線とマーカーの両方でプロットしてみよう。文字列にo-(小文字オーとマイナス)を指定すればOK。

In [6]:
plt.plot(x, y, 'o-') # 丸マーカーと線
plt.show()

マイナスが線を意味しているんだよね。たしか、マイナス2個で破線にできたはず。

In [7]:
plt.plot(x, y, 'o-') # 丸マーカーと破線、線種は他にも'-.'など
plt.show()

次は色を変更してみよう。文字列に小文字r(redのr)を付ければ赤くなるよ。

In [8]:
plt.plot(x, y, 'ro-') # 赤、丸マーカー、線
plt.show()

色指定はbだと青、gで緑、yで黄色、kで黒とかもあったよね。

次はグラフにタイトルを設定しよう。title()メソッドにお好みタイトル名を指定すればOK。文字サイズは引数sizeで、色は引数colorで指定できるよ。

In [9]:
plt.plot(x, y)
plt.title('Graph Title', size=20, color='green') # グラフタイトル設定
plt.show()

次は軸ラベルを付けてみよう。x軸ラベルはxlabel()メソッド、y軸ラベルはylabel()メソッドで設定できるよ。

In [10]:
plt.plot(x, y)
plt.title('Graph Title', size=20)

plt.xlabel('x Label', size=15) # x軸ラベル設定
plt.ylabel('y Label', size=15) # y軸ラベル設定

plt.show()

軸ラベルの文字サイズ、色とかの指定はタイトルと一緒だったね。

次は軸の値範囲を変更してみよう。x軸範囲はxlim()メソッド、y軸範囲はylim()メソッドで、引数にそれぞれの任意の最小と最大値を指定すればOK。

In [11]:
# 軸の値範囲を指定

plt.plot(x, y)
plt.title('Graph Title', size=20)
plt.xlabel('x Label', size=15)
plt.ylabel('y Label', size=15)

plt.xlim(-15, 15) # x軸の範囲設定 xmin, ymax
plt.ylim(-50, 150) # y軸の範囲設定 ymin, ymax

plt.show()

次は複数種類のデータを一つのグラフに重ねてプロットする方法をだよ。yデータを3つ準備してプロットしてみよう。plot()メソッドを順番に書き足すだけOK。

In [12]:
# 複数種類のデータを重ねてプロット

# data for ploting
x = np.arange(-10, 11)
y1 = x ** 2
y2 = (x - 1) ** 2
y3 = (x - 2) ** 2

# plot
plt.plot(x, y1, 'r') # データ1プット
plt.plot(x, y2, 'b') # データ2プロット
plt.plot(x, y3, 'y') # データ3プロット

plt.show()

複数のデータがあると凡例を表示したくなるかも。

凡例を表示したい場合は、legend()メソッドを使うよ。凡例に表示したい名称は、plot()メソッドのlabelに値を設定しておけば、その内容を表示してくれるよ。

In [13]:
# 凡例を表示
plt.plot(x, y1, 'r', label='DATA1(red)') # データ1プット
plt.plot(x, y2, 'b', label='DATA2(blue)') # データ2プロット
plt.plot(x, y3, 'y', label='DATA3(yellow)') # データ3プロット

plt.legend(loc=1) # 凡例表示、locで表示位置指定

plt.show()

引数locは凡例の表示位置だね。位置指定は数値または、文字列(‘best’ 、‘upper right’、‘lower left’など)でも選べたね。

続いて、複数のグラフを並べてプロットする方法。この辺からコードが少しややこしくなるけど、がんばって。対話形式で、ひとつのグラフ枠に複数のグラフをレイアウトしたい場合は、subplot()メソッドを使うよ。試しにグラフを横に3つ並べてみよう!

subplot()メソッドの引数は、レイアウトしたい行数と列数、それとレイアウトの何番目かを指定してね。グラフを横に3つ並べたいので、行数1、列数3だよ。レイアウト番号は今回の場合だと、左から1,2,3になるよ。

コードの記載方法としては、subplot()メソッド、plot()メソッド、その他グラフお飾り()メソッドの組みを、レイアウトしたい順に書いていけばOKだよ。

In [14]:
# 複数のグラフを並べてプロット(1行3列レイアウト)

# data for ploting 簡単のため、データは使いまわしで
x = np.arange(-10, 11)
y = x ** 2

# plot1
plt.subplot(1, 3, 1) # もしくは131(1行3列の1番目のグラフ)
plt.plot(x, y, 'r')
plt.title('Graph-1(1,1)')

# plot2
plt.subplot(1, 3, 2) # もしくは132(1行3列の2番目のグラフ)
plt.plot(x, y, 'b')
plt.title('Grap-2(1,2)')

# plot3
plt.subplot(1, 3, 3) # もしくは133(1行3列の3番目のグラフ)
plt.plot(x, y, 'y')
plt.title('Grap-3(1,3)')

plt.show()

プロットしたいものを順番に書いていけばいいんだね。記載が面倒だけど、コピペも使えるから平気。

同じ要領で2行2列のレイアウトもやってみよう。行数2、列数2とすればOKだね。レイアウト番号は左上から1,2、左下から3,4になるよ。

In [15]:
# 複数のグラフをプロット(2行2列レイアウト)

# plot1
plt.subplot(2, 2, 1) # もしくは221(2行2列の1番目)
plt.plot(x, y, 'r')
plt.title('Graph-1(1,1)')

# plot2
plt.subplot(2, 2, 2) # もしくは222(2行2列の1番目)
plt.plot(x, y, 'b')
plt.title('Graph-2(1,2)')

# plot3
plt.subplot(2, 2, 3) # もしくは221(2行2列の3番目)
plt.plot(x, y, 'y')
plt.title('Graph-3(2,1)')

# plot4
plt.subplot(2, 2, 4) # もしくは221(2行2列の4番目)
plt.plot(x, y, 'k')
plt.title('Graph-4(2,2)')

plt.show()

グラフが重なって、タイトルの文字とか読めないね。

いい感じに隙間を調整してくれる便利なメソッドがあるから大丈夫だよ。tight_layout()メソッドを実行するだけで、グラフが重ならいようにサイズを自動調整してくれるよ。

In [16]:
# 複数のグラフプロット(グラフが重ならいようにサイズ、隙間を自動調整)

# plot1
plt.subplot(2, 2, 1)
plt.plot(x, y, 'r')
plt.title('Graph-1(1,1)')

# plot2
plt.subplot(2, 2, 2)
plt.plot(x, y, 'b')
plt.title('Graph-2(1,2)')

# plot3
plt.subplot(2, 2, 3)
plt.plot(x, y, 'y')
plt.title('Graph-3(2,1)')

# plot4
plt.subplot(2, 2, 4)
plt.plot(x, y, 'k')
plt.title('Graph-4(2,2)')

plt.tight_layout() # グラフが重ならないように自動調整

plt.show()

グラフが重ならいように、いい感じに調整してくれた。便利だね。

次はグラフの大きさを変更してみよう。グラフの全体枠はfigure()メソッドの引数figsizeで設定できるよ。figsizeは横サイズ、縦サイズをタプル形式(w, h)で指定してね。

In [17]:
# グラフサイズ(外枠)を指定

plt.figure(figsize=(10, 10)) # グラフ枠サイズをfigsizeで指定(横, 縦)

# plot1
plt.subplot(2, 2, 1)
plt.plot(x, y, 'r')
plt.title('Graph-1(1,1)')

# plot2
plt.subplot(2, 2, 2)
plt.plot(x, y, 'b')
plt.title('Graph-2(1,2)')

# plot3
plt.subplot(2, 2, 3)
plt.plot(x, y, 'y')
plt.title('Graph-3(2,1)')

# plot4
plt.subplot(2, 2, 4)
plt.plot(x, y, 'k')
plt.title('Graph-4(2,2)')

plt.show()

グラフが大きくなった。

対話的な書き方はこれぐらいで。次は同じことをオブジェクト指向的な書き方で記載してみよう。

オブジェクト指向的な書き方でグラフを作成する方法

オブジェクト指向的にコードを書く場合は、Matplotlibで扱うグラフオブジェクトの階層構造を意識することがポイントだよ。

Matplotlibのグラフオブジェクトは階層構造になっていて、グラフの全体枠(親ウィンドウみたいなもの)がfigureオブジェクト。そしてfigureオブジェクトの中に実際にグラフを描画する領域axesオブジェクトがあるんだよ。ひとつのfigureオブジェクトには複数のaxesオブジェクトを持つことができるよ。

対話的な書き方だとfigureオブジェクトやaxesオブジェクトは、暗黙的に作ってくれたり、現在の操作対象を自動で解釈するから、オブジェクト自体をあまり意識する機会がないよね。

オブジェクト指向的に書く場合は、明示的に作成したオブジェクトを変数に格納。作成したオブジェクトに対してなんらかのグラフ操作を行うような流れになるよ。実際にコードを書いてみよう。

In [18]:
# オブジェクト指向の書き方でグラフを作成1

# data for ploting
x = np.arange(-10, 11)
y = x ** 2

# plot
fig = plt.figure() # figureオブジェクトを作成 ※1

ax = fig.add_subplot(1, 1 ,1) # axesオブジェクトを作成(1行1列の1番目、グラフ1個) ※2

ax.plot(x, y) # axesにプロット ※3

plt.show() # もしくはfig.show()でもOK

まず、figureオブジェクト(グラフの外枠的な入れ物)を作るには、figure()メソッドを利用するよ。今回作ったfigureオブジェクトは、変数名figに格納しているね(コード※1部)。

次に作ったfigureオブジェクト(変数名fig)に対して、add_subplot()メソッドを実行することでaxesオブジェクトが作成されるよ。作ったaxesオブジェクトは、axという変数名で格納しているね(コード※2部)。

add_subplot()はfigureオブジェクトが持つメソッドで、axes(グラフを実際に描画する領域)を作れるんだね。

そして、作ったaxesオブジェクト(変数名ax)に対して、plot()メソッドを実行すれば対話的な書き方と同じようにグラフを作成できるよ。(コード※3部)。

オブジェクト指向的な書き方では、axesオブジェクトに対してplot()メソッドを実行すればいいんだね。

対話的な書き方だと、plt.〇〇〇でなんでも実行できたのに、オブジェクト指向的な書き方だど、少し面倒かも。コードも長くなるし、わざわざオブジェクトを明示的に書くことで、何かメリットあるの?

複雑なグラフを作るとき、対話的なコードだと操作対象のオブジェクトが不明瞭になっちゃうことも多いので、オブジェクト指向的に書いた方が対象が明確になって扱いやすいかな。でも目的のグラフが描けるならどっちの書き方でもOKだよ。ただ、対話式で書く場合でも今、何のオブジェクトに対して操作を行っているか意識することは大事かもね。

両方使ったハイブリットでの記載もよくあるね。混乱しないように対象のオブジェクトを意識しないと。

次はオブジェクト指向的な書き方で複数のグラフをプロットしてみよう。今と同じ書き方でOKだよ。figureオブジェクトのadd_subplot()メソッドで、axesオブジェクトを作って、plot()だね。それをグラフのレイアウト分を書き連ねれば目的のグラフが描けるよ。

あと、タイトルを設定する場合はaxesオブジェクトのset_title()メソッドを使ってね。タイトルとかラベルなどの設定は、axesオブジェクトのメソッドを使うよ。axesオブジェクト.set_〇〇〇()みたい形式が多いから覚えておいてね。

In [19]:
# オブジェクト指向の書き方でグラフを作成2

fig = plt.figure()

ax1 = fig.add_subplot(1, 3 ,1) # グラフ描画エリア(axes)を追加(1行3列の1番目)
ax1.plot(x, y, 'r')
ax1.set_title('Graph-1(1,3,1)') # axisにset_titleでタイトルを設定

ax2 = fig.add_subplot(1, 3 ,2) # グラフ描画エリア(axes)を追加(1行3列の2番目)
ax2.plot(x, y, 'b')
ax2.set_title('Graph-2(1,3,2)')

ax3 = fig.add_subplot(1, 3 ,3) # グラフ描画エリア(axes)を追加(1行3列の2番目)
ax3.plot(x, y, 'y')
ax3.set_title('Graph-3(1,3,3)')

plt.tight_layout()
plt.show()

続いて、figureオブジェクトとaxesオブジェクトを同時に作成する書き方。plt(matplotlib.pyplot)のsubplots()メソッドを使うよ。subplotsはsが付く複数形だから注意ね。引数は作りたいグラフの行数と列数を渡せばOKだよ。

subplots()の返り値はfigureオブジェクトとaxesオブジェクトの2つがあるから、それぞれを順に変数で受け取ってね。それと複数レイアウトだとaxesオブジェクトの返り値が配列形式になるから、対象のaxesオブジェクトにアクセスするときはインデックスも指定する必要があるよ。

In [20]:
# オブジェクト指向の書き方でグラフを作成3

# data for ploting
x = np.arange(-10, 11)
y = x ** 2

# plot
fig, ax = plt.subplots(1, 3) # subplotsでfigureとaxes(1行3列で3個)を同時に作成

ax[0].plot(x, y, 'r')
ax[0].set_title('Graph-1(1,3,1)')

ax[1].plot(x, y, 'b')
ax[1].set_title('Graph-2(1,3,2)')

ax[2].plot(x, y, 'y')
ax[2].set_title('Graph-1(1,3,3)')

plt.tight_layout()
plt.show()

上と同じグラフをインデックスとループ処理を使ってコードにすると、こんな感じかな。

In [21]:
# オブジェクト指向の書き方でグラフを作成4

# data for ploting
x = np.arange(-10, 11)
y = x ** 2

# plot
fig, ax = plt.subplots(1, 3, figsize=(8, 4)) # subplotsでfigureとaxes(1行3列で3個)を同時に作成

type_letters = ['r', 'b', 'y']

for i in range(3):
  ax[i].plot(x, y, type_letters[i])
  ax[i].set_title('Graph-{}(1,3,{})'.format(i+1, i+1), size=15)
  ax[i].set_xlabel('x Label')
  ax[i].set_ylabel('y Label')

plt.tight_layout()
plt.show()

グラフをたくさん書くときは便利かも。

キホン的なグラフの作り方の練習は以上で。ここまで出来れば、あとはドキュメントなどを調べながら、いろんなグラフが作れると思うよ。

最後は、今回の使ったコードを参考にIrisデータをプロットしてみよう。

ラストは、みんな大好き?『Iris』データでグラフを作成

In [22]:
# Irisデータプロット

# データセットからIrisデータ読み込み
from sklearn import datasets
iris = datasets.load_iris()

# プロットするデータの組み合わせリスト
# 0:sepal length (cm) 1:sepal width (cm) 2:petal length (cm) 3:petal width (cm)
pattern = [[0, 1], [0, 2], [0, 3], [1, 2], [1, 3], [2, 3]] # 6通り(4Combi2)

# plot
fig, ax = plt.subplots(2, 3, figsize=(10, 6)) # (2行3列でグラフ6個分)

for i in range(6):
  row = i // 3
  col = i % 3
  
  x_data_index, y_data_index = pattern[i] # プロットするデータの組み合わせ
  
  x = iris.data[:, x_data_index]
  y = iris.data[:, y_data_index]
                
  xlabel = iris.feature_names[x_data_index] # x軸データの特徴名称
  ylabel = iris.feature_names[y_data_index] # y軸データの特徴名称
                
  #xlabel = iris
  ax[row, col].plot(x, y, 'o', alpha=0.5) # マーカー透明度0.5
  ax[row, col].set_title('Iris axes-{}'.format(i), size=15)
  ax[row, col].set_xlabel(xlabel, size=12)
  ax[row, col].set_ylabel(ylabel, size=12)

plt.tight_layout()
plt.show()

お疲れ様でした。またね!







スポンサーリンク

0 件のコメント :

コメントを投稿