路径编辑器
跨GUI共享事件。
此示例演示了使用Matplotlib事件处理与画布上的对象进行交互和修改对象的跨GUI应用程序。

import numpy as npimport matplotlib.path as mpathimport matplotlib.patches as mpatchesimport matplotlib.pyplot as pltPath = mpath.Pathfig, 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 = mpath.Path(verts, codes)patch = mpatches.PathPatch(path, facecolor='green', edgecolor='yellow', alpha=0.5)ax.add_patch(patch)class PathInteractor(object):"""An path editor.Key-bindings't' toggle vertex markers on and off. When vertex markers are on,you can move them, delete them"""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 vertcanvas.mpl_connect('draw_event', self.draw_callback)canvas.mpl_connect('button_press_event', self.button_press_callback)canvas.mpl_connect('key_press_event', self.key_press_callback)canvas.mpl_connect('button_release_event', self.button_release_callback)canvas.mpl_connect('motion_notify_event', self.motion_notify_callback)self.canvas = canvasdef draw_callback(self, event):self.background = self.canvas.copy_from_bbox(self.ax.bbox)self.ax.draw_artist(self.pathpatch)self.ax.draw_artist(self.line)self.canvas.blit(self.ax.bbox)def pathpatch_changed(self, pathpatch):'this method is called whenever the pathpatchgon object is called'# only copy the artist props to the line (except visibility)vis = self.line.get_visible()plt.Artist.update_from(self.line, pathpatch)self.line.set_visible(vis) # don't use the pathpatch visibility statedef get_ind_under_point(self, event):'get the index of the vertex under point if within epsilon tolerance'# display coordsxy = np.asarray(self.pathpatch.get_path().vertices)xyt = self.pathpatch.get_transform().transform(xy)xt, yt = xyt[:, 0], xyt[:, 1]d = np.sqrt((xt - event.x)**2 + (yt - event.y)**2)ind = d.argmin()if d[ind] >= self.epsilon:ind = Nonereturn inddef button_press_callback(self, event):'whenever a mouse button is pressed'if not self.showverts:returnif event.inaxes is None:returnif event.button != 1:returnself._ind = self.get_ind_under_point(event)def button_release_callback(self, event):'whenever a mouse button is released'if not self.showverts:returnif event.button != 1:returnself._ind = Nonedef key_press_callback(self, event):'whenever a key is pressed'if not event.inaxes:returnif event.key == 't':self.showverts = not self.showvertsself.line.set_visible(self.showverts)if not self.showverts:self._ind = Noneself.canvas.draw()def motion_notify_callback(self, event):'on mouse movement'if not self.showverts:returnif self._ind is None:returnif event.inaxes is None:returnif event.button != 1:returnx, y = event.xdata, event.ydatavertices = self.pathpatch.get_path().verticesvertices[self._ind] = x, yself.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()
