Note
Go to the endto download the full example code.
Path editor#
Sharing events across GUIs.
This example demonstrates a cross-GUI application using Matplotlib eventhandling to interact with and modify objects on the canvas.
Note
This example exercises the interactive capabilities of Matplotlib, and thiswill not appear in the static documentation. Please run this code on yourmachine to see the interactivity.
You can copy and paste individual parts, or download the entire exampleusing the link at the bottom of the page.

importmatplotlib.pyplotaspltimportnumpyasnpfrommatplotlib.backend_basesimportMouseButtonfrommatplotlib.patchesimportPathPatchfrommatplotlib.pathimportPathfig,ax=plt.subplots()pathdata=[(Path.MOVETO,(1.58,-2.57)),(Path.CURVE4,(0.35,-1.1)),(Path.CURVE4,(-1.75,2.0)),(Path.CURVE4,(0.375,2.0)),(Path.LINETO,(0.85,1.15)),(Path.CURVE4,(2.2,3.2)),(Path.CURVE4,(3,0.05)),(Path.CURVE4,(2.0,-0.5)),(Path.CLOSEPOLY,(1.58,-2.57)),]codes,verts=zip(*pathdata)path=Path(verts,codes)patch=PathPatch(path,facecolor='green',edgecolor='yellow',alpha=0.5)ax.add_patch(patch)classPathInteractor:""" A path editor. Press 't' to toggle vertex markers on and off. When vertex markers are on, they can be dragged with the mouse. """showverts=Trueepsilon=5# max pixel distance to count as a vertex hitdef__init__(self,pathpatch):self.ax=pathpatch.axescanvas=self.ax.figure.canvasself.pathpatch=pathpatchself.pathpatch.set_animated(True)x,y=zip(*self.pathpatch.get_path().vertices)self.line,=ax.plot(x,y,marker='o',markerfacecolor='r',animated=True)self._ind=None# the active vertexcanvas.mpl_connect('draw_event',self.on_draw)canvas.mpl_connect('button_press_event',self.on_button_press)canvas.mpl_connect('key_press_event',self.on_key_press)canvas.mpl_connect('button_release_event',self.on_button_release)canvas.mpl_connect('motion_notify_event',self.on_mouse_move)self.canvas=canvasdefget_ind_under_point(self,event):""" Return the index of the point closest to the event position or *None* if no point is within ``self.epsilon`` to the event position. """xy=self.pathpatch.get_path().verticesxyt=self.pathpatch.get_transform().transform(xy)# to display coordsxt,yt=xyt[:,0],xyt[:,1]d=np.sqrt((xt-event.x)**2+(yt-event.y)**2)ind=d.argmin()returnindifd[ind]<self.epsilonelseNonedefon_draw(self,event):"""Callback for draws."""self.background=self.canvas.copy_from_bbox(self.ax.bbox)self.ax.draw_artist(self.pathpatch)self.ax.draw_artist(self.line)defon_button_press(self,event):"""Callback for mouse button presses."""if(event.inaxesisNoneorevent.button!=MouseButton.LEFTornotself.showverts):returnself._ind=self.get_ind_under_point(event)defon_button_release(self,event):"""Callback for mouse button releases."""if(event.button!=MouseButton.LEFTornotself.showverts):returnself._ind=Nonedefon_key_press(self,event):"""Callback for key presses."""ifnotevent.inaxes:returnifevent.key=='t':self.showverts=notself.showvertsself.line.set_visible(self.showverts)ifnotself.showverts:self._ind=Noneself.canvas.draw()defon_mouse_move(self,event):"""Callback for mouse movements."""if(self._indisNoneorevent.inaxesisNoneorevent.button!=MouseButton.LEFTornotself.showverts):returnvertices=self.pathpatch.get_path().verticesvertices[self._ind]=event.xdata,event.ydataself.line.set_data(zip(*vertices))self.canvas.restore_region(self.background)self.ax.draw_artist(self.pathpatch)self.ax.draw_artist(self.line)self.canvas.blit(self.ax.bbox)interactor=PathInteractor(patch)ax.set_title('drag vertices to update path')ax.set_xlim(-3,4)ax.set_ylim(-3,4)plt.show()