【Python】【Matplotlib】マウスカーソルに追従する十字線を表示する

matplotlib,python

はじめに

Matplotlibの2次元グラフ上でマウスカーソルに追従する十字線(カーソル)を表示する方法について調べてみました。そのメモです。

カーソルを表示する方法

カーソルを表示するには、Cursorオブジェクトを作成、表示したいAxesオブジェクトと結びつけます。

from matplotlib.widgets import Cursor

cursor = Cursor(ax)

Cursorクラスのコンストラクタに渡すことができる引数は以下です。

引数説明
axカーソルを表示するAxesオブジェクト
horizOn水平の線を表示するかどうか(TrueでON。デフォルトTrue
vertOn垂直の線を表示するかどうか(TrueでON。デフォルトTrue
useblit描画を高速化する場合はTrue。デフォルトFalse
**lineprops線の設定(Line2Dオブジェクトで指定可能な値。こちらを参照)

カーソルの表示/非表示を切り替える

カーソルの表示/非表示を切り替えるには、visibleプロパティにTrueまたはFalseを設定するだけです。以下の例ではカーソルを非表示にします。

cursor.visible = False

カーソル座標の取得

カーソルの座標を取得するには、以前出てきたmpl_connect()を使います。'motion_notify_event'を指定することで、マウスカーソルが移動するたびに登録したイベントハンドラが呼び出されます。ただ、グラフの外でマウスカーソルが移動してもイベントハンドラが呼び出されるので、ハンドラの中でグラフの中にあるかどうかを判定する必要があります。

def on_cursor_move(event):
    if event.inaxes is ax:
      # カーソルがグラフ内の時の処理

グラフ上の座標を取得するには、event.xdataevent.ydataを使用します。

実装例

Matplotlibで作成したグラフに十字線のカーソルを表示する例を以下に示します。今回はTkinterも使い、グラフ座標におけるカーソル位置を表示したり、カーソル自体のON/OFFを切り替えられるようにしました。

import random
import tkinter as tk
from matplotlib import pyplot as plt
from matplotlib.widgets import Cursor
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

def generate_xy():
    """ランダムに100点生成する"""
    x = []
    y = []

    for i in range(0, 100):
        x.append(random.random())
        y.append(random.random())

    return (x, y)

def on_cursor_move(event):
    if event.inaxes is ax and cursor.visible:
        cpos_str = "({:.2f}, {:.2f})".format(event.xdata, event.ydata)
    else:
        cpos_str = "(---, ---)"

    cursor_pos.config(text=cpos_str)

def on_click_radiobutton():
    cursor.visible = var.get()

root = tk.Tk()
root.geometry("640x480")
root.title("Matplotlib Cross Cursor Test")

frame = tk.Frame(root)
frame.pack(expand=True, fill=tk.BOTH)

frame1 = tk.Frame(frame)
frame2 = tk.Frame(frame)
frame2.pack(side="bottom")
frame1.pack(expand=True, fill=tk.BOTH)

cursor_pos = tk.Label(master=frame2, text="(---, ---)")
cursor_pos.grid(column=1, row=1)

var = tk.BooleanVar(value=True)
rad1 = tk.Radiobutton(frame2, text="on", variable=var, value=True, command=on_click_radiobutton)
rad2 = tk.Radiobutton(frame2, text="off", variable=var, value=False, command=on_click_radiobutton)
rad1.grid(column=2, row=1)
rad2.grid(column=3, row=1)

x, y = generate_xy()

fig = plt.Figure()
ax = fig.add_subplot(111)
ax.scatter(x, y)

cursor = Cursor(ax, useblit=True, color='red', linewidth=1)

fig.canvas.mpl_connect('motion_notify_event', on_cursor_move)

canvas = FigureCanvasTkAgg(figure=fig, master=frame)
canvas.get_tk_widget().pack(expand=True, fill=tk.BOTH)

root.mainloop()

まとめ

Matplotlibでグラフ上にマウスに追従する十字線(カーソル)を表示する方法について調べてみました。基本的にはCursorオブジェクトを生成し、表示したいAxesオブジェクトに結びつけるだけで表示可能です。

また、mpl_connetct()を使ってカーソルの座標を取得したり、GUIと組み合わせてカーソルの表示/非表示を切り替えたりすることも可能です。

matplotlib,python

Posted by izadori