MyEnigma

とある自律移動システムエンジニアのブログです。#Robotics #Programing #C++ #Python #MATLAB #Vim #Mathematics #Book #Movie #Traveling #Mac #iPhone

MATLABユーザのためのPythonグラフ作成ツールmatplotlib入門

 

目次

はじめに

多くの人にとって、

MATLABを使っている理由の一つは、

強力なグラフツールだと思います。

 

最近、MATLABも安く手に入るようになってきましたが、

myenigma.hatenablog.com

LinuxやMacなど色々なプラットフォームで使いたくなるので、

MATLABも使いづらい所があります。

 

そこで良くMATLABの代わりに使われるのがPythonです。

Pythonは非常に広く使用されているフリーの汎用プログラミング言語ですが、

機械学習や、確率統計の分野で広く使用され、

フリーのライブラリも数多く提供されているため、

使用する人が多いようです。

 

そんなPythonには、matplotlibという

強力なグラフツールがあります。

このライブラリを使いこなすことができれば、

pythonをMATLABの代わりに使うことも出来そうです。

 

このmatplotlibを上手く使うことで、

MATLABのような見やすいグラフや、

インタラクティブなグラフ

そして、簡単なアニメーションなどを作ることができます。

 

今回はMATLABユーザの視点で、

matplotlibの使い方を説明したいと思います。

matplotlibのダウンロード

ソースコードやインストーラは下記のページにおいてあります。

pipで入れることもできますが、

下記の記事のように、色々依存関係で落とし穴があるみたいなので、

注意してダウンロードしましょう。

 

どんなグラフを作ることができるのかは、

下記の公式ページの例やギャラリーを見るとわかりやすいかと思います。

線グラフ

下記は基本的な線グラフのサンプルコードです。

from pylab import *

t = arange(0.0, 1.0+0.01, 0.01)
s = cos(2*2*pi*t)
plot(t, s, '-', label="data1",lw=2)

xlabel('time (s)')
ylabel('Speed (m/s)')
title('Test')
legend()
grid(True)

show()

すると下記のようなグラフが表示されます。

MATLABと違う所は、

凡例はplot関数の中で指定すること、

gridの設定方法が異なること、

線の太さはlw(linewidth)引数に入れる

plotだけではグラフは表示されず、show関数が必要なことです。

 

ちなみに、左下のボタンを使えば、

グラフをズームしたり、

グラフを画像に変換したりできます。

棒グラフ

下記は基本的な棒グラフのサンプルコードです。

#!/usr/bin/env python
from pylab import *

figure(1)
y = [15, 30, 45, 10, -5]
x = np.array([1, 2, 3, 4, 5])

bar(x, y, align = "center")
grid(True)
show()

すると下記のような棒グラフを書くことができます。

 

横方向の時系列状態グラフ

等高線グラフ

contour関数を使います。

4つ目の引数は等高線の数で、

数を増やすと、

細かく等高線を書くことができます。

#!/usr/bin/python
# -*- coding: utf-8 -*-
import matplotlib.pyplot as plt
import numpy as np

delta = 0.1
minXY=-5.0
maxXY=5.0
nContour=50

def HimmelblauFunction(x,y):
    return (x**2+y-11)**2+(x+y**2-7)**2

def CreateMeshData():
    x = np.arange(minXY, maxXY, delta)
    y = np.arange(minXY, maxXY, delta)
    X, Y = np.meshgrid(x, y)
    Z=[HimmelblauFunction(x,y) for (x,y) in zip(X,Y)]
    return(X,Y,Z)

(X,Y,Z)=CreateMeshData()
CS = plt.contour(X, Y, Z,nContour)
plt.show()

するとこのようなグラフが書けます。

 

また、

下記のようにclabel関数を呼ぶと、

CS = plt.contour(X, Y, Z,nContour)
plt.clabel(CS, inline=1, fontsize=10)

等高線にそれぞれの値を数字で記入してれます。

 

 

三次元プロット

 

下記は基本的な三次元プロットのサンプルコードです。

Axes3Dを使うことで、

通常の二次元plotと同じように

三次元プロットをすることができます。

#!/usr/bin/env python
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np

def AxisEqual3d(x,y,z):
    #for 3d axis equal
    max_range = np.array([x.max()-x.min(), y.max()-y.min(), z.max()-z.min()]).max()
    Xb = 0.5*max_range*np.mgrid[-1:2:2,-1:2:2,-1:2:2][0].flatten() + 0.5*(x.max()+x.min())
    Yb = 0.5*max_range*np.mgrid[-1:2:2,-1:2:2,-1:2:2][1].flatten() + 0.5*(y.max()+y.min())
    Zb = 0.5*max_range*np.mgrid[-1:2:2,-1:2:2,-1:2:2][2].flatten() + 0.5*(z.max()+z.min())
    for xb, yb, zb in zip(Xb, Yb, Zb):
        ax.plot([xb], [yb], [zb], 'w')


x=np.array([0,2,4])
y=np.array([0,2,4])
z=np.array([1,3,5])

fig2 = plt.figure()
ax = Axes3D(fig2)
ax.plot3D(x,y,z,"-*r")
ax.set_xlabel("x[m]")
ax.set_ylabel("y[m]")
ax.set_zlabel("z[m]")
AxisEqual3d(x,y,z)
plt.show()

一つ注意点として、三次元プロットでは、

axis("equal")しても三軸の座標軸はサイズが合いません、

そんな時は上記のようなAxisEqual3d(x,y,z)を使うことで、

無理やり座標系を合わせることができます。

 

また、残念ながら自分のMacでは

上記の3次元プロットは表示できませんでした。

WindowsとUbuntuはOKでした。

 

ヒストグラム

下記は基本的なヒストグラムのサンプルコードです。

#!/usr/bin/env python
from pylab import *
import numpy as np

figure(1)
x = np.random.normal(size = 100)

hist(x)
title("Histgram")
xlabel("x")
ylabel("frequency")
show()

すると下記のようなヒストグラムを書くことができます。

 

ちなみに

hist(x, normed = True)

とすると、ヒストグラムの縦軸を正規化することができます。

円グラフ

下記は基本的な円グラフのサンプルコードです。

#!/usr/bin/env python
from pylab import *

labels = ['Frogs', 'Hogs', 'Dogs', 'Logs']
fracs = [15, 30, 45, 10]

figure(1)
pie(fracs, labels=labels, autopct='%1.1f%%', shadow=True)

savefig('pie_demo')
show()

すると、下記のような円グラフを書くことができます。

 

autopctは割合を円グラフに表示する引数です。

またsavefigでグラフを保存することができます。  

グラフに水平線・垂直線を引く

axvlineとaxhlineという関数を使いましょう。

import numpy as np
import matplotlib.pyplot as plt

x = np.random.normal(size=100)
y = np.random.normal(size=100)
plt.plot(x,y,'g.')
plt.axvline(x=1, color='red')
plt.axhline(y=2, color='blue')
plt.show()

箱ひげ図

複数のヒストグラムをまとめてわかりやすく表現するには、

箱ひげ図を使うと便利です。

matplotlibでは、boxplotという関数を使うことで箱ひげ図を書くことができます。

matplotlib.org

 

import numpy as np
import maplotlib.pyplot as plt
data = np.random.randn(100)
plt.boxplot(data)
plt.show()

一つ注意点として、boxplotは外れ値を自動的に除去するので、

そこは注意が必要です。詳細は公式ドキュメントを参照ください。

 

pandasのdataframeのデータから箱ひげ図を作る場合は、

daraframeから直接boxplot関数を呼ぶことで、箱ひげ図を書くことができます。

pandas.pydata.org

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(1234)
df = pd.DataFrame(np.random.randn(10, 4),
               columns=['Col1', 'Col2', 'Col3', 'Col4'])
boxplot = df.boxplot(column=['Col1', 'Col2', 'Col3'])
plt.show()

 

簡単なGUIツールを作成する方法

あまり知られていませんが、

matplotlibのみで、簡単なGUIツールも作ることができます。

ボタンを作る

上記のサンプルコードを実行すると、

下記のようなボタン付きのグラフを作ることができます。

このサンプルでは、

NextとPreviousのボタンでグラフのレンジを変更できます。

チェックボタンを作る

上記のサンプルコードを実行すると、

下記のように

チェックボタンで描画するグラフを選ぶグラフを作れます。

カーソルの位置を取得し表示

上記のサンプルコードを実行すると、

下記のように

カーソルの位置を取得して表示することができます。

 

グラフ調整のtips

matplotlibのグラフは、

図の下の十字矢印を使うと、

描画部分を水平移動したり、

虫眼鏡のボタンを押すと

ズーム・インできます。

 

ちなみにズームモードで、

ctrlキーを押しながら、ズームすると

ズームアウトできます。

地味便利です。

 

指定した領域のデータを抽出する

上記のサンプルコードを実行すると、

下記のようにクリックしながら、

マウスで書いた領域の中の

データを抽出することができます。

 

メニューボタンを作る

上記のサンプルコードを実行すると、

下記のように、メニューリストをグラフ内に表示することができ、

それらのボタンを押すことでプログラムを制御することができます。

 

ラジオボタンの配置

上記のサンプルコードを実行すると、

下記のように、ラジオボタンをグラフ内に配置することができ、

それらのボタンを押すことでプログラムを制御することができます。

 

スライダーの配置

上記のサンプルコードを実行すると、

下記のように、スライダーをグラフ内に配置することができ、

それらのスライダーを調整することでプログラムを制御することができます。

 

matplotlibでアニメーションを作る

MATLABの可視化機能の中で

最も素晴らしいものの一つは

簡単にアニメーションを作ることができる所です。

 

matplotlibでも同じように

通常のプロット関数を複数回呼ぶことで、

アニメーションを作ることができます。

下記のサンプルコードを起動すると、

Sinカーブがアニメーションで描画されます。

fig, ax = plt.subplots(1, 1)
x=0
y=np.sin(x)

while True:
        # plotデータの更新
        x += 0.1
        y = np.sin(x)
        ax.plot(x,y,".r")
        plt.pause(.01)#描画するまでの時間[sec]

 

アニメーションを動画として保存する

matplotlibのanimationモジュールを使うと、

簡単にアニメーションを動画として保存できます。

 

下記のサンプルのように

plotのフレームをリストにし、

それをArtistAnimation関数に渡し、

アニメーションオブジェクトを作成します。

あとはSave関数でそのアニメーションを

動画として保存することができます。

 

from pylab import *
import matplotlib.pyplot as plt
import matplotlib.animation as animation

fig = plt.figure()
xlist = range(1, 700)
frame_list = []
xl=[]
yl=[]

for x in xlist:
    xl.append(x)
    yl.append(sin(x*3.14/180))
    one_frame = plot(xl, yl)
    frame_list.append(one_frame)

ani = animation.ArtistAnimation(fig, frame_list, interval = 40, repeat_delay = 20)
ani.save("animation.mp4")

 

すると下記のようなサインカーブが伸びる

アニメーションのmp4ファイルが出来ているはずです。

 

ちなみにMacの場合は動画ファイルを作るのに

ffmepgが必要とのことだったので、

下記のコマンドでインストールしました。

brew install ffmpeg

 

また、上記のpauseを使った方法で

アニメーションを作っている場合、

上記の手法ではかなりコードを変更する必要があります。

そんな時は、下記のツールを使いましょう。

myenigma.hatenablog.com

 

MATLABとmatplotlibの相違点

簡単に表にまとめておきます。

MATLAB matplotlib
グラフの表示 plot関数 plot関数+show関数
線の太さの設定 plot(a,b,LineWidth,10) plot(a,b,lw=10)
凡例の設定 legend("a","b") plot関数のlabel引数で設定して、legend() or リストで渡す legend(["velo"])
グラフ罫線の設定 grid on grid(True)
座標軸の非表示 axis off axis("off")
座標軸のスケールを合わせる axis equal axis("equal")
タイトルの設定 title("hoge") set_title("hoge)
x軸のタイトルの設定 xlabel("hoge") set_xlabel("hoge)
y軸のタイトルの設定 ylabel("hoge") set_ylabel("hoge)
x軸の表示範囲 axis([0 0 1 1]) ax.set_xlim(0, 50)
y軸の表示範囲 axis([0 0 1 1]) ax.set_ylim(0, 50)

 

複数のグラフを生成する

一つのスクリプトで、

複数のグラフを書きたい時は、

それぞれのグラフを書く前に、

下記のコマンドでグラフと軸のオブジェクトを作成し、

その後plot関数を呼べば、

複数のグラフを作成することができます。

#plot1
fig, ax=plt.subplots(1)
plot(x1)

#plot2
fig, ax=plt.subplots(1)
plot(x2)

plt.show()

  

C++のコードからmatplotlibの機能を使う

こちらの記事を参照下さい

myenigma.hatenablog.com

 

ブラウザ上でmatplotlibのグラフを表示する

matplotlibのバックエンドとして、"webagg"を使うと、

matplotlibのグラフをブラウザ上で表示してくれます。

matplotlib.org

progmemo114.hatenablog.com

 

下記のように、backendをwebaggとして、

普通にplotすると、

import matplotlib
matplotlib.use('WebAgg')

import matplotlib.pyplot as plt
import numpy as np


def main():
    x = np.arange(-10, 10)
    y = x * x
    y2 = x * 3
    y3 = x * 4

    plt.subplots()
    plt.plot(x, y)

    plt.subplots()
    plt.plot(x, y2)

    plt.subplots()
    plt.plot(x, y3)

    plt.show()


if __name__ == '__main__':
    main

ブラウザが自動的に立ち上がって、

グラフが表示されます。

 

複数のグラフを並べて、表示してくれるところや、

ブラウザ上でも、ズームなどが動くところが非常に便利です。

また、webサーバとして立ち上がるので、

スマホからアクセスしたり、他の人の簡単にグラフを共有することもできます。

簡単なダッシュボードもどきとしても使えそうです。

(ただ、前述のpauseを使ったアニメーションは残念ながら動きませんでした)

 

参考資料

myenigma.hatenablog.com

myenigma.hatenablog.com

myenigma.hatenablog.com

myenigma.hatenablog.com

myenigma.hatenablog.com

myenigma.hatenablog.com

 

MyEnigma Supporters

もしこの記事が参考になり、

ブログをサポートしたいと思われた方は、

こちらからよろしくお願いします。

myenigma.hatenablog.com