matplotlibのグラフ上にマウスカーソルに合わせて動く十字のカーソルを表示するMultiCursorというものがありますが、 twinx()してY2軸を利用すると奇妙なことがおこりました。
カーソルは、Y軸に描画されながらも、その表示位置はY2軸上の値になるという状態です。
もちろん、カーソルを描画する対象をY2軸のほうにすると矛盾のない状態にはなります。
そもそもMultiCursorを利用する対象にY2軸を追加するような利用の仕方は、あまりなさそうです。そうはいっても、そのような要求があったため、Y2軸を追加しても、カーソル位置は、Y軸のほうで決まるようにしてみました。
マウス移動のイベントを処理するonmove()に渡されるeventからキャンバス上のx,y座標が得られるので、それを利用してグラフ軸上のデータに焼きなおすようにしました。
使い方はオリジナルのMultiCursorとほぼ同じですが、parentウィンドウを渡すようにして、そちらへ座標を通知するイベントをポストしています。parentウィンドウでそのイベントを拾えば、カーソル移動にあわせて座標位置を表示できます。
from matplotlib.widgets import MultiCursor
import wx
import wx.lib.newevent
class MyMultiCursor(MultiCursor):
def __init__(self, parent, canvas, axes, color='r', lw=1,
useblit = True, horizOn=True, vertOn=True):
if matplotlib.__version__ >= '1.3.0':
MultiCursor.__init__(self, canvas, axes, color=color,
lw=lw, useblit=useblit, horizOn=horizOn, vertOn=vertOn)
else:
MultiCursor.__init__(self, canvas, axes, color=color, lw=lw, useblit=useblit)
# Produce New Event for Cursor Move Notification to parent window.
self.parent = parent
self.CursorMoveEvent, self.EVT_CURSOR_MOVE = wx.lib.newevent.NewEvent()
self.visible = False
def xydata(self, x, y):
#make new xdata, ydata
cwidth, cheight = self.canvas.GetSize()
target = None
for ax in self.axes:
#find the axes in which the mouse cursor is.
bbox = ax.get_position()
[[left,bottom], [right, top]] = bbox.get_points()
xc = (x+1)/float(cwidth)
yc = y/float(cheight)
if ((left < xc) and (xc < right) and
(bottom < yc) and (yc < top)):
target = ax
break
if not target:
# if there is no target
return (None, None)
width = right-left
height =top-bottom
xmin, xmax = ax.get_xlim()
ymin, ymax = ax.get_ylim()
xdata = xmin + (xc - left) * (xmax - xmin)/width
ydata = ymin + (yc - bottom) * (ymax - ymin)/height
return (xdata, ydata)
def onmove(self, event):
event.xdata, event.ydata = self.xydata(event.x, event.y)
MultiCursor.onmove(self, event)
#make event data
evt = self.CursorMoveEvent(pos = (event.xdata, event.ydata))
#post event to parent window
wx.PostEvent(self.parent, evt)
self.visible = True
0 件のコメント:
コメントを投稿