morikomorou’s blog

自分が学んだことなどの備忘録的なやつ

【python】キー操作でグラフ上の点の値を取得する

はじめに

キー操作でmatplotlibのグラフをいろいろ操作できるようにする方法について解説します。
マウス操作でグラフをインタラクティブに描画する方法については下記を参照ください。

今回の例として作成するのは、矢印キーでカーソルを左右に動かし、グラフ上の点の座標を次々取得していくというものです。
本記事で以下を実装していきます。

それではやっていきましょう。




キーイベントの紐づけ

キーを入力したら何かしらの操作をできるようにしたいので、'key_press_event'を使用します。
使い方とサンプルは公式ドキュメントに載っています。
matplotlib.backend_bases — Matplotlib 3.8.2 documentation
on_key(名前は何でもいいですが)という関数を定義してfigureと紐づけします。

def on_key(event):
    pass

cid = fig.canvas.mpl_connect('key_press_event', on_key)

折れ線グラフを描く

まずはキー操作で値を取得するためのグラフを描いていきます。
ランダムな折れ線グラフを作成しましょう。

import matplotlib.pyplot as plt
import numpy as np

fig, ax = plt.subplots()
x = np.arange(21)
y = np.random.rand(21)
ax.set_xlim([0, 20])
ax.set_ylim([0, 1])
ax.plot(x, y, "o-",picker=15)

plt.show()

以下のようなグラフが出力されます。

入力ボタンを取得する

次にキー入力を試してみます。
どのボタンが押されたかはevent.keyで取得できるので、コマンドラインに出力して動作を確認してみます。

import matplotlib.pyplot as plt
import numpy as np

fig, ax = plt.subplots()
x = np.arange(21)
y = np.random.rand(21)
ax.set_xlim([0, 20])
ax.set_ylim([0, 1])
ax.plot(x, y, "o-",picker=15)

def on_key(event):
    print(event.key)    # 押されたkeyの出力

fig.canvas.mpl_connect('key_press_event', on_key)
plt.show()

以下のようにコマンドラインに押したキーの名前が表示されます。

right
left
right
left
up
down
d
s
d
s
a
e
r

矢印キーはそれぞれright, left, up, downという名前でevent.keyで受け取れるみたいですね。

グラフの要素上にカーソルを表示する

矢印キーで動かすためのカーソルを表示します。

上の記事でヘアラインを表示する方法について触れたので、そのコードを使ってカーソルを表示します。
プロット点のインデックス3にカーソルを合わせて表示してみます。

import matplotlib.pyplot as plt
import numpy as np

fig, ax = plt.subplots()
x = np.arange(21)
y = np.random.rand(21)
n = len(x)
ax.set_xlim([0, 20])
ax.set_ylim([0, 1])
ind = 3    # カーソル位置のインデックス
cur_v = ax.axvline(x[ind], color='k', linestyle='--', linewidth=0.5)
cur_h = ax.axhline(y[ind], color='k', linestyle='--', linewidth=0.5)
ax.plot(x, y, "o-",picker=15)
cur_point, = ax.plot(x[ind], y[ind], color='k', markersize=10, marker='o')
ax.set_title('index: {}, x = {}, y = {}'.format(
                                ind, round(x[ind], 4), round(y[ind], 4)))


def on_key(event):
    print(event.key)

fig.canvas.mpl_connect('key_press_event', on_key)
plt.show()

実行結果は下記のとおりです。




カーソルとキーを連動させる

最後に、カーソルとキーとの連動を実装します。
on_key関数内でevent.keyに入力された値をトリガーにして右矢印キーで次のインデックスの座標へ移動、左矢印キーで前のインデックスの座標へ移動させます。
グラフの端まで行ったら反対側の端から戻ってくるように実装しています。

import matplotlib.pyplot as plt
import numpy as np

fig, ax = plt.subplots()
x = np.arange(21)
y = np.random.rand(21)
n = len(x)
ax.set_xlim([0, 20])
ax.set_ylim([0, 1])
ind = 3    # カーソル位置のインデックス
cur_v = ax.axvline(x[ind], color='k', linestyle='--', linewidth=0.5)
cur_h = ax.axhline(y[ind], color='k', linestyle='--', linewidth=0.5)
ax.plot(x, y, "o-",picker=15)
cur_point, = ax.plot(x[ind], y[ind], color='k', markersize=10, marker='o')
ax.set_title('index: {}, x = {}, y = {}'.format(
                                ind, round(x[ind], 4), round(y[ind], 4)))


def on_key(event):
    global ind
    if event.key == 'right':
        move = 1
    elif event.key == 'left':
        move = -1
    else:
        return

    # インデックスの更新
    ind += move
    ind %= n  # グラフの端に行くと戻るようにする

    # カーソルとタイトルの更新
    cur_v.set_xdata(x[ind])
    cur_h.set_ydata(y[ind])
    cur_point.set_data(x[ind], y[ind])
    ax.set_title('index: {}, x = {}, y = {}'.format(
                                    ind, round(x[ind], 4), round(y[ind], 4)))
    plt.draw()

fig.canvas.mpl_connect('key_press_event', on_key)
plt.show()

実行結果は以下のようになります。

おわりに

キー入力によるグラフ操作の方法について勉強してみました。
今回の例ではキー入力だけでカーソルを動かしていましたが、これまでの記事で取り扱ったマウスイベントやピックイベントをつかって、キー入力とマウス操作を合わせてグラフの値を取得できるように改造していきたいですね。