2013-10-25 47 views
4

首先嚐試交互式繪圖,所以任何幫助都是值得歡迎的。在點擊圖表時繪製點的Python GUI?

我想要獲得一個交互式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() 

回答

3

你只需要編寫邏輯來完成它。這是我使用的稍微修改過的版本(並且只保留一個列表),但應該很容易將其擴展以執行您想要的操作。

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)