matplotlib绘制鼠标的十字光标的实现(自定义方式,官方实例)
matplotlib在widgets模块提供Cursor类用于支持十字光标的生成。另外官方还提供了自定义十字光标的实例。
widgets模块Cursor类源码
classCursor(AxesWidget):
"""
Acrosshaircursorthatspanstheaxesandmoveswithmousecursor.
Forthecursortoremainresponsiveyoumustkeepareferencetoit.
Parameters
----------
ax:`matplotlib.axes.Axes`
The`~.axes.Axes`toattachthecursorto.
horizOn:bool,default:True
Whethertodrawthehorizontalline.
vertOn:bool,default:True
Whethertodrawtheverticalline.
useblit:bool,default:False
Useblittingforfasterdrawingifsupportedbythebackend.
OtherParameters
----------------
**lineprops
`.Line2D`propertiesthatcontroltheappearanceofthelines.
Seealso`~.Axes.axhline`.
Examples
--------
See:doc:`/gallery/widgets/cursor`.
"""
def__init__(self,ax,horizOn=True,vertOn=True,useblit=False,
**lineprops):
AxesWidget.__init__(self,ax)
self.connect_event('motion_notify_event',self.onmove)
self.connect_event('draw_event',self.clear)
self.visible=True
self.horizOn=horizOn
self.vertOn=vertOn
self.useblit=useblitandself.canvas.supports_blit
ifself.useblit:
lineprops['animated']=True
self.lineh=ax.axhline(ax.get_ybound()[0],visible=False,**lineprops)
self.linev=ax.axvline(ax.get_xbound()[0],visible=False,**lineprops)
self.background=None
self.needclear=False
defclear(self,event):
"""Internaleventhandlertoclearthecursor."""
ifself.ignore(event):
return
ifself.useblit:
self.background=self.canvas.copy_from_bbox(self.ax.bbox)
self.linev.set_visible(False)
self.lineh.set_visible(False)
defonmove(self,event):
"""Internaleventhandlertodrawthecursorwhenthemousemoves."""
ifself.ignore(event):
return
ifnotself.canvas.widgetlock.available(self):
return
ifevent.inaxes!=self.ax:
self.linev.set_visible(False)
self.lineh.set_visible(False)
ifself.needclear:
self.canvas.draw()
self.needclear=False
return
self.needclear=True
ifnotself.visible:
return
self.linev.set_xdata((event.xdata,event.xdata))
self.lineh.set_ydata((event.ydata,event.ydata))
self.linev.set_visible(self.visibleandself.vertOn)
self.lineh.set_visible(self.visibleandself.horizOn)
self._update()
def_update(self):
ifself.useblit:
ifself.backgroundisnotNone:
self.canvas.restore_region(self.background)
self.ax.draw_artist(self.linev)
self.ax.draw_artist(self.lineh)
self.canvas.blit(self.ax.bbox)
else:
self.canvas.draw_idle()
returnFalse
自定义十字光标实现
简易十字光标实现
首先在Cursor类的构造方法__init__中,构造了十字光标的横线、竖线和坐标显示;然后在on_mouse_move方法中,根据事件数据更新横竖线和坐标显示,最后在调用时,通过mpl_connect方法绑定on_mouse_move方法和鼠标移动事件'motion_notify_event'。
importmatplotlib.pyplotasplt
importnumpyasnp
classCursor:
"""
Acrosshaircursor.
"""
def__init__(self,ax):
self.ax=ax
self.horizontal_line=ax.axhline(color='k',lw=0.8,ls='--')
self.vertical_line=ax.axvline(color='k',lw=0.8,ls='--')
#textlocationinaxescoordinates
self.text=ax.text(0.72,0.9,'',transform=ax.transAxes)
defset_cross_hair_visible(self,visible):
need_redraw=self.horizontal_line.get_visible()!=visible
self.horizontal_line.set_visible(visible)
self.vertical_line.set_visible(visible)
self.text.set_visible(visible)
returnneed_redraw
defon_mouse_move(self,event):
ifnotevent.inaxes:
need_redraw=self.set_cross_hair_visible(False)
ifneed_redraw:
self.ax.figure.canvas.draw()
else:
self.set_cross_hair_visible(True)
x,y=event.xdata,event.ydata
#updatethelinepositions
self.horizontal_line.set_ydata(y)
self.vertical_line.set_xdata(x)
self.text.set_text('x=%1.2f,y=%1.2f'%(x,y))
self.ax.figure.canvas.draw()
x=np.arange(0,1,0.01)
y=np.sin(2*2*np.pi*x)
fig,ax=plt.subplots()
ax.set_title('Simplecursor')
ax.plot(x,y,'o')
cursor=Cursor(ax)
#关键部分,绑定鼠标移动事件处理
fig.canvas.mpl_connect('motion_notify_event',cursor.on_mouse_move)
plt.show()
优化十字光标实现
在简易实现中,每次鼠标移动时,都会重绘整个图像,这样效率比较低。
在优化实现中,每次鼠标移动时,只重绘光标和坐标显示,背景图像不再重绘。
importmatplotlib.pyplotasplt
importnumpyasnp
classBlittedCursor:
"""
Acrosshaircursorusingblittingforfasterredraw.
"""
def__init__(self,ax):
self.ax=ax
self.background=None
self.horizontal_line=ax.axhline(color='k',lw=0.8,ls='--')
self.vertical_line=ax.axvline(color='k',lw=0.8,ls='--')
#textlocationinaxescoordinates
self.text=ax.text(0.72,0.9,'',transform=ax.transAxes)
self._creating_background=False
ax.figure.canvas.mpl_connect('draw_event',self.on_draw)
defon_draw(self,event):
self.create_new_background()
defset_cross_hair_visible(self,visible):
need_redraw=self.horizontal_line.get_visible()!=visible
self.horizontal_line.set_visible(visible)
self.vertical_line.set_visible(visible)
self.text.set_visible(visible)
returnneed_redraw
defcreate_new_background(self):
ifself._creating_background:
#discardcallstriggeredfromwithinthisfunction
return
self._creating_background=True
self.set_cross_hair_visible(False)
self.ax.figure.canvas.draw()
self.background=self.ax.figure.canvas.copy_from_bbox(self.ax.bbox)
self.set_cross_hair_visible(True)
self._creating_background=False
defon_mouse_move(self,event):
ifself.backgroundisNone:
self.create_new_background()
ifnotevent.inaxes:
need_redraw=self.set_cross_hair_visible(False)
ifneed_redraw:
self.ax.figure.canvas.restore_region(self.background)
self.ax.figure.canvas.blit(self.ax.bbox)
else:
self.set_cross_hair_visible(True)
#updatethelinepositions
x,y=event.xdata,event.ydata
self.horizontal_line.set_ydata(y)
self.vertical_line.set_xdata(x)
self.text.set_text('x=%1.2f,y=%1.2f'%(x,y))
self.ax.figure.canvas.restore_region(self.background)
self.ax.draw_artist(self.horizontal_line)
self.ax.draw_artist(self.vertical_line)
self.ax.draw_artist(self.text)
self.ax.figure.canvas.blit(self.ax.bbox)
x=np.arange(0,1,0.01)
y=np.sin(2*2*np.pi*x)
fig,ax=plt.subplots()
ax.set_title('Blittedcursor')
ax.plot(x,y,'o')
blitted_cursor=BlittedCursor(ax)
fig.canvas.mpl_connect('motion_notify_event',blitted_cursor.on_mouse_move)
plt.show()
捕捉数据十字光标实现
在前面的两种实现中,鼠标十字光标可以随意移动。在本实现中,十字光标只会出现在离鼠标x坐标最近的数据点上。
importmatplotlib.pyplotasplt
importnumpyasnp
classSnappingCursor:
"""
Acrosshaircursorthatsnapstothedatapointofaline,whichis
closesttothe*x*positionofthecursor.
Forsimplicity,thisassumesthat*x*valuesofthedataaresorted.
"""
def__init__(self,ax,line):
self.ax=ax
self.horizontal_line=ax.axhline(color='k',lw=0.8,ls='--')
self.vertical_line=ax.axvline(color='k',lw=0.8,ls='--')
self.x,self.y=line.get_data()
self._last_index=None
#textlocationinaxescoords
self.text=ax.text(0.72,0.9,'',transform=ax.transAxes)
defset_cross_hair_visible(self,visible):
need_redraw=self.horizontal_line.get_visible()!=visible
self.horizontal_line.set_visible(visible)
self.vertical_line.set_visible(visible)
self.text.set_visible(visible)
returnneed_redraw
defon_mouse_move(self,event):
ifnotevent.inaxes:
self._last_index=None
need_redraw=self.set_cross_hair_visible(False)
ifneed_redraw:
self.ax.figure.canvas.draw()
else:
self.set_cross_hair_visible(True)
x,y=event.xdata,event.ydata
index=min(np.searchsorted(self.x,x),len(self.x)-1)
ifindex==self._last_index:
return#stillonthesamedatapoint.Nothingtodo.
self._last_index=index
x=self.x[index]
y=self.y[index]
#updatethelinepositions
self.horizontal_line.set_ydata(y)
self.vertical_line.set_xdata(x)
self.text.set_text('x=%1.2f,y=%1.2f'%(x,y))
self.ax.figure.canvas.draw()
x=np.arange(0,1,0.01)
y=np.sin(2*2*np.pi*x)
fig,ax=plt.subplots()
ax.set_title('Snappingcursor')
line,=ax.plot(x,y,'o')
snap_cursor=SnappingCursor(ax,line)
fig.canvas.mpl_connect('motion_notify_event',snap_cursor.on_mouse_move)
plt.show()
参考资料
https://www.matplotlib.org.cn/gallery/misc/cursor_demo_sgskip.html
到此这篇关于matplotlib绘制鼠标的十字光标的实现(自定义方式,官方实例)的文章就介绍到这了,更多相关matplotlib鼠标十字光标内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!