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鼠标十字光标内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!