LoginSignup
183
173

More than 3 years have passed since last update.

matplotlibでインタラクティブにプロットしたいんじゃ

Last updated at Posted at 2019-07-05

はじめに

Pythonのmatplotlibを使うと簡単にインタラクティブなプロットができます。特に、グラフの座標の値を容易にとってこれるので、実験やシミュレーション結果の簡易ビューワの作成に適しています。

参考文献

Event handling and picking

動作確認

matplotib : '2.2.2'
backend : MacOSX or Qt5Agg

イベントとコールバック関数

こちらが用意されてるイベントの一覧です。
Screen Shot 2019-07-05 at 18.41.51.png

イベントにコールバック関数を紐付けるだけでインタラクティブなプロットができます。例えば、マウスをクリックしたときにonclick関数を呼ぶには下記のように書きます。

def onclick(event):
  pass

fig = plt.figure()
fig.canvas.mpl_connect('button_press_event', onclick)

ちなみにこれでもいけます。

def onclick(event):
   pass

plt.figure()
plt.connect('button_press_event', onclick)

マウスカーソルの位置に点を描画

event.xdataでマウスカーソルのx軸の値を、event.ydataでマウスカーソルのy軸の値をとってこれます。マウスカーソルの位置に点を描画するコードが下記になります。

import matplotlib.pyplot as plt 

def motion(event):  
    x = event.xdata
    y = event.ydata

    ln.set_data(x,y)
    plt.draw()

plt.figure()
ln, = plt.plot([],[],'x')

plt.connect('motion_notify_event', motion)
plt.show()

Jul-05-2019 19-00-18.gif

軸の外にマウスカーソルがあるとevent.xdataevent.ydataにはNoneが入るので,

def motion(event):  
    if (event.xdata is  None) or (event.ydata is  None):
        return

などと書いて除きます。

マウスカーソルの位置に縦線や横線を引く

axvlineaxhlineで縦線や横線が引けます。戻り値はリストではなくmatplotlib.lines.Line2Dオブジェクトです(plt.plotの戻り値はリスト)。set_xdataset_ydataとすることで、xやyの値だけ更新できます。

import matplotlib.pyplot as plt 

def motion(event):  
    x = event.xdata
    y = event.ydata
    ln_v.set_xdata(x)
    ln_h.set_ydata(y)
    plt.draw()

plt.figure()
ln_v = plt.axvline(0)
ln_h = plt.axhline(0)

plt.connect('motion_notify_event', motion)
plt.show()

Jul-05-2019 19-19-22.gif

subplotでもインタラクティブ・プロット

event.inaxesでマウスカーソルがのっている軸のAxesインスタンスがとってこれるので, subplotの軸毎に別々の処理をさせたい時は下記のように書きます。

import matplotlib.pyplot as plt 

def motion(event):  
    x = event.xdata
    y = event.ydata
    if event.inaxes == ax1:
        ln_1.set_data(x,y)
    if event.inaxes == ax2:
        ln_2.set_data(x,y)
    plt.draw()

plt.figure()
ax1 = plt.subplot(1,2,1)
ln_1, = plt.plot([],[],'o')

ax2 = plt.subplot(1,2,2)
ln_2, = plt.plot([],[],'x')

plt.connect('motion_notify_event', motion)
plt.show()

Jul-05-2019 19-35-22.gif

プロットした点を動かしたい

pick_eventを使うとプロットしたオブジェクトをとってこれます。 このときpickerプロパティに許容する範囲を指定する必要があります。

plt.plot(0, 0, "o", picker=15)

event.artistpick_eventを発生させたArtistになります。

def onpick(event):
    plt.title(event.artist)

plt.connect('pick_event', onpick)

プロットした点を動かすコードです。

import matplotlib.pyplot as plt 

def motion(event):
    global gco
    if gco is None:
        return
    x = event.xdata
    y = event.ydata
    gco.set_data(x,y)
    plt.draw()

def onpick(event):
    global gco
    gco = event.artist
    plt.title(gco)

def release(event):
    global gco
    gco = None

gco = None
plt.figure()

plt.plot(0,0,"o",picker=15)
plt.plot(1,0,"o",picker=15)

plt.connect('motion_notify_event', motion)
plt.connect('pick_event', onpick)
plt.connect('button_release_event', release)
plt.show()

Jul-05-2019 19-54-27.gif

左クリック、右クリック、ダブルクリック (追記)

button_press_eventだと、左クリックをしたときはevent.buttonが1に, 右クリックをしたときはevent.buttonが3になっています。またダブルクリックしたときはevent.dblclickが1になっています。

import matplotlib.pyplot as plt 

def motion(event):  
    if event.dblclick == 1:
        plt.title("double click")

    elif event.button == 1:
        plt.title("left click")

    elif event.button == 3:
        plt.title("right click")

    plt.draw()

plt.figure()
plt.connect('button_press_event', motion)
plt.show()

Jul-06-2019 22-48-34.gif

ドラッグ中にだけ更新 (追記)

motion_notify_eventの場合では、左クリックしながら動かす(つまりドラッグする)と、event.buttonが1なっているので、ドラッグ中にだけプロットしたいときは下記のように書きます。

import matplotlib.pyplot as plt 

def motion(event):  
    if event.button == 1:
        x = event.xdata
        y = event.ydata

        ln.set_data(x,y)
    plt.draw()

plt.figure()
ln, = plt.plot([],[],'x')
plt.connect('motion_notify_event', motion)
plt.show()

Jul-06-2019 23-05-58.gif

手元の環境では、matplotlibのbackendがMacOSXの場合、上記のように書かなくてもドラッグ中にしかプロットされませんでした。

183
173
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
183
173