4

首先尝试交互式绘图,因此欢迎提供任何帮助。

我正在尝试获取交互式 matplotlib 图,每次单击鼠标时都会绘制点。这些点将被绘制在点击的位置和图像的顶部。我想我已经弄清楚了如何做到这一点,但我想知道是否有一种简单的方法可以添加一个“撤消”按钮,以便我可以在需要时删除最后一个绘制的点。出于同样的想法,我还想添加“重置”(即删除所有点)和“保存”按钮。

from matplotlib import pyplot as plt

def onclick(event):
    button=event.button
    x=event.xdata
    y=event.ydata

    if button==1: plt.plot(x,y,'ro')
    if button!=1: plt.plot(x,y,'bo')
    print 'button=%d, x=%d, y=%d, xdata=%f, ydata=%f'%(
    event.button, event.x, event.y, event.xdata, event.ydata)

im = plt.imread('Picture1.png')
fig, ax=plt.subplots()
ax.imshow(im)
ax.autoscale(False)
cid = fig.canvas.mpl_connect('button_press_event', onclick)

plt.show()
4

1 回答 1

4

您只需要编写逻辑即可。这是我使用的东西的一个稍微修改过的版本(并且只维护一个列表),但是应该很容易扩展它来做你想做的事情。

class clicker_class(object):
    def __init__(self, ax, pix_err=1):
        self.canvas = ax.get_figure().canvas
        self.cid = None
        self.pt_lst = []
        self.pt_plot = ax.plot([], [], marker='o',
                               linestyle='none', zorder=5)[0]
        self.pix_err = pix_err
        self.connect_sf()

    def set_visible(self, visible):
        '''sets if the curves are visible '''
        self.pt_plot.set_visible(visible)

    def clear(self):
        '''Clears the points'''
        self.pt_lst = []
        self.redraw()

    def connect_sf(self):
        if self.cid is None:
            self.cid = self.canvas.mpl_connect('button_press_event',
                                               self.click_event)

    def disconnect_sf(self):
        if self.cid is not None:
            self.canvas.mpl_disconnect(self.cid)
            self.cid = None

    def click_event(self, event):
        ''' Extracts locations from the user'''
        if event.key == 'shift':
            self.pt_lst = []
            return
        if event.xdata is None or event.ydata is None:
            return
        if event.button == 1:
            self.pt_lst.append((event.xdata, event.ydata))
        elif event.button == 3:
            self.remove_pt((event.xdata, event.ydata))

        self.redraw()

    def remove_pt(self, loc):
        if len(self.pt_lst) > 0:
            self.pt_lst.pop(np.argmin(map(lambda x:
                                          np.sqrt((x[0] - loc[0]) ** 2 +
                                                  (x[1] - loc[1]) ** 2),
                                          self.pt_lst)))

    def redraw(self):
        if len(self.pt_lst) > 0:
            x, y = zip(*self.pt_lst)
        else:
            x, y = [], []
        self.pt_plot.set_xdata(x)
        self.pt_plot.set_ydata(y)

        self.canvas.draw()

    def return_points(self):
        '''Returns the clicked points in the format the rest of the
        code expects'''
        return np.vstack(self.pt_lst).T

ax = gca()
cc = clicker_class(ax)
于 2013-10-25T16:44:03.850 回答