class ImagePanel(tk.Frame): """ This is a wrapper class for matplotlib figure canvas. It implements the mediator pattern for communication with collegues. """ def __init__(self, parent, name, figsize=(2,2), dpi=100, title='', wl=False, info=False, toolbar=False, cb=False): self.name = name tk.Frame.__init__(self, parent) self.parent = parent self.img_is_set = False self.figsize = figsize self.dpi = dpi self.title = title self.toolbar = toolbar self.wl = wl self.make_canvas() if info: self.make_info() self.images = None self.original_img = None self.nZoom = 0 self.indexOfImg = 0 self.level_is_set = False self.window_is_set = False self.initial_level = None self.initial_window = None self.img = None self.cb = cb self.cbar = None self.metadata = {} self.collegues = [] def register(self, collegue): self.collegues.append(collegue) def inform(self, event): for collegue in self.collegues: collegue.update_(self.name, event) def doubleclick(self, event): if event.dblclick: self.inform('<Double-Button-1>') print('DoubleClick') def make_canvas(self): self.canvas_frame = tk.Frame(self, padx=5, pady=5, cursor='crosshair') self.canvas_frame.pack(side=tk.TOP, fill=tk.BOTH, expand=1) if self.toolbar: self.toolbar_frame = self.make_toolbar() self.toolbar_frame.pack(side=tk.TOP, fill=tk.X, expand=0) self.f = Figure(figsize=self.figsize, dpi=self.dpi) self.subplot = self.f.add_subplot(111) self.subplot.set_title(self.title, fontsize=10) plt.setp(self.subplot.get_xticklabels(), fontsize=4) plt.setp(self.subplot.get_yticklabels(), fontsize=4) self.canvas = FigureCanvasTkAgg(self.f, master=self.canvas_frame) self.img = self.canvas.show() self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1) self.canvas.mpl_connect('scroll_event', self.mouseWheel) self.canvas.mpl_connect('button_press_event', self.doubleclick) if self.wl: self.wl_scale = self.make_wl() self.wl_scale.pack(side=tk.TOP, fill=tk.X, expand=0) def make_wl(self): f = font.Font(size=6) wl_frame = tk.Frame(self.canvas_frame) self.levelScale = tk.Scale(wl_frame, orient=tk.HORIZONTAL, from_=0.0, to=256.0, width=8, font=f, command=self.set_level) self.levelScale.pack(side=tk.TOP, fill=tk.X, expand=0) self.windowScale = tk.Scale(wl_frame, orient=tk.HORIZONTAL, from_=0.0, to=256.0, width=8, font=f, command=self.set_window) self.windowScale.pack(side=tk.TOP, fill=tk.X, expand=0) return wl_frame def make_info(self): self.info = tk.LabelFrame(self.parent, text='Image Info', padx=5, pady=5, width=400) self.info.pack(side=tk.RIGHT, fill=tk.BOTH, expand=0) def make_toolbar(self): toolbar_frame = tk.Frame(self.canvas_frame) set = ('DrawRectangle$icons/Rectangle$tk.FLAT$self.drawRectangle$tk.LEFT', 'Delete$icons/Delete$tk.FLAT$self.deleteRectangle$tk.LEFT', 'ZoomIn$icons/ZoomIn$tk.FLAT$self.zoomIn$tk.LEFT', 'ZoomOut$icons/ZoomOut$tk.FLAT$self.zoomOut$tk.LEFT', 'Reset$icons/ResetZoom$tk.FLAT$self.resetZoom$tk.LEFT', 'Move$icons/Move$tk.FLAT$self.move$tk.LEFT', 'Ruler$icons/Ruler$tk.FLAT$self.ruler$tk.LEFT', 'Histogram$icons/Histogram$tk.FLAT$self.histogram$tk.LEFT', 'Info$icons/Info$tk.FLAT$self.info$tk.LEFT', 'Save$icons/Save18$tk.FLAT$self.savePicture$tk.LEFT' ) self.imgToolbar= [] for v in set: text, image, relief, command, side = v.split('$') self.imgToolbar.append(tk.PhotoImage(file=image+'.gif')) button = tk.Button(toolbar_frame, image=self.imgToolbar[-1], text=text, relief=eval(relief), command=eval(command)) button.pack(side=tk.LEFT, fill=tk.BOTH, expand=0) return toolbar_frame def drawRectangle(self): print('Draw rectangle!') self.x0 = None self.y0 = None self.x1 = None self.y1 = None self.xp0 = None self.yp0 = None self.xp1 = None self.yp1 = None self.rectangle = Rectangle((0,0), 1, 1, facecolor='None', edgecolor='green') self.subplot.add_patch(self.rectangle) self.ispressed = False self.bpe = self.canvas.mpl_connect('button_press_event', self.drawRectangle_onPress) self.bre = self.canvas.mpl_connect('button_release_event', self.drawRectangle_onRelease) self.mne = self.canvas.mpl_connect('motion_notify_event', self.drawRectangle_onMotion) def drawRectangle_onPress(self, event): self.xp0 = event.x self.yp0 = event.y self.x0 = event.xdata self.y0 = event.ydata self.x1 = event.xdata self.y1 = event.ydata self.rectangle.set_width(self.x1-self.x0) self.rectangle.set_xy((self.x0, self.y0)) self.rectangle.set_linestyle('dashed') self.canvas.draw() self.ispressed = True def drawRectangle_onRelease(self, event): self.xp1 = event.x self.yp1 = event.y self.x1 = event.xdata self.y1 = event.ydata self.rectangle.set_width(self.x1-self.x0) self.rectangle.set_height(self.y1-self.y0) self.rectangle.set_xy((self.x0, self.y0)) self.rectangle.set_linestyle('solid') self.canvas.draw() self.ispressed = False self.canvas.mpl_disconnect(self.bpe) self.canvas.mpl_disconnect(self.bre) self.canvas.mpl_disconnect(self.mne) print(self.xp0, self.yp0, self.xp1, self.yp1) self.inform('<DrawRectangle>') return (self.xp0, self.yp0, self.xp1, self.yp1) def getRectanglePoints(self): return (self.xp0, self.yp0, self.xp1, self.yp1) def drawRectangle_onMotion(self, event): if self.ispressed is True: self.x1 = event.xdata self.y1 = event.ydata self.rectangle.set_width(self.x1-self.x0) self.rectangle.set_height(self.y1-self.y0) self.rectangle.set_xy((self.x0, self.y0)) self.rectangle.set_linestyle('dashed') self.canvas.draw() def deleteRectangle(self): print('Delete rectangle!') self.rectangle.remove() self.canvas.draw() self.inform('<DeleteRectangle>') def zoomIn(self): print('Zoom in!') print(np.shape(self.images)) self.images = self.images[:,10:-10, 10:-10] self.show_images() self.nZoom = self.nZoom+1 def zoomOut(self): print('ZoomOut!') if np.shape(self.images) != np.shape(self.original_img): if self.nZoom>1: self.images = self.original_img[:,(self.nZoom-1)*10:-(self.nZoom-1)*10, (self.nZoom-1)*10:-(self.nZoom-1)*10] self.show_images() self.nZoom = self.nZoom-1 else: self.images = self.original_img self.nZoom = 0 def resetZoom(self): print('Reset zoom!') self.images = self.original_img self.show_images() self.nZoom = 0 def histogram(self): print('Histogram!') histo = tk.Toplevel() f = Figure(figsize=(4,4), dpi=100) subplot = f.add_subplot(111) subplot.set_title('Histogram', fontsize=10) plt.setp(subplot.get_xticklabels(), fontsize=8) plt.setp(subplot.get_yticklabels(), fontsize=8) canvas = FigureCanvasTkAgg(f, master=histo) canvas.show() canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1) subplot.hist(self.images.flatten(), 100, normed=True, histtype='step', fc='k', ec='k') canvas.draw() close_button = tk.Button(histo, text='Close', command = histo.destroy) close_button.pack(side=tk.TOP) def savePicture(self): print('Save!') savefile = tk.filedialog.asksaveasfilename(title='Save image as ...', defaultextension='png', filetypes=[('all files', '.*'), ('png files', '.png')]) if savefile: self.f.savefig(savefile, dpi=1200, format='png', ) def mouseWheel(self, event): print('Test mouseWheel.') if event.button == 'down': self.indexOfImg = self.indexOfImg+1 self.show_images() self.inform('<MouseWheelDown') if event.button == 'up': self.indexOfImg = self.indexOfImg-1 self.show_images() self.inform('<MouseWheelUp') def change_wl(self, arg): print('Button press event test') def set_images(self, images): self.images = images if self.img_is_set == False: self.original_img = images self.show_images() self.img_is_set = True def set_metadata(self, data): self.metadata = data def show_images(self): plt.clf() if (self.indexOfImg < np.size(self.images, 0))and (self.indexOfImg >= 0): self.img = self.subplot.imshow(self.images[self.indexOfImg]) if self.level_is_set == False: self.level = (np.max(self.images[self.indexOfImg])-np.min(self.images[self.indexOfImg]))/2 self.window = 2*self.level self.levelScale.config(from_=np.min(self.images[self.indexOfImg])) self.levelScale.config(to=np.max(self.images[self.indexOfImg])) self.levelScale.set(self.level) self.windowScale.config(from_=0) self.windowScale.config(to=self.window) self.windowScale.set(self.window) if self.window < 1: self.levelScale.config(resolution=0.0001) self.windowScale.config(resolution=0.0001) self.img.set_clim(self.level-self.window/2, self.level+self.window/2) else: self.indexOfImg = 0 self.img = self.subplot.imshow(self.images[self.indexOfImg]) if self.level_is_set == False: self.level = (np.max(self.images[self.indexOfImg])-np.min(self.images[self.indexOfImg]))/2 self.window = 2*self.level self.levelScale.config(from_=np.min(self.images[self.indexOfImg])) self.levelScale.config(to=np.max(self.images[self.indexOfImg])) self.levelScale.set(self.level) self.windowScale.config(from_=0) self.windowScale.config(to=self.window) self.windowScale.set(self.window) if self.window < 1: self.levelScale.config(resolution=0.0001) self.windowScale.config(resolution=0.0001) self.img.set_clim(self.level-self.window/2, self.level+self.window/2) if self.cb: if self.cbar: self.cbar.set_clim(np.min(self.images[self.indexOfImg]), np.max(self.images[self.indexOfImg])) else: self.cbar = self.f.colorbar(self.img) self.canvas.draw() def set_level(self, event): self.level = self.levelScale.get() if self.level >= (np.max(self.images[self.indexOfImg])-np.min(self.images[self.indexOfImg]))/2: self.window = 2*(np.max(self.images[self.indexOfImg])-self.level) elif self.level < (np.max(self.images[self.indexOfImg])-np.min(self.images[self.indexOfImg]))/2: self.window = 2*(self.level-np.min(self.images[self.indexOfImg])) print(self.level, self.window) if self.windowScale.get() <= self.window: self.img.set_clim(float(self.level-self.windowScale.get()/2), float(self.level+self.windowScale.get()/2)) else: self.img.set_clim(float(self.level-self.window/2), float(self.level+self.window/2)) #self.level_is_set = True self.windowScale.config(to = self.window) self.canvas.draw() def set_window(self, event): self.window = self.windowScale.get() self.img.set_clim(float(self.level-self.window/2), float(self.level+self.window/2)) #self.level_is_set = True self.canvas.draw() def set_indexOfImg(self, index): self.indexOfImg = index def ruler(self): print('Measure!') def move(self): print('Move!') def info(self): info = tk.Toplevel() tk.Button(info, text='Close', command = info.destroy).pack(side=tk.TOP)
class click_yrange: '''An interactive yrange selector. Given an axis and a starting y0 location, draw a full-width rectange that follows the mouise. Similar to click_window, but more appropriate for selecting out a y-range.''' def __init__(self, ax, y0): self.ax = ax self.y0 = y0 x0,x1 = ax.get_xbound() self.rect = Rectangle((x0,y0), width=(x1-x0), height=0, alpha=0.1) ax.add_artist(self.rect) def connect(self): self.cidmotion = self.rect.figure.canvas.mpl_connect( 'motion_notify_event', self.on_motion) def on_motion(self, event): # Have we left the axes? if event.inaxes != self.rect.axes: return self.rect.set_height(event.ydata - self.y0) self.ax.figure.canvas.draw() def close(self): self.rect.figure.canvas.mpl_disconnect(self.cidmotion) self.rect.remove() self.ax.figure.canvas.draw() return(self.y0, self.rect.get_y()+self.rect.get_height())
class Annotate(object): def __init__(self, ax): self.ax = ax self.rect = Rectangle((0,0), 1, 1, fill=False) self.x0 = None self.y0 = None self.x1 = None self.y1 = None self.ax.add_patch(self.rect) self.ax.figure.canvas.mpl_connect('button_press_event', self.on_press) self.ax.figure.canvas.mpl_connect('button_release_event', self.on_release) def on_press(self, event): print 'press' self.x0 = event.xdata self.y0 = event.ydata def on_release(self, event): print 'release' self.x1 = event.xdata self.y1 = event.ydata self.rect.set_width(self.x1 - self.x0) self.rect.set_height(self.y1 - self.y0) self.rect.set_xy((self.x0, self.y0)) self.ax.figure.canvas.draw() self.get_graph_bound() #self.bounds = ColorBounds(Cb_min=self.x0, Cr_min=self.y0, Cb_max=self.x1, Cr_max=self.y1) self.bounds = ColorBounds(Cr_min=self.x0, Yp_min=self.y0, Cr_max=self.x1, Yp_max=self.y1) def get_graph_bound(self): print(self.x0, self.y0, self.x1, self.y1)
class LaneSelector(object): def __init__(self, cb): self.ax = gca() self.rect = Rectangle((0,0), 1, 1, alpha=0.2, color='red') self.x0 = None self.y0 = None self.x1 = None self.y1 = None self.pressed = False self.cb = cb self.ax.add_patch(self.rect) self.ax.figure.canvas.mpl_connect('button_press_event', self.on_press) self.ax.figure.canvas.mpl_connect('button_release_event', self.on_release) self.ax.figure.canvas.mpl_connect('motion_notify_event', self.on_motion) def on_press(self, event): self.x0 = event.xdata self.y0 = event.ydata self.pressed = True def on_release(self, event): self.pressed = False if self.x0 != self.x1 and self.y0 != self.y1: self.cb(self.x0, self.y0, self.x1, self.y1) def on_motion(self, event): if self.pressed: self.x1 = event.xdata self.y1 = event.ydata self.rect.set_width(self.x1 - self.x0) self.rect.set_height(self.y1 - self.y0) self.rect.set_xy((self.x0, self.y0)) self.ax.figure.canvas.draw()
class Annotate(object): def __init__(self, ax, areas, rects): self.ax = ax self.areas = areas self.rects = rects self.rect = Rectangle((0, 0), 0, 0, color='orange', alpha=0.5) self.x0 = None self.y0 = None self.x1 = None self.y1 = None self.ax.add_patch(self.rect) self.ax.figure.canvas.mpl_connect('button_press_event', self.on_press) self.ax.figure.canvas.mpl_connect('button_release_event', self.on_release) def on_press(self, event): if event.inaxes == self.ax: self.x0 = event.xdata self.y0 = event.ydata def on_release(self, event): if event.inaxes == self.ax: self.x1 = event.xdata self.y1 = event.ydata if event.button == 1: self.areas.append( [self.x0, self.y0, self.x1, self.y1, "appended", "a"]) elif event.button == 3: self.areas.append( [self.x0, self.y0, self.x1, self.y1, "appended", "d"]) self.rect.set_width(self.x1 - self.x0) self.rect.set_height(self.y1 - self.y0) self.rect.set_xy((self.x0, self.y0)) self.rect.set_visible(False)
class Annotate(object): def __init__(self): self.ax = plt.gca() self.rect = Rectangle((0,0), 0, 0) self.x0 = 0 self.y0 = 0 self.x1 = 0 self.y1 = 0 self.ax.add_patch(self.rect) self.ax.figure.canvas.mpl_connect('button_press_event', self.on_press) self.ax.figure.canvas.mpl_connect('button_release_event', self.on_release) def on_press(self, event): self.x0 = event.xdata self.y0 = event.ydata def on_release(self, event): try: self.x1 = event.xdata self.y1 = event.ydata self.rect.set_width(self.x1 - self.x0) self.rect.set_height(self.y1 - self.y0) self.rect.set_xy((self.x0, self.y0)) self.ax.figure.canvas.draw() except TypeError: print("Can't select outside the plot! Try again!")
class click_window: '''An interactive window. Given an axis instance and a start point (x0,y0), draw a dynamic rectangle that follows the mouse until the close() function is called (which returns the coordinates of the final rectangle. Useful or selecting out square regions.''' def __init__(self, ax, x0, y0): self.ax = ax self.x0 = x0 self.y0 = y0 self.rect = Rectangle((x0, y0), width=0, height=0, alpha=0.1) ax.add_artist(self.rect) def connect(self): self.cidmotion = self.rect.figure.canvas.mpl_connect( 'motion_notify_event', self.on_motion) def on_motion(self, event): # Have we left the axes? if event.inaxes != self.rect.axes: return self.rect.set_width(event.xdata - self.x0) self.rect.set_height(event.ydata - self.y0) self.ax.figure.canvas.draw() def close(self): self.rect.figure.canvas.mpl_disconnect(self.cidmotion) extent = self.rect.get_bbox().get_points() self.rect.remove() self.ax.figure.canvas.draw() return (list(ravel(extent)))
class Selector(object): def __init__(self, ax): self.ax = ax self.x0 = None self.y0 = None self.rect = Rectangle((0, 0), 1, 1, fill=False) self.ax.add_patch(self.rect) self.ax.figure.canvas.mpl_connect('button_press_event', self.on_press) self.ax.figure.canvas.mpl_connect('button_release_event', self.on_release) def on_press(self, event): self.x0 = event.xdata self.y0 = event.ydata def on_release(self, event): x1 = event.xdata y1 = event.ydata self.rect.set_width(x1 - self.x0) self.rect.set_height(y1 - self.y0) self.rect.set_xy((self.x0, self.y0)) self.ax.figure.canvas.draw() x_min = min(self.x0, x1) x_max = max(self.x0, x1) y_min = min(self.y0, y1) y_max = max(self.y0, y1) self.xybounds = (x_min, x_max, y_min, y_max)
class click_yrange: '''An interactive yrange selector. Given an axis and a starting y0 location, draw a full-width rectange that follows the mouise. Similar to click_window, but more appropriate for selecting out a y-range.''' def __init__(self, ax, y0): self.ax = ax self.y0 = y0 x0, x1 = ax.get_xbound() self.rect = Rectangle((x0, y0), width=(x1 - x0), height=0, alpha=0.1) ax.add_artist(self.rect) def connect(self): self.cidmotion = self.rect.figure.canvas.mpl_connect( 'motion_notify_event', self.on_motion) def on_motion(self, event): # Have we left the axes? if event.inaxes != self.rect.axes: return self.rect.set_height(event.ydata - self.y0) self.ax.figure.canvas.draw() def close(self): self.rect.figure.canvas.mpl_disconnect(self.cidmotion) self.rect.remove() self.ax.figure.canvas.draw() return (self.y0, self.rect.get_y() + self.rect.get_height())
def resizeGraphics(self, width, height): """ It is time to set a magnitude to our currently normalized lines, and send them to the figure. Here we assume that __normLines & __normPatches are already fully populated. """ self.__fig.lines = [] # clear all old lines from figure self.__fig.patches = [] # clear all old patches from figure self.__xsz = width self.__ysz = height # scale each text item for t in self.__fig.texts: t.set_size(self.getTextPointSize(t.gkiTextSzFactor, width, height)) # scale each line, then apply it to the figure for nrln in self.__normLines: ll = Line2D([], []) ll.update_from(nrln) ll.set_data( nrln.get_xdata(True) * self.__xsz, nrln.get_ydata(True) * self.__ysz) self.__fig.lines.append(ll) # scale each patch, then apply it to the figure for nrpa in self.__normPatches: rr = Rectangle((0, 0), 0, 0) rr.update_from(nrpa) rr.set_x(nrpa.get_x() * self.__xsz) rr.set_y(nrpa.get_y() * self.__ysz) rr.set_width(nrpa.get_width() * self.__xsz) rr.set_height(nrpa.get_height() * self.__ysz) self.__fig.patches.append(rr)
class Annotate(object): def __init__(self): self.ax = plt.gca() self.rect = Rectangle((0,0), 1, 1) self.x0 = None self.y0 = None self.x1 = None self.y1 = None self.ax.add_patch(self.rect) self.ax.figure.canvas.mpl_connect('button_press_event', self.on_press) self.ax.figure.canvas.mpl_connect('button_release_event', self.on_release) def on_press(self, event): print 'press' self.x0 = event.xdata self.y0 = event.ydata def on_release(self, event): print 'release' self.x1 = event.xdata self.y1 = event.ydata self.rect.set_width(self.x1 - self.x0) self.rect.set_height(self.y1 - self.y0) self.rect.set_xy((self.x0, self.y0)) self.ax.figure.canvas.draw()
class Annotate(object): def __init__(self, uploaded_image): self.uploaded_image = uploaded_image plt.imshow(uploaded_image, zorder=0) self.ax = plt.gca() axcut = plt.axes([0.9, 0.0, 0.1, 0.075]) self.bsubmit = Button(axcut, "Submit", color='red', hovercolor="green") self.rect = Rectangle((0, 0), 1, 1, fc=(1, 0, 0, .5), ec=(0, 0, 0, 1), lw=2) self.x0 = None self.y0 = None self.x1 = None self.y1 = None self.boundedboxes = [] self.ax.add_patch(self.rect) self.ax.figure.canvas.mpl_connect('button_press_event', self.on_press) self.ax.figure.canvas.mpl_connect('button_release_event', self.on_release) self.bsubmit.on_clicked(self.submit) def on_press(self, event): self.x0 = event.xdata self.y0 = event.ydata # For drawing the boxes. When release it saves the coordinates in list of list datastructure def on_release(self, event): self.x1 = event.xdata self.y1 = event.ydata self.rect.set_width(self.x1 - self.x0) self.rect.set_height(self.y1 - self.y0) self.rect.set_xy((self.x0, self.y0)) self.boundedboxes.append([self.x0, self.y0, self.x1, self.y1]) self.ax.figure.canvas.draw() # On click of submit button # Needs to be updated to send these values to the function which will # recognize the objects # Then closes all the matplotlib objects that are open def submit(self, event): word = "" count = 0 n = len(self.boundedboxes) n = n - 1 cropped_images = np.empty(shape=(n, 32, 32, 3)) for i in self.boundedboxes: if i[1] > 1: cropped_images[count, :, :, :] = crop_image( self.uploaded_image, i) count += 1 guesses = predict_char(cropped_images) for i in guesses: word += get_label_name(i) Translate(word)
class MplYRangeROI(AbstractMplRoi): def __init__(self, ax): """ :param ax: A matplotlib Axes object to attach the graphical ROI to """ AbstractMplRoi.__init__(self, ax) self._xi = None self.plot_opts = {'edgecolor': PATCH_COLOR, 'facecolor': PATCH_COLOR, 'alpha': 0.3} trans = blended_transform_factory(self._ax.transAxes, self._ax.transData) self._patch = Rectangle((0., 0.), 1., 1., transform=trans) self._patch.set_zorder(100) self._setup_patch() def _setup_patch(self): self._ax.add_patch(self._patch) self._patch.set_visible(False) self._sync_patch() def _roi_factory(self): return YRangeROI() def start_selection(self, event): if event.inaxes != self._ax: return self._roi.reset() self._roi.set_range(event.ydata, event.ydata) self._xi = event.ydata self._mid_selection = True self._sync_patch() def update_selection(self, event): if not self._mid_selection or event.inaxes != self._ax: return self._roi.set_range(min(event.ydata, self._xi), max(event.ydata, self._xi)) self._sync_patch() def finalize_selection(self, event): self._mid_selection = False self._patch.set_visible(False) self._draw() def _sync_patch(self): if self._roi.defined(): rng = self._roi.range() self._patch.set_xy((0, rng[0])) self._patch.set_height(rng[1] - rng[0]) self._patch.set_width(1) self._patch.set(**self.plot_opts) self._patch.set_visible(True) else: self._patch.set_visible(False) self._draw()
class Selector(object): def __init__(self, ax): self.ax = ax self.x0 = None self.y0 = None self.rect = Rectangle((0,0), 1, 1, fill=False) self.ax.add_patch(self.rect) self.ax.figure.canvas.mpl_connect('button_press_event', self.on_press) self.ax.figure.canvas.mpl_connect('button_release_event', self.on_release) def on_press(self, event): self.x0 = event.xdata self.y0 = event.ydata def on_release(self, event): x1 = event.xdata y1 = event.ydata self.rect.set_width(x1 - self.x0) self.rect.set_height(y1 - self.y0) self.rect.set_xy((self.x0, self.y0)) self.ax.figure.canvas.draw() x_min = min(self.x0, x1) x_max = max(self.x0, x1) y_min = min(self.y0, y1) y_max = max(self.y0, y1) self.xybounds = (x_min, x_max, y_min, y_max)
class click_window: '''An interactive window. Given an axis instance and a start point (x0,y0), draw a dynamic rectangle that follows the mouse until the close() function is called (which returns the coordinates of the final rectangle. Useful or selecting out square regions.''' def __init__(self, ax, x0, y0): self.ax = ax self.x0 = x0 self.y0 = y0 self.rect = Rectangle((x0,y0), width=0, height=0, alpha=0.1) ax.add_artist(self.rect) def connect(self): self.cidmotion = self.rect.figure.canvas.mpl_connect( 'motion_notify_event', self.on_motion) def on_motion(self, event): # Have we left the axes? if event.inaxes != self.rect.axes: return self.rect.set_width(event.xdata - self.x0) self.rect.set_height(event.ydata - self.y0) self.ax.figure.canvas.draw() def close(self): self.rect.figure.canvas.mpl_disconnect(self.cidmotion) extent = self.rect.get_bbox().get_points() self.rect.remove() self.ax.figure.canvas.draw() return(list(ravel(extent)))
def resizeGraphics(self, width, height): """ It is time to set a magnitude to our currently normalized lines, and send them to the figure. Here we assume that __normLines & __normPatches are already fully populated. """ self.__fig.lines = [] # clear all old lines from figure self.__fig.patches = [] # clear all old patches from figure self.__xsz = width self.__ysz = height # scale each text item for t in self.__fig.texts: t.set_size(self.getTextPointSize(t.gkiTextSzFactor, width, height)) # scale each line, then apply it to the figure for nrln in self.__normLines: ll = Line2D([], []) ll.update_from(nrln) ll.set_data(nrln.get_xdata(True)*self.__xsz, nrln.get_ydata(True)*self.__ysz) self.__fig.lines.append(ll) # scale each patch, then apply it to the figure for nrpa in self.__normPatches: rr = Rectangle((0,0),0,0) rr.update_from(nrpa) rr.set_x(nrpa.get_x()*self.__xsz) rr.set_y(nrpa.get_y()*self.__ysz) rr.set_width(nrpa.get_width()*self.__xsz) rr.set_height(nrpa.get_height()*self.__ysz) self.__fig.patches.append(rr)
class Annotate(object): def __init__(self): self.ax = plt.gca() #self.ax = ax #self.fig = fig self.rect = Rectangle((0,0), 1, 1, facecolor='None', edgecolor='green') self.x0 = None self.y0 = None self.x1 = None self.y1 = None self.is_pressed = False self.ax.add_patch(self.rect) #self.fig.canvas.mpl_connect('button_press_event',self.on_press) #self.fig.canvas.mpl_connect('button_release_event', self.on_release) #self.fig.canvas.mpl_connect('motion_notify_event', self.on_motion) self.ax.figure.canvas.mpl_connect('button_press_event', self.on_press) self.ax.figure.canvas.mpl_connect('button_release_event', self.on_release) self.ax.figure.canvas.mpl_connect('motion_notify_event', self.on_motion) self.ax.figure.canvas.draw() def on_press(self, event): print 'press' self.is_pressed = True self.x0 = event.xdata self.y0 = event.ydata print self.x0, self.y0 #self.rect.set_width(self.x1 - self.x0) #self.rect.set_height(self.y1 - self.y0) #self.rect.set_xy((self.x0, self.y0)) #self.rect.set_linestyle('dashed') #self.fig.canvas.draw() #self.ax.figure.canvas.draw() def on_motion(self,event): print 'motion' if self.is_pressed is True: return self.x1 = event.xdata self.y1 = event.ydata self.rect.set_width(self.x1 - self.x0) self.rect.set_height(self.y1 - self.y0) self.rect.set_xy((self.x0, self.y0)) self.rect.set_linestyle('dashed') #self.fig.canvas.draw() self.ax.figure.canvas.draw() def on_release(self, event): print 'release' self.is_pressed = False self.x1 = event.xdata self.y1 = event.ydata self.rect.set_width(self.x1 - self.x0) self.rect.set_height(self.y1 - self.y0) self.rect.set_xy((self.x0, self.y0)) self.rect.set_linestyle('solid') #self.fig.canvas.draw() self.ax.figure.canvas.draw() #time.sleep(3) #plt.close() print self.x0,self.y0,self.x1,self.y1
class MplYRangeROI(AbstractMplRoi): def __init__(self, ax): """ :param ax: A matplotlib Axes object to attach the graphical ROI to """ AbstractMplRoi.__init__(self, ax) self._xi = None self.plot_opts = { 'edgecolor': PATCH_COLOR, 'facecolor': PATCH_COLOR, 'alpha': 0.3 } trans = blended_transform_factory(self._ax.transAxes, self._ax.transData) self._patch = Rectangle((0., 0.), 1., 1., transform=trans) self._patch.set_zorder(100) self._ax.add_patch(self._patch) self._sync_patch() def _roi_factory(self): return YRangeROI() def start_selection(self, event): if event.inaxes != self._ax: return self._roi.reset() self._roi.set_range(event.ydata, event.ydata) self._xi = event.ydata self._mid_selection = True self._sync_patch() def update_selection(self, event): if not self._mid_selection or event.inaxes != self._ax: return self._roi.set_range(min(event.ydata, self._xi), max(event.ydata, self._xi)) self._sync_patch() def finalize_selection(self, event): self._mid_selection = False self._patch.set_visible(False) self._draw() def _sync_patch(self): if self._roi.defined(): rng = self._roi.range() self._patch.set_xy((0, rng[0])) self._patch.set_height(rng[1] - rng[0]) self._patch.set_width(1) self._patch.set(**self.plot_opts) self._patch.set_visible(True) else: self._patch.set_visible(False) self._draw()
class Annotate(object): def __init__(self): self.ax = plt.gca() self.img = cv2.imread('./img/11.jpg') self.rect = Rectangle((0, 0), 1, 1, edgecolor='red') self.x0 = None self.y0 = None self.x1 = None self.y1 = None self.range = self.img.shape[0:2] self.rect_coor = [] self.press = False self.ax.add_patch(self.rect) self.ax.imshow(self.img) self.ax.figure.canvas.mpl_connect('button_press_event', self.on_press) self.ax.figure.canvas.mpl_connect('button_release_event', self.on_release) self.ax.figure.canvas.mpl_connect('motion_notify_event', self.on_motion) def on_press(self, event): self.x0 = event.xdata if event.xdata else 0 self.y0 = event.ydata if event.ydata else 0 self.press = True def on_release(self, event): self.x1 = event.xdata if event.xdata else 0 self.y1 = event.ydata if event.ydata else 0 self.press = False # self.rect.set_width(self.x1 - self.x0) # self.rect.set_height(self.y1 - self.y0) # self.rect.set_xy((self.x0, self.y0)) self.rect_coor.append((self.x0, self.y0, self.x1, self.y1)) self.draw_rect(self.rect_coor) print(self.rect_coor) def on_motion(self, event): if self.press == True: x0, y0, x1, y1 = self.x0, self.y0, self.x1, self.y1 x_now = event.xdata if event.xdata else 0 y_now = event.ydata if event.ydata else 0 dx = x_now - x0 dy = y_now - y0 self.rect.set_width(dx) self.rect.set_height(dy) self.rect.set_xy((self.x0, self.y0)) self.ax.figure.canvas.draw() def draw_rect(self, coor_arrs): '''draw rect, and rect's arr from coor_arrs ''' for coor in coor_arrs: rect = Rectangle((0, 0), 1, 1, edgecolor='red', fill=False) self.ax.add_patch(rect) rect.set_width(coor[2] - coor[0]) rect.set_height(coor[3] - coor[1]) rect.set_xy((coor[0], coor[1])) self.ax.figure.canvas.draw()
def draw_rect(self, coor): rect = Rectangle((0, 0), 1, 1, edgecolor='red', fill=False) self.ax.add_patch(rect) rect.set_width(coor[2] - coor[0]) rect.set_height(coor[3] - coor[1]) rect.set_xy((coor[0], coor[1])) # self.ax.annotate(1, (coor[0], coor[1]), color='w', weight='bold', # fontsize=16, horizontalalignment='left', verticalalignment='top') self.ax.figure.canvas.draw()
class ImageAreaSelect(object): def __init__(self, img, out, fit=False): self.img = img self.out = out self.fit = fit plt.figure() plt.title("Testing Image") plt.xlabel(r'M') plt.ylabel(r'N') self.ax = plt.gca() self.rect = Rectangle((0, 0), 1, 1, antialiased=True, color='b', linestyle='solid', lw=1.2) self.rect.set_fill(False) self.x0 = None self.y0 = None self.x1 = None self.y1 = None self.draw_rect = False self.ax.add_patch(self.rect) self.ax.figure.canvas.mpl_connect('button_press_event', self.on_press) self.ax.figure.canvas.mpl_connect('button_release_event', self.on_release) self.ax.figure.canvas.mpl_connect('motion_notify_event', self.on_motion) plt.imshow(self.img, cmap="gray") plt.show() def on_press(self, event): self.draw_rect = True self.x0 = int(event.xdata) self.y0 = int(event.ydata) def on_motion(self, event): if self.draw_rect: if self.x1 != int(event.xdata) or self.y1 != int(event.ydata): self.x1 = int(event.xdata) self.y1 = int(event.ydata) self.rect.set_width(self.x1 - self.x0) self.rect.set_height(self.y1 - self.y0) self.rect.set_xy((self.x0, self.y0)) self.ax.figure.canvas.draw() def on_release(self, event): self.draw_rect = False self.x1 = int(event.xdata) self.y1 = int(event.ydata) self.calc() def calc(self): if self.x1 == self.x0 or self.y1 == self.y0: return print('crop(x,y):', self.x0, self.x1, self.y0, self.y1) img = self.img[self.y0:self.y1, self.x0:self.x1] mtf_from_img(img, self.out + "/" + str(self.x0) + "_" + str(self.x1) + "_" + str(self.y0) + "_" + str(self.y1), True)
def draw_rect(self, coor_arrs): '''draw rect, and rect's arr from coor_arrs ''' for coor in coor_arrs: rect = Rectangle((0, 0), 1, 1, edgecolor='red', fill=False) self.ax.add_patch(rect) rect.set_width(coor[2] - coor[0]) rect.set_height(coor[3] - coor[1]) rect.set_xy((coor[0], coor[1])) self.ax.figure.canvas.draw()
class Annotate(object): def __init__(self): self.ax = plt.gca() self.rect = Rectangle((0, 0), 1, 1, facecolor='None', edgecolor='red') self.x0 = None self.y0 = None self.x1 = None self.y1 = None self.x2 = None self.y2 = None self.is_pressed = False self.ax.add_patch(self.rect) self.ax.figure.canvas.mpl_connect('button_press_event', self.on_press) self.ax.figure.canvas.mpl_connect('button_release_event', self.on_release) self.ax.figure.canvas.mpl_connect('motion_notify_event', self.on_motion) def on_press(self, event): self.is_pressed = True self.x0 = event.xdata self.y0 = event.ydata def on_motion(self, event): self.x1, self.y1 = event.xdata, event.ydata if (self.is_pressed is True and self.x1 is not None and self.y1 is not None): self.rect.set_width(self.x1 - self.x0) self.rect.set_height(self.y1 - self.y0) self.rect.set_xy((self.x0, self.y0)) self.rect.set_linestyle('dashed') self.ax.figure.canvas.draw() def on_release(self, event): self.is_pressed = False self.x1, self.y1 = event.xdata, event.ydata try: self.rect.set_width(self.x1 - self.x0) self.rect.set_height(self.y1 - self.y0) self.rect.set_xy((self.x0, self.y0)) except TypeError: if (self.x1 is None or self.y1 is None): return else: raise self.rect.set_linestyle('solid') self.ax.figure.canvas.draw() print self.x0, self.x1, self.y0, self.y1 self.x2 = self.x1 self.y2 = self.y1 def __call__(self): return [self.x0, self.x2, self.y0, self.y2]
class RoiRect(object): ''' Class for getting a mouse drawn rectangle Based on the example from: http://matplotlib.org/users/event_handling.html#draggable-rectangle-exercise Note that: * It makes only one roi ''' def __init__(self): self.ax = plt.gca() self.rect = Rectangle((0,0), 1, 1,fc='none', ec='r') self.x0 = None self.y0 = None self.x1 = None self.y1 = None self.ax.add_patch(self.rect) self.ax.figure.canvas.mpl_connect('button_press_event', self.on_press) self.ax.figure.canvas.mpl_connect('button_release_event', self.on_release) self.ax.figure.canvas.mpl_connect('motion_notify_event', self.on_motion) def on_press(self, event): print 'press' self.x0 = event.xdata self.y0 = event.ydata self.rect.set_linestyle('dashed') self.set = False def on_release(self, event): print 'release' self.x1 = event.xdata self.y1 = event.ydata self.rect.set_width(self.x1 - self.x0) self.rect.set_height(self.y1 - self.y0) self.rect.set_xy((self.x0, self.y0)) self.rect.set_linestyle('solid') self.ax.figure.canvas.draw() self.set = True self.ax.figure.canvas.mpl_disconnect(self.on_press) self.ax.figure.canvas.mpl_disconnect(self.on_release) self.ax.figure.canvas.mpl_disconnect(self.on_motion) def on_motion(self, event): # on motion will move the rect if the mouse if self.x0 is None: return if self.set: return # if event.inaxes != self.rect.axes: return self.x1 = event.xdata self.y1 = event.ydata self.rect.set_width(self.x1 - self.x0) self.rect.set_height(self.y1 - self.y0) self.rect.set_xy((self.x0, self.y0)) self.ax.figure.canvas.draw()
class ROI(object): def __init__(self, fig, ax_tran, ax_fron, ax_sagi): self.fig = fig self.ax_tran = ax_tran self.ax_fron = ax_fron self.ax_sagi = ax_sagi self.rect = Rectangle((0, 0), 1, 1, facecolor='None', edgecolor='red') self.x0 = None self.y0 = None self.x1 = None self.y1 = None self.is_pressed = False self.ax.figure.canvas.mpl_connect('button_press_event', self.on_press) self.ax.figure.canvas.mpl_connect('button_release_event', self.on_release) self.ax.figure.canvas.mpl_connect('motion_notify_event', self.on_motion) def check_axes(self, event): if self.ax_tran.in_axes(event): self.ax_tran.add_patch(self.rect) def on_press(self, event): self.is_pressed = True print('press') self.x0 = event.xdata self.y0 = event.ydata def on_motion(self, event): if self.is_pressed == True: self.x1 = event.xdata self.y1 = event.ydata self.rect.set_width(self.x1 - self.x0) self.rect.set_height(self.y1 - self.y0) self.rect.set_xy((self.x0, self.y0)) self.rect.set_linestyle('dashed') self.fig.canvas.draw() # self.ax.figure.canvas.draw() def on_release(self, event): self.is_pressed = False print('release') self.x1 = event.xdata self.y1 = event.ydata self.rect.set_width(self.x1 - self.x0) self.rect.set_height(self.y1 - self.y0) self.rect.set_xy((self.x0, self.y0)) self.rect.set_linestyle('solid') self.fig.canvas.draw() # self.ax.figure.canvas.draw() print(self.x0, self.x1, self.y0, self.y1) return [self.x0, self.x1, self.y0, self.y1]
class rectSelection(GuiSelection): """Interactive selection of a rectangular region on the axis. Used by hist2d_alex(). """ def on_press_draw(self): if 'r' in self.__dict__: self.r.set_height(0) self.r.set_width(0) self.r.set_xy((self.xs, self.ys)) self.e.height = 0 self.e.width = 0 self.e.center = (self.xs, self.ys) else: self.r = Rectangle(xy=(self.xs, self.ys), height=0, width=0, fill=False, lw=2, alpha=0.5, color='blue') self.e = Ellipse(xy=(self.xs, self.ys), height=0, width=0, fill=False, lw=2, alpha=0.6, color='blue') self.ax.add_artist(self.r) self.ax.add_artist(self.e) self.r.set_clip_box(self.ax.bbox) self.r.set_zorder(10) self.e.set_clip_box(self.ax.bbox) self.e.set_zorder(10) def on_motion_draw(self): self.r.set_height(self.ye - self.ys) self.r.set_width(self.xe - self.xs) self.e.height = (self.ye - self.ys) self.e.width = (self.xe - self.xs) self.e.center = (np.mean([self.xs, self.xe]), np.mean([self.ys, self.ye])) self.fig.canvas.draw() def on_release_print(self): # This is the only custom method for hist2d_alex() E1, E2 = min((self.xs, self.xe)), max((self.xs, self.xe)) S1, S2 = min((self.ys, self.ye)), max((self.ys, self.ye)) self.selection = dict(E1=E1, E2=E2, S1=S1, S2=S2) pprint("Selection: \nE1=%.2f, E2=%.2f, S1=%.2f, S2=%.2f\n" %\ (E1,E2,S1,S2))
class Selector(): def __init__(self, ax, canvas, x0=0, y0=0, x1=1, y1=1): self.Rect = Rectangle((x0, y0), x1-x0, y1-y0, color="blue", alpha=0.2, visible=False) self.cHandles = Line2D([x0, x1, x1, x0], [y0, y0, y1, y1], marker='o', markersize=7, mfc='w', markeredgecolor='mediumblue', ls='none', alpha=0.8, visible=False, label='_nolegend_') self.eHandles = Line2D([(x0+x1)/2, x1, (x0+x1)/2, x0], [y0, (y0+y1)/2, y1, (y0+y1)/2], marker='s', markersize=5, mfc='w', markeredgecolor='dodgerblue', ls='none', alpha=0.8, visible=False, label='_nolegend_') self.artist = [self.Rect, self.cHandles, self.eHandles] self.region = (x0, y0, x1, y1) self.active_handle = 0 self.visible = False self.ax = ax self.canvas = canvas self.moveing_state = "draw" self.origin = (0, 0) self.ax.add_patch(self.Rect) self.ax.add_line(self.cHandles) self.ax.add_line(self.eHandles) def resize(self, x0, y0, x1, y1): xmin, xmax = sorted((x0, x1)) ymin, ymax = sorted((y0, y1)) self.region = (xmin, ymin, xmax, ymax) self.Rect.set_xy((xmin, ymin)) self.Rect.set_width(xmax-xmin) self.Rect.set_height(ymax-ymin) self.cHandles.set_data([xmin, xmax, xmax, xmin], [ymin, ymin, ymax, ymax]) self.eHandles.set_data([(xmin+xmax)/2, xmax, (xmin+xmax)/2, xmin], [ymin, (ymin+ymax)/2, ymax, (ymin+ymax)/2]) def set_visible(self, visible): self.Rect.set_visible(visible) self.cHandles.set_visible(visible) self.eHandles.set_visible(visible) self.visible = visible def isinRegion(self, x, y): if ((self.region[0] < x < self.region[2]) and (self.region[1] < y < self.region[3])): return True else: return False def nearestCorner(self, x, y): x0, y0, x1, y1 = self.region array = np.array([[x0,y0], [(x0+x1)/2, y0], [x1,y0], [x1, (y0+y1)/2], [x1,y1], [(x0+x1)/2, y1], [x0,y1], [x0, (y0+y1)/2]]) pts = self.ax.transData.transform(array) diff = pts - ((x, y)) distance = np.sqrt(np.sum(diff ** 2, axis=1)) self.active_handle = distance.argmin() return distance.min()
class ROI(object): def __init__(self, ax, roi_data, pat_id, ax_name, ax_index): self.ax = ax self.roi_data = roi_data self.pat_id = pat_id self.ax_name = ax_name self.ax_index = ax_index self.rect = Rectangle((0, 0), 1, 1, facecolor='None', edgecolor='red') self.x1 = None self.y1 = None self.x2 = None self.y2 = None self.is_pressed = False self.ax.add_patch(self.rect) self.ax.figure.canvas.mpl_connect('button_press_event', self.on_press) self.ax.figure.canvas.mpl_connect('button_release_event', self.on_release) self.ax.figure.canvas.mpl_connect('motion_notify_event', self.on_motion) def on_press(self, event): self.is_pressed = True self.x1 = event.xdata self.y1 = event.ydata def on_motion(self, event): if self.is_pressed == True: self.x2 = event.xdata self.y2 = event.ydata self.rect.set_width(self.x2 - self.x1) self.rect.set_height(self.y2 - self.y1) self.rect.set_xy((self.x1, self.y1)) self.rect.set_linestyle('dashed') self.ax.figure.canvas.draw() def on_release(self, event): self.is_pressed = False self.x2 = event.xdata self.y2 = event.ydata self.rect.set_width(self.x2 - self.x1) self.rect.set_height(self.y2 - self.y1) self.rect.set_xy((self.x1, self.y1)) self.rect.set_linestyle('solid') self.ax.figure.canvas.draw() # Append axes name and two rectangluar coordinates self.roi_data.append([self.pat_id, self.ax_name, self.ax_index[-1], int(self.x1), int(self.y1), int(self.x2), int(self.y2)])
def draw_rects(self, coor_arrs): '''draw rect, and rect's arr from coor_arrs ''' for index, coor in enumerate(coor_arrs): rect = Rectangle((0, 0), 1, 1, edgecolor='red', fill=False) self.ax.add_patch(rect) rect.set_width(coor[2] - coor[0]) rect.set_height(coor[3] - coor[1]) rect.set_xy((coor[0], coor[1])) ann = self.ax.annotate((index, int(coor[0]), int( coor[1]), int(coor[2]), int(coor[3])), (coor[0], coor[1]), color='w', fontsize=10, horizontalalignment='left', verticalalignment='top') self.anns.append(ann) self.ax.figure.canvas.draw()
class RectangleRegionSelector(object): isPressed = False def __init__(self): self.ax = plt.gca() self.rect = Rectangle((0, 0), 1, 1, color='b', fill=False) self.x0 = None self.y0 = None self.x1 = None self.y1 = None self.ax.add_patch(self.rect) self.ax.figure.canvas.mpl_connect('button_press_event', self.on_press) self.ax.figure.canvas.mpl_connect('button_release_event', self.on_release) self.ax.figure.canvas.mpl_connect('motion_notify_event', self.on_motion) def on_press(self, event): self.x0 = event.xdata self.y0 = event.ydata self.isPressed = True def on_motion(self, event): if self.isPressed: self.x1 = event.xdata self.y1 = event.ydata self.draw_rect() def on_release(self, event): self.isPressed = False if event.xdata is not None and event.ydata is not None: self.x1 = event.xdata self.y1 = event.ydata self.draw_rect() else: print "Mouse must be released within the axes, try again." def draw_rect(self): self.rect.set_width(self.x1 - self.x0) self.rect.set_height(self.y1 - self.y0) self.rect.set_xy((self.x0, self.y0)) self.ax.figure.canvas.draw() def asXYWH(self): return (min(self.x0, self.x1), min(self.y0, self.y1), abs(self.x1 - self.x0), abs(self.y1 - self.y0))
class Plotcanvas_with_rect(FigureCanvas): def __init__(self, parent=None, width=8, height=8, dpi=100, topo=[], cmap='binary'): self.fig = Figure(figsize=(width, height), dpi=dpi) self.fig.set_tight_layout({'pad': 0, 'w_pad': 0, 'h_pad': 0}) self.fig.set_constrained_layout_pads(w_pad=0, h_pad=0, wspace=0, hspace=0) self.cmap = cmap self.topo = topo self.axs = self.fig.add_subplot(111) FigureCanvas.__init__(self, self.fig) self.axs.pcolormesh(self.topo, cmap=plt.get_cmap(cmap)) self.rect = Rectangle((0, 0), 0.2, 0.2, color='k', fill=None, alpha=1) self.axs.add_patch(self.rect) self.rect.set_visible(False) self.fig.canvas.draw() self.show() self.fig.canvas.mpl_connect('button_press_event', self.on_click) self.fig.canvas.mpl_connect('motion_notify_event', self.on_motion) def on_click(self, event): if event.button == 1 or event.button == 3: if event.inaxes is not None: self.xclick = event.xdata self.yclick = event.ydata self.onpress = True def on_motion(self, event): if event.button == 1 or event.button == 3 and self.on_press == True: if (self.xclick is not None and self.yclick is not None): x0, y0 = self.xclick, self.yclick x1, y1 = event.xdata, event.ydata if (x1 is not None or y1 is not None): self.rect.set_width(x1 - x0) self.rect.set_height(y1 - y0) self.rect.set_xy((x0, y0)) self.rect.set_visible(True) self.draw() # self.canvas.drawRectangle(self.rect)
class RectangleRegionSelector(object): isPressed = False def __init__(self): self.ax = plt.gca() self.rect = Rectangle((0, 0), 1, 1, color='b', fill=False) self.x0 = None self.y0 = None self.x1 = None self.y1 = None self.ax.add_patch(self.rect) self.ax.figure.canvas.mpl_connect('button_press_event', self.on_press) self.ax.figure.canvas.mpl_connect('button_release_event', self.on_release) self.ax.figure.canvas.mpl_connect('motion_notify_event', self.on_motion) def on_press(self, event): self.x0 = event.xdata self.y0 = event.ydata self.isPressed = True def on_motion(self, event): if self.isPressed: self.x1 = event.xdata self.y1 = event.ydata self.draw_rect() def on_release(self, event): self.isPressed = False if event.xdata is not None and event.ydata is not None: self.x1 = event.xdata self.y1 = event.ydata self.draw_rect() else: print "Mouse must be released within the axes, try again." def draw_rect(self): self.rect.set_width(self.x1 - self.x0) self.rect.set_height(self.y1 - self.y0) self.rect.set_xy((self.x0, self.y0)) self.ax.figure.canvas.draw() def asXYWH(self): return (min(self.x0, self.x1), min(self.y0, self.y1), abs(self.x1-self.x0), abs(self.y1-self.y0))
def UpdateZoomGizmo(scale, xrange, yrange): global axis, zoom_factor, img_offset, z_container, z_box aspect = yrange / xrange # Change the size of the Gizmo size = 320 if zoom_factor > 1: gizmo_w = size * scale gizmo_h = size * scale * aspect gizmo_pos = img_offset[0] - xrange * scale, img_offset[ 1] + yrange * scale - gizmo_h if z_container is None: z_container = Rectangle(gizmo_pos, gizmo_w, gizmo_h, edgecolor="w", facecolor='none') z_container.label = "zoom_container" z_box = Rectangle(gizmo_pos, gizmo_w, gizmo_h, alpha=0.5) z_box.label = "zoom_box" axis.add_artist(z_container) axis.add_artist(z_box) else: z_container.set_xy(gizmo_pos) z_container.set_width(gizmo_w) z_container.set_height(gizmo_h) z_box.set_x(gizmo_pos[0] + 0.5 * (img_offset[0] * gizmo_w / xrange - gizmo_w * scale)) z_box.set_y(gizmo_pos[1] + 0.5 * (img_offset[1] * gizmo_h / yrange - gizmo_h * scale)) z_box.set_width(gizmo_w * scale) z_box.set_height(gizmo_h * scale) else: if z_container is not None: z_container.remove() z_container = None z_box.remove() z_box = None
class AxesSelectBlobImage(BoardFreeHand): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.binary_image = [] self.rectangle = Rectangle((np.nan, np.nan), np.nan, np.nan, linewidth=1, edgecolor='g', facecolor='none') self.ax.add_patch(self.rectangle) # protected self._command = [] @property def command(self): return self.__command def command(self, command): # check if the command is lambda expression if callable(command): self._command = command def set_binary_image(self, binary_image: np.array): self.binary_image = binary_image self.ax.imshow(binary_image) pass def draw_on(self, x0: int, y0: int, drawcolor='black', size=1): if callable(self.command): self.command(x0, y0, self.binary_image) else: blob = blob_select(self.binary_image, x0, y0) ROI = blob['ROI'] self.rectangle.set_x(ROI['x']) self.rectangle.set_y(ROI['y']) self.rectangle.set_width(ROI['width']) self.rectangle.set_height(ROI['height']) # Add the patch to the Axes pass
class selectRect(object): """ Draws a rectangle on a figure and keeps track of the rectangle's size and location. Used to select the target image data. Attributes ---------- x0 : float64 X coordinate (row) of start of rectangle. y0 : float 64 Y coordinate (column) of start of rectangle. x1 : float64 X coordinate (row) of end of rectangle. y1 : float 64 Y coordinate (column) of end of rectangle. """ def __init__(self): self.ax = plt.gca() self.rect = Rectangle((0, 0), 1, 1, facecolor='none', edgecolor='#6CFF33', linewidth=3) self.x0 = None self.y0 = None self.x1 = None self.y1 = None self.ax.add_patch(self.rect) self.ax.figure.canvas.mpl_connect('button_press_event', self.on_press) self.ax.figure.canvas.mpl_connect('button_release_event', self.on_release) def on_press(self, event): self.x0 = event.xdata self.y0 = event.ydata def on_release(self, event): self.x1 = event.xdata self.y1 = event.ydata self.rect.set_width(self.x1 - self.x0) self.rect.set_height(self.y1 - self.y0) self.rect.set_xy((self.x0, self.y0)) self.ax.figure.canvas.draw()
def visualize_generation(self, generation): """ Draw each ab combination color and size coded :param generation: :param ax: :return: """ fig, ax = plt.subplots() # ax.clear() for ind in range(len(self.ga_solver.population[generation])): child = self.ga_solver.population[generation][ind] xy = self._ab_to_xy(child) rect = Rectangle(xy=xy, width=0.5, height=0.5, angle=90) ax.add_artist(rect) rect.set_clip_box(ax.bbox) # alpha = float(child[3]) / ANTIBODY_CNT # rgb = [float(child[0])/ANTIBODY_CNT, float(child[1])/ANTIBODY_CNT, float(child[2])/ANTIBODY_CNT/ ANTIBODY_CNT] # # rect.set_alpha(alpha) # rect.set_facecolor(rgb) fitness = self.ga_solver.get_fitness_value(child) if fitness > 0.5: rect.set_facecolor('r') else: rect.set_facecolor('b') rect.set_width(fitness * 100) rect.set_height(fitness * 100) ax.set_xlim( 0, self.ga_solver.antibody_cnt * self.ga_solver.antibody_cnt + 10) ax.set_ylim( 0, self.ga_solver.antibody_cnt * self.ga_solver.antibody_cnt + 10) plt.show() plt.pause(1) plt.close()
def get_score(self,event): # if self.handle==None: # self.handle = get_handle() # im = prtsc(self.handle) if isinstance(self.origin_img,np.ndarray) and isinstance(self.cut_img,np.ndarray): pass else: wx.MessageBox("请先载入并裁剪相应图像") return im = self.origin_img #changed to BGR aligned to the cv2 #im = im [:,:,::-1] window_resolution = globalvar.get_window_resolution() max_resolution = self.origin_res match_im = config_ark.pic_resize(self.cut_img,window_resolution,max_resolution) results = pic_locate(match_im,im,0.8,True,True) if results: for i in results: pos = i['rectangle'][0] width = i['rectangle'][2][0] - i['rectangle'][0][0] height = i['rectangle'][1][1] - i['rectangle'][0][1] # Draw the bounding rectangle #self.rect = Rectangle((0, 0), 0, 0, facecolor='None', edgecolor='red') #self.axes.add_patch(self.rect) tmp_rect = Rectangle((0, 0), 0, 0, facecolor='None', edgecolor='red') tmp_rect.set_width(width) tmp_rect.set_height(height) tmp_rect.set_xy(pos) self.axes.add_patch(tmp_rect) #tmp_rect.remove() self.draws.append(tmp_rect) #self.text = plt.text(pos[0],pos[1],"{0:.4f}".format(i['confidence'])) tmp_text = self.axes.text(pos[0],pos[1],"{0:.3f}".format(i['confidence']),fontdict={'color':'red','size':12}, bbox=dict(facecolor='white', alpha=0.8)) #tmp_text.remove() self.draws.append(tmp_text) self.canvas.draw() for j in self.draws: j.remove() self.draws = [] else: wx.MessageBox("模拟器中没有包含所选图像")
class RectSelect(object): ''' region = RectSelect() plt.show() ''' def __init__(self, ax=None): self.ax = ax or plt.gca() self.rect = Rectangle((0, 0), 0, 0, color='orange', alpha=0.5) self.ax.add_patch(self.rect) self.blc = np.zeros(2) self.brc = np.zeros(2) self.tlc = np.zeros(2) self.trc = np.zeros(2) def selector(event): if event.key in ['Q', 'q'] and selector.RS.active: print('RectangleSelector deactivated.') selector.RS.set_active(False) if event.key in ['A', 'a'] and not selector.RS.active: print('RectangleSelector activated.') selector.RS.set_active(True) selector.RS = RectangleSelector(self.ax, self.callback) self.ax.figure.canvas.mpl_connect('key_press_event', selector) self.ax.figure.canvas.mpl_connect('button_release_event', self.release) def callback(self, eclick, erelease): x0, x1 = eclick.xdata, erelease.xdata y0, y1 = eclick.ydata, erelease.ydata self.blc = min(x0, x1), min(y0, y1) self.brc = max(x0, x1), min(y0, y1) self.tlc = min(x0, x1), max(y0, y1) self.trc = max(x0, x1), max(y0, y1) blc_print = '({:0.4},{:0.4})'.format(*self.blc) trc_print = '({:0.4},{:0.4})'.format(*self.trc) print('blc={}, trc={}'.format(blc_print, trc_print)) def release(self, event): self.rect.set_width(self.trc[0] - self.blc[0]) self.rect.set_height(self.trc[1] - self.blc[1]) self.rect.set_xy(self.blc) self.ax.figure.canvas.draw()
class Annotate(object): def __init__(self, image): self.ax = plt.gca() self.ax.imshow(image) self.rect = Rectangle((0, 0), 1, 1) self.rect.fill = False self.x0 = self.y0 = self.x1 = self.y1 = None self.pressing = False self.ax.add_patch(self.rect) self.ax.figure.canvas.mpl_connect('button_press_event', self.on_press) self.ax.figure.canvas.mpl_connect('motion_notify_event', self.motion) self.ax.figure.canvas.mpl_connect('button_release_event', self.on_release) self.ax.figure.canvas.mpl_connect('key_press_event', self.on_key) def run(self): plt.show() def on_press(self, event): self.x0 = event.xdata self.y0 = event.ydata self.pressing = True def motion(self, event): if self.pressing: x1 = event.xdata y1 = event.ydata self.rect.set_width(x1 - self.x0) self.rect.set_height(y1 - self.y0) self.rect.set_xy((self.x0, self.y0)) self.ax.figure.canvas.draw() def on_release(self, event): self.x1 = event.xdata self.y1 = event.ydata self.pressing = False def on_key(self, event): if event.key == 'enter' and a.x1: plt.close()
class Annotate(object): def __init__(self,ax=None): if ax==None: self.ax = plt.gca() else: self.ax = ax self.rect = Rectangle((0,0), 0, 0, facecolor='yellow', edgecolor='yellow', alpha=.5, \ zorder=10, clip_on=False) self.x0 = None self.y0 = None self.x1 = None self.y1 = None self.is_pressed = False self.ax.add_patch(self.rect) self.ax.figure.canvas.mpl_connect('button_press_event', self.on_press) self.ax.figure.canvas.mpl_connect('button_release_event', self.on_release) self.ax.figure.canvas.mpl_connect('motion_notify_event', self.on_motion) def on_press(self, event): self.is_pressed = True print 'press' self.x0 = event.xdata self.y0 = event.ydata self.x1 = event.xdata self.y1 = event.ydata if not np.any( [c==None for c in [self.x0,self.y0,self.x1,self.y1]] ): self.rect.set_width(self.x1 - self.x0) self.rect.set_height(self.y1 - self.y0) self.rect.set_xy((self.x0, self.y0)) self.rect.set_linestyle('dashed') self.ax.figure.canvas.draw() def on_motion(self,event): if self.is_pressed is True: self.x1 = event.xdata self.y1 = event.ydata if not np.any( [c==None for c in [self.x0,self.y0,self.x1,self.y1]] ): self.rect.set_width(self.x1 - self.x0) self.rect.set_height(self.y1 - self.y0) self.rect.set_xy((self.x0, self.y0)) self.rect.set_linestyle('dashed') self.ax.figure.canvas.draw() def on_release(self, event): self.is_pressed = False print 'release' self.x1 = event.xdata self.y1 = event.ydata if not np.any( [c==None for c in [self.x0,self.y0,self.x1,self.y1]] ): self.rect.set_width(self.x1 - self.x0) self.rect.set_height(self.y1 - self.y0) self.rect.set_xy((self.x0, self.y0)) self.rect.set_linestyle('solid') self.ax.figure.canvas.draw() print self.x0,self.y0,self.x1,self.y1 if self.x0==self.x1 and self.y0==self.y1: print type(self.__bases__)
class GaussianSelector: """ GaussianSelector is a class for hand-fitting Gaussian components. Taken and tweaked from SMR's pygaussfit.py """ def __init__(self, ax, profile, errs, tau=0.0, fixscat=True, auto_gauss=0.0, profile_fit_flags=None, minspanx=None, minspany=None, useblit=True): """ Initialize the input parameters and open the interactive window. ax is a pyplot axis. profile is an array of pulse profile data values. errs specifies the uncertainty on the profile values. tau is a scattering timescale [bin]. fixscat=True does not fit for the scattering timescale. auto_gauss != 0.0 specifies the initial guess at a width [rot] of a single Gaussian component to be fit automatically. profile_fit_flags is an array specifying which of the non-scattering parameters to fit; defaults to fitting all. minspanx, minspany are vestigial. useblit should be True. """ if not auto_gauss: print "" print "=============================================" print "Left mouse click to draw a Gaussian component" print "Middle mouse click to fit components to data" print "Right mouse click to remove last component" print "=============================================" print "Press 'q' or close window when done fitting" print "=============================================" self.ax = ax.axes self.profile = profile self.proflen = len(profile) self.phases = np.arange(self.proflen, dtype='d') / self.proflen self.errs = errs self.tauguess = tau #in bins self.fit_scattering = not fixscat if self.fit_scattering and self.tauguess == 0.0: self.tauguess = 0.1 #seems to break otherwise self.profile_fit_flags = profile_fit_flags self.visible = True self.DCguess = sorted(profile)[len(profile)/10 + 1] self.init_params = [self.DCguess, self.tauguess] self.ngauss = 0 self.canvas = ax.figure.canvas self.canvas.mpl_connect('motion_notify_event', self.onmove) self.canvas.mpl_connect('button_press_event', self.press) self.canvas.mpl_connect('button_release_event', self.release) self.canvas.mpl_connect('draw_event', self.update_background) self.canvas.mpl_connect('key_press_event', self.keypress) self.background = None self.rectprops = dict(facecolor='white', edgecolor = 'black', alpha=0.5, fill=False) self.to_draw = Rectangle((0,0), 0, 1, visible=False, **self.rectprops) self.ax.add_patch(self.to_draw) self.useblit = useblit self.minspanx = minspanx self.minspany = minspany # will save the data (position at mouseclick) self.eventpress = None # will save the data (pos. at mouserelease) self.eventrelease = None self.plot_gaussians(self.init_params) self.auto_gauss = auto_gauss if self.auto_gauss: amp = self.profile.max() wid = self.auto_gauss first_gauss = amp*gaussian_profile(self.proflen, 0.5, wid) loc = 0.5 + fit_phase_shift(self.profile, first_gauss, self.errs).phase self.init_params += [loc, wid, amp] self.ngauss += 1 self.plot_gaussians(self.init_params) print "Auto-fitting a single Gaussian component..." fgp = fit_gaussian_profile(self.profile, self.init_params, np.zeros(self.proflen) + self.errs, self.profile_fit_flags, self.fit_scattering, quiet=True) self.fitted_params = fgp.fitted_params self.fit_errs = fgp.fit_errs self.chi2 = fgp.chi2 self.dof = fgp.dof self.residuals = fgp.residuals # scaled uncertainties #scaled_fit_errs = fit_errs * np.sqrt(chi_sq / dof) # Plot the best-fit profile self.plot_gaussians(self.fitted_params) fitprof = gen_gaussian_profile(self.fitted_params, self.proflen) plt.plot(self.phases, fitprof, c='black', lw=1) plt.draw() # Plot the residuals plt.subplot(212) plt.cla() residuals = self.profile - fitprof plt.plot(self.phases, residuals, 'k') plt.xlabel('Pulse Phase') plt.ylabel('Data-Fit Residuals') plt.draw() self.eventpress = None # will save the data (pos. at mouserelease) self.eventrelease = None def update_background(self, event): """force an update of the background""" if self.useblit: self.background = self.canvas.copy_from_bbox(self.ax.bbox) def ignore(self, event): """return True if event should be ignored""" # If no button was pressed yet ignore the event if it was out # of the axes if self.eventpress == None: return event.inaxes != self.ax # If a button was pressed, check if the release-button is the # same. return (event.inaxes != self.ax or event.button != self.eventpress.button) def press(self, event): """on button press event""" # Is the correct button pressed within the correct axes? if self.ignore(event): return # make the drawed box/line visible get the click-coordinates, # button, ... self.eventpress = event if event.button == 1: self.to_draw.set_visible(self.visible) self.eventpress.ydata = self.DCguess def release(self, event): """on button release event""" if self.eventpress is None or self.ignore(event): return # release coordinates, button, ... self.eventrelease = event if event.button == 1: # make the box/line invisible again self.to_draw.set_visible(False) self.canvas.draw() xmin, ymin = self.eventpress.xdata, self.eventpress.ydata xmax, ymax = self.eventrelease.xdata, self.eventrelease.ydata # calculate dimensions of box if xmin > xmax: xmin, xmax = xmax, xmin if ymin > ymax: ymin, ymax = ymax, ymin spanx = xmax - xmin spany = ymax - ymin xproblems = self.minspanx is not None and spanx < self.minspanx yproblems = self.minspany is not None and spany < self.minspany # call desired function self.onselect() self.eventpress = None # reset the variables to their self.eventrelease = None # inital values def update(self): """draw using blit or old draw depending on useblit""" if self.useblit: if self.background is not None: self.canvas.restore_region(self.background) self.ax.draw_artist(self.to_draw) self.canvas.blit(self.ax.bbox) else: self.canvas.draw_idle() def onmove(self, event): """on move event""" if self.eventpress is None or self.ignore(event): return x, y = event.xdata, event.ydata # actual position # with button still pressed minx, maxx = self.eventpress.xdata, x # click-x and actual mouse-x miny, maxy = self.eventpress.ydata, y # click-y and actual mouse-y if minx > maxx: minx, maxx = maxx, minx # get them in the right order if miny > maxy: miny, maxy = maxy, miny self.to_draw.set_x(minx) # set lower left of box self.to_draw.set_y(miny) self.to_draw.set_width(maxx - minx) # set width and height of box self.to_draw.set_height(maxy - miny) self.update() def keypress(self, event): """on key press event""" if self.ignore(event): return self.eventpress = event if event.key == 'q': self.eventpress = None self.close() def plot_gaussians(self, params): """plot Gaussian components and profile""" plt.subplot(211) plt.cla() # Re-plot the original profile plt.hlines(0, 0.0, 1.0, color='black', lw=1, alpha=0.3, linestyle=':') plt.plot(self.phases, self.profile, c='black', lw=3, alpha=0.3) plt.xlabel('Pulse Phase') plt.ylabel('Pulse Amplitude') prefit_buff = 0.1 postfit_buff = 0.1 if self.fit_scattering: prefit_buff = 1.0 ymin,ymax = plt.ylim() ymin = params[0] - prefit_buff*(self.profile.max()-self.profile.min()) ymax = self.profile.max() + prefit_buff * \ (self.profile.max()-self.profile.min()) plt.ylim(ymin, ymax) DC = params[0] tau = params[1] # Plot the individual Gaussians max_amp = 0.0 for igauss in range(self.ngauss): loc, wid, amp = params[(2 + igauss*3):(5 + igauss*3)] if amp >= max_amp: max_amp = amp plt.plot(self.phases, DC + amp*gaussian_profile(self.proflen, loc, wid), '%s'%cols[igauss]) if max_amp > ymax: plt.ylim(ymin, max_amp + postfit_buff * \ (max_amp - self.profile.min())) def onselect(self): """on select event""" event1 = self.eventpress event2 = self.eventrelease # Left mouse button = add a Gaussian if event1.button == event2.button == 1: x1, y1 = event1.xdata, event1.ydata x2, y2 = event2.xdata, event2.ydata loc = 0.5 * (x1 + x2) wid = np.fabs(x2 - x1) #amp = np.fabs(1.05 * (y2 - self.init_params[0]) * (x2 - x1)) amp = np.fabs(1.05 * (y2 - self.init_params[0])) self.init_params += [loc, wid, amp] self.ngauss += 1 self.plot_gaussians(self.init_params) plt.draw() # Middle mouse button = fit the Gaussians elif event1.button == event2.button == 2: print "Fitting reference Gaussian profile..." fgp = fit_gaussian_profile(self.profile, self.init_params, np.zeros(self.proflen) + self.errs, self.profile_fit_flags, self.fit_scattering, quiet=True) self.fitted_params = fgp.fitted_params self.fit_errs = fgp.fit_errs self.chi2 = fgp.chi2 self.dof = fgp.dof self.residuals = fgp.residuals # scaled uncertainties #scaled_fit_errs = fit_errs * np.sqrt(chi_sq / dof) # Plot the best-fit profile self.plot_gaussians(self.fitted_params) fitprof = gen_gaussian_profile(self.fitted_params, self.proflen) plt.plot(self.phases, fitprof, c='black', lw=1) plt.draw() # Plot the residuals plt.subplot(212) plt.cla() residuals = self.profile - fitprof plt.plot(self.phases, residuals, 'k') plt.xlabel('Pulse Phase') plt.ylabel('Data-Fit Residuals') plt.draw() # Right mouse button = remove last Gaussian elif event1.button == event2.button == 3: if self.ngauss: self.init_params = self.init_params[:-3] self.ngauss -= 1 self.plot_gaussians(self.init_params) plt.draw() plt.subplot(212) plt.cla() plt.xlabel('Pulse Phase') plt.ylabel('Data-Fit Residuals') plt.draw() def close(self): """close""" plt.close(1) plt.close(2)
class GaussianSelector: def __init__(self, ax, profile, errs, profnm, minspanx=None, minspany=None, useblit=True): self.ax = ax.axes self.profile = profile self.proflen = len(profile) self.profnm = profnm self.phases = Num.arange(self.proflen, dtype='d')/self.proflen self.errs = errs self.visible = True self.DCguess = sorted(profile)[len(profile)/10+1] self.init_params = [self.DCguess] self.numgaussians = 0 self.canvas = ax.figure.canvas self.canvas.mpl_connect('motion_notify_event', self.onmove) self.canvas.mpl_connect('button_press_event', self.press) self.canvas.mpl_connect('button_release_event', self.release) self.canvas.mpl_connect('draw_event', self.update_background) self.background = None self.rectprops = dict(facecolor='white', edgecolor = 'black', alpha=0.5, fill=False) self.to_draw = Rectangle((0,0), 0, 1, visible=False, **self.rectprops) self.ax.add_patch(self.to_draw) self.useblit = useblit self.minspanx = minspanx self.minspany = minspany # will save the data (position at mouseclick) self.eventpress = None # will save the data (pos. at mouserelease) self.eventrelease = None self.plot_gaussians(self.init_params) def update_background(self, event): 'force an update of the background' if self.useblit: self.background = self.canvas.copy_from_bbox(self.ax.bbox) def ignore(self, event): 'return True if event should be ignored' # If no button was pressed yet ignore the event if it was out # of the axes if self.eventpress == None: return event.inaxes!= self.ax # If a button was pressed, check if the release-button is the # same. return (event.inaxes!=self.ax or event.button != self.eventpress.button) def press(self, event): 'on button press event' # Is the correct button pressed within the correct axes? if self.ignore(event): return # make the drawed box/line visible get the click-coordinates, # button, ... self.eventpress = event if event.button==1: self.to_draw.set_visible(self.visible) self.eventpress.ydata = self.DCguess def release(self, event): 'on button release event' if self.eventpress is None or self.ignore(event): return # release coordinates, button, ... self.eventrelease = event if event.button==1: # make the box/line invisible again self.to_draw.set_visible(False) self.canvas.draw() xmin, ymin = self.eventpress.xdata, self.eventpress.ydata xmax, ymax = self.eventrelease.xdata, self.eventrelease.ydata # calculate dimensions of box if xmin>xmax: xmin, xmax = xmax, xmin if ymin>ymax: ymin, ymax = ymax, ymin spanx = xmax - xmin spany = ymax - ymin xproblems = self.minspanx is not None and spanx<self.minspanx yproblems = self.minspany is not None and spany<self.minspany # call desired function self.onselect() self.eventpress = None # reset the variables to their self.eventrelease = None # inital values def update(self): 'draw using newfangled blit or oldfangled draw depending on useblit' if self.useblit: if self.background is not None: self.canvas.restore_region(self.background) self.ax.draw_artist(self.to_draw) self.canvas.blit(self.ax.bbox) else: self.canvas.draw_idle() def onmove(self, event): if self.eventpress is None or self.ignore(event): return x,y = event.xdata, event.ydata # actual position with button still pressed minx, maxx = self.eventpress.xdata, x # click-x and actual mouse-x miny, maxy = self.eventpress.ydata, y # click-y and actual mouse-y if minx>maxx: minx, maxx = maxx, minx # get them in the right order if miny>maxy: miny, maxy = maxy, miny self.to_draw.set_x(minx) # set lower left of box self.to_draw.set_y(miny) self.to_draw.set_width(maxx-minx) # set width and height of box self.to_draw.set_height(maxy-miny) self.update() def plot_gaussians(self, params): plt.subplot(211) plt.cla() # Re-plot the original profile plt.plot(self.phases, self.profile, c='black', lw=3, alpha=0.3) plt.xlabel('Pulse Phase') plt.ylabel('Pulse Amplitude') DC = params[0] # Plot the individual gaussians for ii in range(self.numgaussians): phase, FWHM, amp = params[1+ii*3:4+ii*3] plt.plot(self.phases, DC + amp*gaussian_profile(self.proflen, phase, FWHM)) def onselect(self): event1 = self.eventpress event2 = self.eventrelease # Left mouse button = add a gaussian if event1.button == event2.button == 1: x1, y1 = event1.xdata, event1.ydata x2, y2 = event2.xdata, event2.ydata phase = 0.5*(x1+x2) FWHM = Num.fabs(x2-x1) amp = Num.fabs(1.05*(y2-self.init_params[0])*(x2-x1)) self.init_params += [phase, FWHM, amp] self.numgaussians += 1 self.plot_gaussians(self.init_params) plt.draw() # Middle mouse button = fit the gaussians elif event1.button == event2.button == 2: fit_params, fit_errs, chi_sq, dof = \ fit_gaussians(self.profile, self.init_params, Num.zeros(self.proflen)+self.errs, self.profnm) # scaled uncertainties #scaled_fit_errs = fit_errs * Num.sqrt(chi_sq / dof) # Plot the best-fit profile self.plot_gaussians(fit_params) fitprof = gen_gaussians(fit_params, self.proflen) plt.plot(self.phases, fitprof, c='black', lw=1) plt.draw() # Plot the residuals plt.subplot(212) plt.cla() residuals = prof - fitprof plt.plot(self.phases, residuals) plt.xlabel('Pulse Phase') plt.ylabel('Data-Fit Residuals') plt.draw() # Right mouse button = remove last gaussian elif event1.button == event2.button == 3: if self.numgaussians: self.init_params = self.init_params[:-3] self.numgaussians -= 1 self.plot_gaussians(self.init_params) plt.draw() plt.subplot(212) plt.cla() plt.xlabel('Pulse Phase') plt.ylabel('Data-Fit Residuals') plt.draw()
class RectangleSelectImagePanel(wx.Panel): ''' Panel that contains an image that allows the users to select an area of the image with the mouse. The user clicks and holds the mouse to create a dotted rectangle, and when the mouse is released the rectangles origin, width and height can be read. The dimensions of these readings are always relative to the original image, so even if the image is scaled up larger to fit the panel the measurements will always refer to the original image.''' def __init__(self, parent, pathToImage=None): ''' Initialise the panel. Setting an initial image is optional.''' # Initialise the parent wx.Panel.__init__(self, parent) # Intitialise the matplotlib figure self.figure = plt.figure() # Create an axes, turn off the labels and add them to the figure self.axes = plt.Axes(self.figure,[0,0,1,1]) self.axes.set_axis_off() self.figure.add_axes(self.axes) # Add the figure to the wxFigureCanvas self.canvas = FigureCanvas(self, -1, self.figure) # Initialise the rectangle self.rect = Rectangle((0,0), 1, 1, facecolor='None', edgecolor='green') self.x0 = None self.y0 = None self.x1 = None self.y1 = None self.axes.add_patch(self.rect) # Sizer to contain the canvas self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer.Add(self.canvas, 3, wx.ALL) self.SetSizer(self.sizer) self.Fit() # Connect the mouse events to their relevant callbacks self.canvas.mpl_connect('button_press_event', self._onPress) self.canvas.mpl_connect('button_release_event', self._onRelease) self.canvas.mpl_connect('motion_notify_event', self._onMotion) # Lock to stop the motion event from behaving badly when the mouse isn't pressed self.pressed = False # If there is an initial image, display it on the figure if pathToImage is not None: self.setImage(pathToImage) def _onPress(self, event): ''' Callback to handle the mouse being clicked and held over the canvas''' # Check the mouse press was actually on the canvas if event.xdata is not None and event.ydata is not None: # Upon initial press of the mouse record the origin and record the mouse as pressed self.pressed = True self.rect.set_linestyle('dashed') self.x0 = event.xdata self.y0 = event.ydata def _onRelease(self, event): '''Callback to handle the mouse being released over the canvas''' # Check that the mouse was actually pressed on the canvas to begin with and this isn't a rouge mouse # release event that started somewhere else if self.pressed: # Upon release draw the rectangle as a solid rectangle self.pressed = False self.rect.set_linestyle('solid') # Check the mouse was released on the canvas, and if it wasn't then just leave the width and # height as the last values set by the motion event if event.xdata is not None and event.ydata is not None: self.x1 = event.xdata self.y1 = event.ydata # Set the width and height and origin of the bounding rectangle self.boundingRectWidth = self.x1 - self.x0 self.boundingRectHeight = self.y1 - self.y0 self.bouningRectOrigin = (self.x0, self.y0) # Draw the bounding rectangle self.rect.set_width(self.boundingRectWidth) self.rect.set_height(self.boundingRectHeight) self.rect.set_xy((self.x0, self.y0)) self.canvas.draw() def _onMotion(self, event): '''Callback to handle the motion event created by the mouse moving over the canvas''' # If the mouse has been pressed draw an updated rectangle when the mouse is moved so # the user can see what the current selection is if self.pressed: # Check the mouse was released on the canvas, and if it wasn't then just leave the width and # height as the last values set by the motion event if event.xdata is not None and event.ydata is not None: self.x1 = event.xdata self.y1 = event.ydata # Set the width and height and draw the rectangle self.rect.set_width(self.x1 - self.x0) self.rect.set_height(self.y1 - self.y0) self.rect.set_xy((self.x0, self.y0)) self.canvas.draw() def setImage(self, pathToImage): '''Sets the background image of the canvas''' # Load the image into matplotlib and PIL image = matplotlib.image.imread(pathToImage) imPIL = Image.open(pathToImage) # Save the image's dimensions from PIL self.imageSize = imPIL.size # Add the image to the figure and redraw the canvas. Also ensure the aspect ratio of the image is retained. self.axes.imshow(image,aspect='equal') self.canvas.draw()
class MplRectangularROI(AbstractMplRoi): """ A subclass of RectangularROI that also renders the ROI to a plot *Attributes*: plot_opts: Dictionary instance A dictionary of plot keywords that are passed to the patch representing the ROI. These control the visual properties of the ROI """ def __init__(self, axes): """ :param axes: A matplotlib Axes object to attach the graphical ROI to """ AbstractMplRoi.__init__(self, axes) self._xi = None self._yi = None self.plot_opts = {'edgecolor': PATCH_COLOR, 'facecolor': PATCH_COLOR, 'alpha': 0.3} self._patch = Rectangle((0., 0.), 1., 1.) self._patch.set_zorder(100) self._setup_patch() def _setup_patch(self): self._axes.add_patch(self._patch) self._patch.set_visible(False) self._sync_patch() def _roi_factory(self): return RectangularROI() def start_selection(self, event): if event.inaxes != self._axes: return False if event.key == SCRUBBING_KEY: if not self._roi.defined(): return False elif not self._roi.contains(event.xdata, event.ydata): return False self._roi_store() self._xi = event.xdata self._yi = event.ydata if event.key == SCRUBBING_KEY: self._scrubbing = True self._cx, self._cy = self._roi.center() else: self.reset() self._roi.update_limits(event.xdata, event.ydata, event.xdata, event.ydata) self._mid_selection = True self._sync_patch() def update_selection(self, event): if not self._mid_selection or event.inaxes != self._axes: return False if event.key == SCRUBBING_KEY: if not self._roi.defined(): return False if self._scrubbing: self._roi.move_to(self._cx + event.xdata - self._xi, self._cy + event.ydata - self._yi) else: self._roi.update_limits(min(event.xdata, self._xi), min(event.ydata, self._yi), max(event.xdata, self._xi), max(event.ydata, self._yi)) self._sync_patch() def finalize_selection(self, event): self._scrubbing = False self._mid_selection = False self._patch.set_visible(False) self._draw() def _sync_patch(self): if self._roi.defined(): corner = self._roi.corner() width = self._roi.width() height = self._roi.height() self._patch.set_xy(corner) self._patch.set_width(width) self._patch.set_height(height) self._patch.set(**self.plot_opts) self._patch.set_visible(True) else: self._patch.set_visible(False) self._draw() def __str__(self): return "MPL Rectangle: %s" % self._patch
class MplXRangeROI(AbstractMplRoi): def __init__(self, axes): """ :param axes: A matplotlib Axes object to attach the graphical ROI to """ AbstractMplRoi.__init__(self, axes) self._xi = None self.plot_opts = {'edgecolor': PATCH_COLOR, 'facecolor': PATCH_COLOR, 'alpha': 0.3} trans = blended_transform_factory(self._axes.transData, self._axes.transAxes) self._patch = Rectangle((0., 0.), 1., 1., transform=trans) self._patch.set_zorder(100) self._setup_patch() def _setup_patch(self): self._axes.add_patch(self._patch) self._patch.set_visible(False) self._sync_patch() def _roi_factory(self): return XRangeROI() def start_selection(self, event): if event.inaxes != self._axes: return False if event.key == SCRUBBING_KEY: if not self._roi.defined(): return False elif not self._roi.contains(event.xdata, event.ydata): return False self._roi_store() if event.key == SCRUBBING_KEY: self._scrubbing = True self._dx = event.xdata - self._roi.center() else: self.reset() self._roi.set_range(event.xdata, event.xdata) self._xi = event.xdata self._mid_selection = True self._sync_patch() def update_selection(self, event): if not self._mid_selection or event.inaxes != self._axes: return False if event.key == SCRUBBING_KEY: if not self._roi.defined(): return False if self._scrubbing: self._roi.move_to(event.xdata + self._dx) else: self._roi.set_range(min(event.xdata, self._xi), max(event.xdata, self._xi)) self._sync_patch() def finalize_selection(self, event): self._scrubbing = False self._mid_selection = False self._patch.set_visible(False) self._draw() def _sync_patch(self): if self._roi.defined(): rng = self._roi.range() self._patch.set_xy((rng[0], 0)) self._patch.set_width(rng[1] - rng[0]) self._patch.set_height(1) self._patch.set(**self.plot_opts) self._patch.set_visible(True) else: self._patch.set_visible(False) self._draw()
class PlotInterface(object): def __init__(self, df, EvT_color_set, EvT_size_set): self.df = df self.ax = plt.gca() self.rect = Rectangle((0.1,0.1), 0, 0, fill=False) self.rect.set_visible(False) self.ax.add_patch(self.rect) self.x0 = None self.y0 = None self.x1 = None self.y1 = None self.press = False self.sub_df = None self.EvT_color_set = EvT_color_set self.EvT_size_set = EvT_size_set self.ax.figure.canvas.mpl_connect('button_press_event', self.on_press) self.ax.figure.canvas.mpl_connect('motion_notify_event',self.on_motion) self.ax.figure.canvas.mpl_connect('button_release_event', self.on_release) def on_press(self, event): if event.inaxes: self.press = True self.x0 = event.xdata self.y0 = event.ydata self.rect.set_width(0) self.rect.set_height(0) self.rect.set_xy((self.x0,self.y0)) self.rect.set_visible(True) #Save the plot background self.background = self.ax.figure.canvas.copy_from_bbox(self.ax.bbox) def on_release(self, event): if event.inaxes: self.press = False self.x1 = event.xdata self.y1 = event.ydata self.rect.set_visible(False) self.ax.figure.canvas.draw() self.min_x = min(self.x0,self.x1) self.max_x = max(self.x0,self.x1) self.min_y = min(self.y0,self.y1) self.max_y = max(self.y0,self.y1) if self.sub_df is not None: self.sub_df = self.sub_df.append(self.df[ (self.df['timestamp'] > self.min_x) & (self.df['timestamp'] < self.max_x) & \ (self.df['amplitude'] > self.min_y) & (self.df['amplitude'] < self.max_y)]) else: self.sub_df = self.df[ (self.df['timestamp'] > self.min_x) & (self.df['timestamp'] < self.max_x) & \ (self.df['amplitude'] > self.min_y) & (self.df['amplitude'] < self.max_y)] plt.scatter(self.sub_df['timestamp'],self.sub_df['amplitude'],color='blue',s=self.EvT_size_set) self.ax.figure.canvas.draw() print('Selected (%d < timestamp < %d) and (%d < amplitude < %d)' % (self.min_x, self.max_x, self.min_y, self.max_y)) def on_motion(self, event): if self.press is False: return if event.inaxes != self.rect.axes: return self.x1 = event.xdata self.y1 = event.ydata self.rect.set_width(self.x1 - self.x0) self.rect.set_height(self.y1 - self.y0) self.rect.set_xy((self.x0, self.y0)) self.ax.figure.canvas.restore_region(self.background) self.ax.draw_artist(self.rect) self.ax.figure.canvas.blit(self.rect.clipbox)
class Annotate(object): def __init__(self, cloud, selection_shape, z_color=False, unlabeled_color = (1,0,0), labeled_color = (0,0,1)): self.selection_shape = selection_shape self.unlabeled_color = np.array(unlabeled_color) self.labeled_color = np.array(labeled_color) assert not np.all(unlabeled_color == labeled_color) self.fig = plt.figure('label rope ends', figsize=(24,12)) self.fig.clear() self.ax = self.fig.add_subplot(111, aspect='equal') if cloud.shape[1] == 6: self.cloud = cloud else: self.cloud = np.c_[cloud[:,:3], np.tile(self.unlabeled_color, (cloud.shape[0],1))] if z_color: z_min = self.cloud[:,2].min() z_max = self.cloud[:,2].max() self.z_color = np.empty((len(self.cloud),3)) for i in range(len(self.cloud)): f = (self.cloud[i,2] - z_min) / (z_max - z_min) self.z_color[i,:] = np.array(colorsys.hsv_to_rgb(f,1,1)) else: self.z_color = None self.scatters = [] self.rescatter_cloud() self.ax.autoscale(False) if self.selection_shape == 'rectangle' or self.selection_shape == 'square': self.rect = Rectangle((0,0), 0, 0, facecolor='None', edgecolor='green', linestyle='dashed') self.ax.add_patch(self.rect) elif self.selection_shape == 'circle': self.circle = Circle((0,0), 0, facecolor='None', edgecolor='green', linestyle='dashed') self.ax.add_patch(self.circle) self.x0 = None self.y0 = None self.x1 = None self.y1 = None self.fig.canvas.mpl_connect('button_press_event', self.on_press) self.fig.canvas.mpl_connect('button_release_event', self.on_release) self.motion_notify_cid = None self.fig.canvas.mpl_connect('key_press_event', self.on_key) plt.show() def rescatter_cloud(self): for scatter in self.scatters: scatter.remove() self.scatters = [] if self.z_color is not None: ul_inds = np.absolute((self.cloud[:,3:] - self.unlabeled_color)).sum(axis=1) == 0 # unlabeled inds self.scatters.append(plt.scatter(self.cloud[ul_inds,0], self.cloud[ul_inds,1], c=self.z_color[ul_inds,:], edgecolors=self.z_color[ul_inds,:], marker=',', s=5)) self.scatters.append(plt.scatter(self.cloud[~ul_inds,0], self.cloud[~ul_inds,1], c=self.cloud[~ul_inds,3:], edgecolors=self.cloud[~ul_inds,3:], marker='o', s=20)) else: self.scatters.append(plt.scatter(self.cloud[:,0], self.cloud[:,1], c=self.cloud[:,3:], edgecolors=self.cloud[:,3:], marker=',', s=5)) def on_press(self, event): if event.xdata < self.ax.get_xlim()[0] or event.xdata > self.ax.get_xlim()[1] or \ event.ydata < self.ax.get_ylim()[0] or event.ydata > self.ax.get_ylim()[1]: return self.x0 = event.xdata self.y0 = event.ydata self.motion_notify_cid = self.fig.canvas.mpl_connect('motion_notify_event', self.on_motion) def on_release(self, event): if self.motion_notify_cid: self.fig.canvas.mpl_disconnect(self.motion_notify_cid) self.motion_notify_cid = None if self.selection_shape == 'rectangle' or self.selection_shape == 'square': x0 = min(self.x0, self.x1) x1 = max(self.x0, self.x1) y0 = min(self.y0, self.y1) y1 = max(self.y0, self.y1) inside_rect_inds = (x0 <= self.cloud[:,0]) * (self.cloud[:,0] <= x1) * (y0 <= self.cloud[:,1]) * (self.cloud[:,1] <= y1) num_pts_inside_rect = inside_rect_inds.sum() self.cloud[inside_rect_inds,3:] = np.tile(self.labeled_color, (num_pts_inside_rect,1)) elif self.selection_shape == 'circle': inside_circle_inds = np.apply_along_axis(np.linalg.norm, 1, self.cloud[:,:2] - np.array(self.circle.center)) <= self.circle.get_radius() num_pts_inside_circle = inside_circle_inds.sum() self.cloud[inside_circle_inds,3:] = np.tile(self.labeled_color, (num_pts_inside_circle,1)) self.rescatter_cloud() plt.draw() def on_motion(self, event): if event.xdata < self.ax.get_xlim()[0] or event.xdata > self.ax.get_xlim()[1] or \ event.ydata < self.ax.get_ylim()[0] or event.ydata > self.ax.get_ylim()[1]: return if self.selection_shape == 'rectangle': self.x1 = event.xdata self.y1 = event.ydata elif self.selection_shape == 'circle' or self.selection_shape == 'square': side = max(abs(event.xdata - self.x0), abs(event.ydata - self.y0)) self.x1 = self.x0 + np.sign(event.xdata - self.x0) * side self.y1 = self.y0 + np.sign(event.ydata - self.y0) * side if self.selection_shape == 'rectangle' or self.selection_shape == 'square': self.rect.set_width(self.x1 - self.x0) self.rect.set_height(self.y1 - self.y0) self.rect.set_xy((self.x0, self.y0)) elif self.selection_shape == 'circle': self.circle.center = ((self.x1 + self.x0)/2.0, (self.y0 + self.y1)/2.0) self.circle.set_radius(side/2.0) plt.draw() def on_key(self, event): if event.key == 'q': sys.exit(0) if event.key == 'd': plt.close(self.fig)
def display_bx(): bx[0].cla() bx[1].cla() bx[3].cla() bx[4].cla() bx[5].cla() bx[0].text(20, 0.0, r'g-r', fontsize=15) bx[1].text(20, 0.0, r'g-i', fontsize=15) bx[3].text(20, 2, r'r-i', fontsize=15) bx[4].text(20, 2, r'i-z', fontsize=15) bx[5].text(20, 2, r'r-z', fontsize=15) bx[0].scatter(self.gr_mag_all, self.gr_color_all,color="black", marker='.',s=1) bx[1].scatter(self.gi_mag_all, self.gi_color_all,color="black", marker='.',s=1) bx[3].scatter(self.ri_mag_all, self.ri_color_all,color="black", marker='.',s=1) bx[4].scatter(self.iz_mag_all, self.iz_color_all,color="black", marker='.',s=1) bx[5].scatter(self.rz_mag_all, self.rz_color_all,color="black", marker='.',s=1) if len(self.ra) > 1: bx[0].scatter(self.r_mag,self.gr_color,marker='o',s=40,color="blue") bx[1].scatter(self.i_mag,self.gi_color,marker='o',s=40,color="green") bx[3].scatter(self.r_mag,self.ri_color,marker='o',s=40,color="orange") bx[4].scatter(self.i_mag,self.iz_color,marker='o',s=40,color="red") bx[5].scatter(self.i_mag,self.rz_color,marker='o',s=40,color="magenta") if len(self.zra) > 1: bx[0].scatter(self.z_gr_mag,self.z_gr_color,color="cyan",marker='s',s=5) bx[1].scatter(self.z_gi_mag,self.z_gi_color,color="cyan",marker='s',s=5) bx[3].scatter(self.z_ri_mag,self.z_ri_color,color="cyan",marker='s',s=5) bx[4].scatter(self.z_iz_mag,self.z_iz_color,color="cyan",marker='s',s=5) bx[5].scatter(self.z_rz_mag,self.z_rz_color,color="cyan",marker='s',s=5) if len(self.bcg_ra>1): bx[0].scatter(self.bcg_r_mag,self.bcg_gr_color,color="red",marker=(5, 0),s=250, alpha=0.2) bx[1].scatter(self.bcg_i_mag,self.bcg_gi_color,color="red",marker=(5, 0),s=250, alpha=0.2) bx[3].scatter(self.bcg_r_mag,self.bcg_ri_color,color="red",marker=(5, 0),s=250, alpha=0.2) bx[4].scatter(self.bcg_i_mag,self.bcg_iz_color,color="red",marker=(5, 0),s=250, alpha=0.2) bx[5].scatter(self.bcg_i_mag,self.bcg_rz_color,color="red",marker=(5, 0),s=250, alpha=0.2) if self.temp_gr_color !=-100: bx[0].scatter(self.temp_r_mag, self.temp_gr_color, color="black", marker=(5, 2), s=250, alpha=0.4) bx[1].scatter(self.temp_i_mag, self.temp_gi_color, color="black", marker=(5, 2), s=250, alpha=0.4) bx[3].scatter(self.temp_r_mag, self.temp_ri_color, color="black", marker=(5, 2), s=250, alpha=0.4) bx[4].scatter(self.temp_i_mag, self.temp_iz_color, color="black", marker=(5, 2), s=250, alpha=0.4) bx[5].scatter(self.temp_i_mag, self.temp_rz_color, color="black", marker=(5, 2), s=250, alpha=0.4) if (self.gr_xbot != 0): rect = Rectangle( ( 0,0 ), 1, 1, alpha = 0.2, ec = "gray", fc = "CornflowerBlue", visible = True, axes=bx[0]) rect.set_width(self.gr_xtop - self.gr_xbot) rect.set_height(self.gr_ytop - self.gr_ybot) rect.set_xy((self.gr_xbot, self.gr_ybot)) bx[0].add_patch(rect) if (self.gi_xbot != 0): rect = Rectangle( ( 0,0 ), 1, 1, alpha = 0.2, ec = "gray", fc = "CornflowerBlue", visible = True, axes=bx[1]) rect.set_width(self.gi_xtop - self.gi_xbot) rect.set_height(self.gi_ytop - self.gi_ybot) rect.set_xy((self.gi_xbot, self.gi_ybot)) bx[1].add_patch(rect) if (self.ri_xbot != 0): rect = Rectangle( ( 0,0 ), 1, 1, alpha = 0.2, ec = "gray", fc = "CornflowerBlue", visible = True, axes=bx[3]) rect.set_width(self.ri_xtop - self.ri_xbot) rect.set_height(self.ri_ytop - self.ri_ybot) rect.set_xy((self.ri_xbot, self.ri_ybot)) bx[3].add_patch(rect) if (self.iz_xbot != 0): rect = Rectangle( ( 0,0 ), 1, 1, alpha = 0.2, ec = "gray", fc = "CornflowerBlue", visible = True, axes=bx[4]) rect.set_width(self.iz_xtop - self.iz_xbot) rect.set_height(self.iz_ytop - self.iz_ybot) rect.set_xy((self.iz_xbot, self.iz_ybot)) bx[4].add_patch(rect) if (self.rz_xbot != 0): rect = Rectangle( ( 0,0 ), 1, 1, alpha = 0.2, ec = "gray", fc = "CornflowerBlue", visible = True, axes=bx[5]) rect.set_width(self.rz_xtop - self.rz_xbot) rect.set_height(self.rz_ytop - self.rz_ybot) rect.set_xy((self.rz_xbot, self.rz_ybot)) bx[5].add_patch(rect) bx.set_xlim(16, 24) bx.set_ylim(-0.2, 3.5) bx.axes_llc.set_xlabel("magnitude") bx.axes_llc.set_ylabel("color") fig2.suptitle('Measured Redshift = '+'{: .3f}'.format(xcs_z), fontsize=20) fig2.canvas.draw()
def handle_event(): global command global command_meta global main_pic global history global patch global patches global click_handlers global G if command=="horizontal_line" or command=="vertical_line": h,w = main_pic.shape[:2] if patch is not None: w1,h1 = patch.get_xy() if command=="horizontal_line": line = Line(0,int(h1),w,int(h1), int(patch.get_height()), magenta) else: line = Line(int(w1),0,int(w1),h, int(patch.get_width()), magenta) main_pic = draw_line_on_picture(main_pic, line) patch=None else: if command=="horizontal_line": patch = Rectangle((0,0), w, 1, edgecolor='magenta', alpha=1) else: patch = Rectangle((0,0), 1, h, edgecolor='magenta', alpha=1) if command=="needle" or command=="angle_needle": G["needle"]["active"] = True just_added_patch = False if "pt1" in G["needle"] and "pt2" in G["needle"]: if patch is None: print "Drawing needle patch" pt1 = G["needle"]["pt1"] pt2 = G["needle"]["pt2"] if command=="needle": patch = Rectangle((pt1[0], pt1[1]), abs(pt2[0]-pt1[0]), abs(pt2[1]-pt1[1]), edgecolor='magenta', alpha=1, facecolor='magenta') else: patch = Polygon(np.array([pt1, pt2, p(pt1), p(pt2)]), closed=False, edgecolor='magenta', alpha=1, facecolor='magenta') angle = get_angle(pt1, pt2) print ("Angle :{}".format(angle)) # how to add text? just_added_patch = True if patch is not None and not just_added_patch: if isinstance(patch, Polygon): patches.append(patch) patch=None else: print "finalize" w1,h1 = patch.get_xy() w = patch.get_width() h = patch.get_height() if w>h: print("horizontal patch") line = Line(int(w1),int(h1),int(w1+w),int(h1), 3, magenta) else: line = Line(int(w1),int(h1),int(w1),int(h1+h), 3, magenta) main_pic = draw_line_on_picture(main_pic, line) G["needle"] = {} if command == "divide": divide(command_meta.xdata, command_meta.ydata) if command == "brighten": main_pic = do_brighten(main_pic) if command == "mirror": main_pic = np.fliplr(main_pic) if command == "zoom": click_handlers = not click_handlers if command == "darken": main_pic = do_darken(main_pic) if command == "edge": main_pic = edge_detect(main_pic) if command == "resize_patch": if patch is not None: h = patch.get_height() w = patch.get_width() patch.set_width(int(w * 0.9)) patch.set_height(int(h * 0.9)) if command == "crop": if patch is not None: # apply patch # crop main_pic h = patch.get_height() w = patch.get_width() w1,h1 = patch.get_xy() main_pic = main_pic[slice(h1,h1+h),slice(w1,w1+w),slice(None)] patch=None else: # create patch # TODO: can read this from settings :)) portrait_ratio = 14.8/20.8 if orientation=="portrait": w_to_h = portrait_ratio else: w_to_h = 1.0/portrait_ratio shape = main_pic.shape border = 15 hp = shape[0] - border wp = shape[1] - border if w_to_h * hp >wp: tw = wp th = wp / w_to_h else: th = hp tw = w_to_h * hp print th,tw patch = Rectangle((0,0), tw, th, edgecolor='magenta', alpha=1, facecolor='none') if command == "undo": print "Undoing" print len(history) if len(history)>=2: main_pic,cmd = history[-2] print cmd history = history[:-1] if command!="undo": history.append((np.copy(main_pic),command)) if command not in ["crop","horizontal_line","vertical_line","needle","angle_needle","resize_patch"]: patch = None command = None command_meta = None plot(patch=patch, click_handlers=click_handlers) if command is not None: handle_event()
class MplYRangeROI(AbstractMplRoi): """ Matplotlib ROI for y range selections Parameters ---------- axes : `~matplotlib.axes.Axes` The Matplotlib axes to draw to. """ _roi_cls = YRangeROI def __init__(self, axes): super(MplYRangeROI, self).__init__(axes) self._xi = None self.plot_opts = {'edgecolor': PATCH_COLOR, 'facecolor': PATCH_COLOR, 'alpha': 0.3} trans = blended_transform_factory(self._axes.transAxes, self._axes.transData) self._patch = Rectangle((0., 0.), 1., 1., transform=trans, zorder=100) self._patch.set_visible(False) self._axes.add_patch(self._patch) def start_selection(self, event): if event.inaxes != self._axes: return False if event.key == SCRUBBING_KEY: if not self._roi.defined(): return False elif not self._roi.contains(event.xdata, event.ydata): return False self._store_previous_roi() self._store_background() if event.key == SCRUBBING_KEY: self._scrubbing = True self._dy = event.ydata - self._roi.center() else: self.reset() self._roi.set_range(event.ydata, event.ydata) self._xi = event.ydata self._mid_selection = True self._sync_patch() self._draw() def update_selection(self, event): if not self._mid_selection or event.inaxes != self._axes: return False if event.key == SCRUBBING_KEY: if not self._roi.defined(): return False if self._scrubbing: self._roi.move_to(event.ydata + self._dy) else: self._roi.set_range(min(event.ydata, self._xi), max(event.ydata, self._xi)) self._sync_patch() self._draw() def finalize_selection(self, event): self._scrubbing = False self._mid_selection = False self._patch.set_visible(False) self._draw() def _sync_patch(self): if self._roi.defined(): rng = self._roi.range() self._patch.set_xy((0, rng[0])) self._patch.set_height(rng[1] - rng[0]) self._patch.set_width(1) self._patch.set(**self.plot_opts) self._patch.set_visible(True) else: self._patch.set_visible(False)
class set_line(object): """ Class to set a line to cross in an image Saves either an X coordinate for a vertical line or a Y coordinate for a horizontal one line will have a bit of thickness as it is essentially a very thin rectangular ROI """ def __init__(self, line_color, background_img, line_width=3, line_mode = 'vertical', roi_selection_msg = "Press the 'n' key on your keyboard when you are happy with the ROI"): self.fig, self.ax = plt.subplots() self.fig.set_size_inches((11, 8.5), forward=True) self.ax.imshow(background_img) self.fig.suptitle(roi_selection_msg, size=16) self.type = 'line' self.line_width=line_width self.color = line_color self.ax_height, self.ax_width = background_img.shape[:2] self.line_mode = line_mode self.click_pos = None self.start_pos = None self.end_pos = None self.roi = None self.roi_finalized = False self.line = Rectangle((0,0), 0, 0, color=self.color, alpha=0.4) self.ax.add_patch(self.line) self.ax.figure.canvas.mpl_connect('button_press_event', self.on_mouse_press) self.ax.figure.canvas.mpl_connect('key_press_event', self.on_key_press) def on_mouse_press(self, event): if self.roi_finalized is False: self.click_pos = np.array([event.xdata, event.ydata]) if self.line_mode is 'vertical': self.center_offset = event.xdata - self.line_width/2. self.line.set_width(self.line_width) self.line.set_height(self.ax_height) self.line.set_xy((self.center_offset, 0)) self.start_pos = np.array([self.center_offset, 0]) self.end_pos = np.array([self.center_offset + self.line_width, self.ax_height]) if self.line_mode is 'horizontal': self.center_offset = event.ydata - self.line_width/2. self.line.set_width(self.ax_width) self.line.set_height(self.line_width) self.line.set_xy((0, self.center_offset)) self.start_pos = np.array([0, self.center_offset]) self.end_pos = np.array([self.ax_width, self.center_offset + self.line_width]) self.ax.figure.canvas.draw() def on_key_press(self, event): if event.key=='n': self.roi = (self.start_pos.astype('int'), self.end_pos.astype('int')) #print "test" self.roi_finalized = True plt.close(self.fig) def wait_for_roi(self): """ Function that allows scripts that invoke roi classes to wait for user to set ROI """ while True: plt.pause(0.0001) if self.roi_finalized is True: print("ROI is finalized") break
class set_roi(object): """ Class to set an roi in an image. Saves start of ROI on mouse button press and saves end of ROI on mouse button release Need to specify an roi_color to use as well as a background_img to draw the roi on """ def __init__(self, roi_color, background_img, roi_selection_msg = "Press the 'n' key on your keyboard when you are happy with the ROI"): self.fig, self.ax = plt.subplots() self.fig.set_size_inches((11, 8.5), forward=True) self.ax.imshow(background_img) self.fig.suptitle(roi_selection_msg, size=16) self.type = 'roi' self.color = roi_color self.bg_img = background_img self.rect = Rectangle((0,0), 0, 0, color=self.color, alpha=0.4) self.start_pos = None self.end_pos = None self.current_pos = None self.released = True self.roi_finalized = False self.ax.add_patch(self.rect) self.ax.figure.canvas.mpl_connect('button_press_event', self.on_mouse_press) self.ax.figure.canvas.mpl_connect('button_release_event', self.on_mouse_release) self.ax.figure.canvas.mpl_connect('motion_notify_event', self.on_mouse_motion) self.ax.figure.canvas.mpl_connect('key_press_event', self.on_key_press) def on_mouse_press(self, event): self.released = False if self.roi_finalized is False: self.start_pos = np.array([event.xdata, event.ydata]) def on_mouse_release(self, event): self.released = True if self.roi_finalized is False: self.end_pos = np.array([event.xdata, event.ydata]) try: self.diff = (self.end_pos - self.start_pos) self.rect.set_width(self.diff[0]) self.rect.set_height(self.diff[1]) self.rect.set_xy(self.start_pos) self.ax.figure.canvas.draw() except: print("The mouse cursor went out of the canvas area! Please retry drawing the ROI!") def on_mouse_motion(self, event): if self.roi_finalized is False: if self.released is False: self.current_pos = np.array([event.xdata, event.ydata]) try: self.diff = (self.current_pos - self.start_pos) self.rect.set_width(self.diff[0]) self.rect.set_height(self.diff[1]) self.rect.set_xy(self.start_pos) self.ax.figure.canvas.draw() except: print("The mouse cursor went out of the canvas area! Please retry drawing the ROI!") def standardize_coords(self): """ This function take the start and end coordinates selected by the user and standardizes them so that the start is always the upper left corner and the end is always the lower right corner """ x_coords, y_coords = zip(*(self.start_pos, self.end_pos)) #0,0 is top left and max, max is bottom right standardized_start = np.array([min(x_coords), min(y_coords)]) standardized_end = np.array([max(x_coords), max(y_coords)]) return standardized_start.astype('int'), standardized_end.astype('int') def on_key_press(self, event): if event.key=='n': self.roi = self.standardize_coords() #print "test" self.roi_finalized = True plt.close(self.fig) def wait_for_roi(self): """ Function that allows scripts that invoke roi classes to wait for user to set ROI """ while True: plt.pause(0.0001) if self.roi_finalized is True: print("ROI is finalized") break
class Annotate(object): def __init__(self, image,name): self.img = image self.imgname = name self.i = 1 self.col = 'b' # deafult color for true positive label self.ax = plt.gca() # Initialize the Reactangle patch object with properties self.rect = Rectangle((0,0), 1, 1, alpha = 1,ls = 'solid',fill = False, clip_on = True,color = self.col) # Initialize two diagonally opposite co-ordinates of reactangle as None self.xc = None self.yc = None self.x0 = None self.y0 = None self.x1 = None self.y1 = None self.sizeModifier = 2 self.w = 30.0 self.h = 40.0 self.qkey = None self.objList = [] #self.centers # The list that will store value of those two co-ordinates of # all the patches for storing into the file later self.xy = [] self.ax.add_patch(self.rect) # Initialize mpl connect object connect = self.ax.figure.canvas.mpl_connect # Create objects that will handle user initiated events # We are using three events # First event is button press event (on left key click)- # on which on_click function is called self.ax.figure.canvas.mpl_connect('button_press_event', self.on_click) self.ax.figure.canvas.mpl_connect('close_event', self.handle_close) # Second event to draw, in case a mistake in labelling is made, # deleting the patch requires redrawing the original canvas self.draw_cid = connect('draw_event', self.grab_background) # Third event - key press event # To change color of the patches when you want to switch between # true postive and false postive labels self.ax.figure.canvas.mpl_connect('key_press_event',self.colorChange) def objCreation(self): # The new reactangle object to use after blit function (clearing # the canvas and removing rectangle objects) self.rect = Rectangle((0,0), 1, 1, alpha = 1,ls = 'solid',fill = False, clip_on = True) self.xc = None # x co-ordinate of patch center self.yc = None # y co-ordinate of patch center self.x0 = None # top left x co-ordinate of patch center self.y0 = None # top left y co-ordinate of patch center self.x1 = None # lower right y co-ordinate of patch center self.y1 = None # lower right y co-ordinate of patch center self.sizeModifier = 2 # The amount by which width/height will increase/decrease self.w = 30.0 # Initial width self.h = 40.0 # Initial height # Aspect Ratio of 3/4 # Add the patch on the axes object of figure self.ax.add_patch(self.rect) def deletePrevious(self): ''' Deletes the latest patch that was drawn ''' # Clear the screen by calling blit function self.blit() # Remove the last patch co-ordinates from the list self.xy = self.xy[:-1] # Redraw all the rects except the previous ones for coords in self.xy: self.rect.set_width(coords[2] - coords[0]) self.rect.set_height(coords[3] - coords[1]) self.rect.set_xy((coords[0], coords[1])) self.rect.set_color(coords[4]) self.ax.draw_artist(self.rect) self.ax.figure.canvas.blit(self.ax.bbox) def resize(self,det): ''' Resizing at the same center, maintaing the same aspect ratio and using key only (without dragging) ''' # Resizing without dragging requires deleting previous patch # Saving the center, width, height of the patch before deleting it # As it will be used for reconstructing with increased/decreased size last_obj = self.xy[-1] # print last_obj xc = last_obj[-2] yc = last_obj[-1] col = last_obj[-3] w = last_obj[2] - last_obj[0] h = last_obj[3] - last_obj[1] self.deletePrevious() self.xc = xc self.yc = yc self.col = col self.w = w*det print self.w self.h = h*det self.drawRect() def handle_close(self,event): ''' if you ended up closing the plot using the plot's X button instead of 'q' key ''' if self.qkey != 'q': self.close_plot() def close_plot(self): ''' saving numpy patches and co-ordinates of the patches ''' b = 0 r = 0 print os.getcwd() print 'close' header = open('header.txt','a') ##print self.xy #self.xy = filter(lambda x: 0 not in np.shape(x) , self.xy) blue_patches = filter(lambda x: x[4]=='b',self.xy) for blue_patch_list in blue_patches: xy = blue_patch_list name = str('NumpyPatches\\')+str(self.imgname)+'_blue'+str(b)+'.npy' patch_array = self.img[xy[1]:xy[3],xy[0]:xy[2]] if 0 not in np.shape(patch_array): header.write("%s" % self.imgname+',') print os.getcwd() np.save(name, patch_array) b = b+1 for item in xy[:5]: header.write("%s" % item+',') header.write('\n') red_patches = filter(lambda x: x[4]=='r',self.xy) for red_patch_list in red_patches: xy = red_patch_list name = self.imgname+'_red'+str(r)+'.npy' patch_array = self.img[xy[1]:xy[3],xy[0]:xy[2]] if 0 not in np.shape(patch_array): header.write("%s" % self.imgname+',') np.save(name, patch_array) r = r+1 for item in xy[:5]: header.write("%s" % item+',') header.write('\n') # xy = self.xy[0] # patch = img[xy[1]:xy[3],xy[0]:xy[2]] # imgplot = plt.imshow(patch) # plt.show() plt.close() def colorChange(self,event): ''' To change color to take false positves into consideration - the default is color blue for true postive ''' print('press', event.key) sys.stdout.flush() if event.key == 'r': # red color # When 'r' key is pressed, the color of the next patch will be red self.col = 'r' elif event.key == 'b': # blue color # When 'b' key is pressed, the color of the next patch will be blue self.col = 'b' # Optional setting for drawing patched using spacebar # elif event.key == ' ': # self.on_click(event) elif event.key == 'd': # delete # When 'd' key is pressed, the latest patch drawn is deleted #self.deletePrevious() nr = self.objList[-1] nr.set_visible(False) elif event.key == 'c': # clear # When 'c' key is pressed, all the patches are cleared, only orignal background is present self.blit() self.xy = [] # Flush out the list as we don't want to consider any patch co-ordinates elif event.key == 'tab': # use tab to increase the aspect ratio of the patch self.resize(1.2) elif event.key == 'control': # use control key to decrease the aspect ratio of the patch self.resize(0.95) elif event.key == '2': # use control key to decrease the aspect ratio of the patch self.resize(0.85) elif event.key == '3': # use control key to decrease the aspect ratio of the patch self.resize(0.50) elif event.key == 'q': # quit plot, show up the next # save necessary labels and close the plot self.qkey = 'q' self.close_plot() elif event.key == '0': sys.exit() def on_click(self, event): ''' Using one click on the center of the human, make a patch of fixed aspect ratio ''' # The first click to mark center point of the rectangle and save the coordinates print 'click1' self.xc = event.xdata self.yc = event.ydata # Chosing Aspect Ratio of 3/4 self.w = 30.0 self.h = 40.0 self.drawRect() def drawRect(self): # Set the two diagonally opposite co-ordinates of the patch by width and height self.x0 = self.xc-self.w/2 self.y0 = self.yc-self.h/2 self.x1 = self.xc+self.w/2 self.y1 = self.yc+self.h/2 # set the stated width self.rect.set_width(self.w) # set the stated height self.rect.set_height(self.h) # set the top left corner self.rect.set_xy((self.x0, self.y0 )) # append to the list of patch co-ordinates self.xy.append([self.x0,self.y0,self.x1,self.y1,self.col,self.xc,self.yc]) #print self.xy self.objList.append(self.rect) # Set the color of the reactangle - can be blue/red depending on postive/negative label respectively self.rect.set_color(self.col) self.ax.draw_artist(self.rect) self.ax.figure.canvas.update() # Blit is used to successively retain and display patches on the screen # Else Successively drawing one patch will remove the last drawn patch #self.ax.figure.canvas.blit(self.ax.bbox) # The following three functions taken from # http://stackoverflow.com/questions/29277080/efficient-matplotlib-redrawing def safe_draw(self): """Temporarily disconnect the draw_event callback to avoid recursion""" canvas = self.ax.figure.canvas canvas.mpl_disconnect(self.draw_cid) canvas.draw() self.draw_cid = canvas.mpl_connect('draw_event', self.grab_background) def grab_background(self, event=None): """ When the figure is resized, hide the rect, draw everything, and update the background. """ self.rect.set_visible(False) self.safe_draw() # With most backends (e.g. TkAgg), we could grab (and refresh, in # self.blit) self.ax.bbox instead of self.fig.bbox, but Qt4Agg, and # some others, requires us to update the _full_ canvas, instead. self.background = self.ax.figure.canvas.copy_from_bbox(self.ax.figure.bbox) self.rect.set_visible(True) self.blit() def blit(self): """ Efficiently update the figure, without needing to redraw the "background" artists. """ self.objCreation() self.ax.figure.canvas.restore_region(self.background) self.ax.draw_artist(self.rect) self.ax.figure.canvas.blit(self.ax.figure.bbox)
class RangeSelector: def __init__(self, axes, callbackPre, callbackPost): self.axes = axes self.callbackPre = callbackPre self.callbackPost = callbackPost self.eventPressed = None self.eventReleased = None props = dict(facecolor="red", edgecolor="white", alpha=0.25, fill=True, zorder=100, gid="range") self.rect = Rectangle((0, 0), 0, 0, **props) self.axes.add_patch(self.rect) figure = self.axes.get_figure() figure.canvas.mpl_connect("motion_notify_event", self.__on_move) figure.canvas.mpl_connect("button_press_event", self.__on_press) figure.canvas.mpl_connect("button_release_event", self.__on_release) def __on_press(self, event): if self.__skip_event(event): return self.eventPressed = event self.callbackPre() self.rect.set_visible(True) return def __on_move(self, event): if self.eventPressed is None or self.__skip_event(event): return xMin = self.eventPressed.xdata xMax = event.xdata if xMin > xMax: xMin, xMax = xMax, xMin self.callbackPost(xMin, xMax) return def __on_release(self, event): if self.eventPressed is None or self.__skip_event(event): return self.eventReleased = event xMin, xMax = self.eventPressed.xdata, self.eventReleased.xdata if xMin > xMax: xMin, xMax = xMax, xMin self.callbackPost(xMin, xMax) self.eventPressed = None self.eventReleased = None return def __skip_event(self, event): if event.button != 2: return True if self.eventPressed is None: return event.inaxes != self.axes if event.button == self.eventPressed.button and event.inaxes != self.axes: transform = self.axes.transData.inverted() (x, _y) = transform.transform_point((event.x, event.y)) x0, x1 = self.axes.get_xbound() x = max(x0, x) x = min(x1, x) event.xdata = x return False return event.inaxes != self.axes or event.button != self.eventPressed.button def draw(self, xMin, xMax): self.rect.set_visible(True) yMin, yMax = self.axes.get_ylim() height = yMax - yMin yMin -= height * 100.0 yMax += height * 100.0 self.rect.set_x(xMin) self.rect.set_y(yMin) self.rect.set_width(xMax - xMin) self.rect.set_height(yMax - yMin) if self.axes._cachedRenderer is not None: self.axes.draw_artist(self.rect) def hide(self): self.rect.set_visible(False) def clear(self): self.rect.set_visible(False) canvas = self.axes.get_figure().canvas canvas.draw()
class CustomToolbar(NavToolbar): toolitems = NavToolbar.toolitems + ( (None, None, None, None), ("ROI", "Select ROI", "selection", "_on_custom_select"), ) def __init__(self, plotCanvas): # create the default toolbar NavToolbar.__init__(self, plotCanvas) self.selector = RectSelector( self.canvas.figure.axes[0], self.onSelect, button=[1, 3], minspanx=5, minspany=5 # don't use middle button ) self.selector.set_active(True) self.ax = self.canvas.figure.axes[0] self.roi = None self.fixedSize = False if wx.Platform == "__WXMAC__": self.to_draw = Rectangle( (0, 0), 0, 1, visible=False, facecolor="yellow", edgecolor="black", alpha=0.5, fill=True ) self.ax.add_patch(self.to_draw) self.background = None def _init_toolbar(self): self._parent = self.canvas.GetParent() self.wx_ids = {} for text, tooltip_text, image_file, callback in self.toolitems: if text is None: self.AddSeparator() continue self.wx_ids[text] = wx.NewId() try: bitmap = _load_bitmap(image_file + ".png") except IOError: bitmap = wx.Bitmap(image_file + ".png") if text in ["Pan", "Zoom", "ROI"]: self.AddCheckTool(self.wx_ids[text], bitmap, shortHelp=text, longHelp=tooltip_text) else: self.AddSimpleTool(self.wx_ids[text], bitmap, text, tooltip_text) bind(self, wx.EVT_TOOL, getattr(self, callback), id=self.wx_ids[text]) self.ToggleTool(self.wx_ids["ROI"], True) self.Realize() def _set_markers(self): self.canvas.parentFrame.set_markers() def _update_view(self): NavToolbar._update_view(self) self._set_markers() # MacOS needs a forced draw to update plot if wx.Platform == "__WXMAC__": self.canvas.draw() def draw(self): self._set_markers() NavToolbar.draw(self) # MacOS needs a forced draw to update plot if wx.Platform == "__WXMAC__": self.canvas.draw() def zoom(self, ev): if wx.Platform == "__WXMAC__": self.ToggleTool(self.wx_ids["Zoom"], self.GetToolState(self.wx_ids["Zoom"])) NavToolbar.zoom(self, ev) def pan(self, ev): if wx.Platform == "__WXMAC__": self.ToggleTool(self.wx_ids["Pan"], self.GetToolState(self.wx_ids["Pan"])) NavToolbar.pan(self, ev) def press_zoom(self, ev): if wx.Platform == "__WXMAC__": self.update_background() self.to_draw.set_visible(True) NavToolbar.press_zoom(self, ev) def release_zoom(self, ev): if wx.Platform == "__WXMAC__": self.to_draw.set_visible(False) NavToolbar.release_zoom(self, ev) def draw_rubberband(self, event, x0, y0, x1, y1): # XOR does not work on MacOS ... if wx.Platform != "__WXMAC__": NavToolbar.draw_rubberband(self, event, x0, y0, x1, y1) else: if self.background is not None: self.canvas.restore_region(self.background) c0, c1 = self.ax.transData.inverted().transform([[x0, y0], [x1, y1]]) l, b = c0 r, t = c1 self.to_draw.set_bounds(l, b, r - l, t - b) self.ax.draw_artist(self.to_draw) self.canvas.blit(self.ax.bbox) def update_background(self): """force an update of the background""" self.background = self.canvas.copy_from_bbox(self.ax.bbox) # Turn on selection # TODO: Proper handling of states, actual functionality. def _on_custom_select(self, evt): # for id in ['Zoom','Pan']: # self.ToggleTool(self.wx_ids[id], False) # print('Select ROI: %s' % (self.GetToolState(self.wx_ids['ROI']))) # self.ToggleTool(self.wx_ids['ROI'], # self.GetToolState(self.wx_ids['ROI']) ) self.toggle_selector() # print('Select ROI: %s' % (self.GetToolState(self.wx_ids['ROI']))) def onSelect(self, eclick, erelease): "eclick and erelease are matplotlib events at press and release" # print(' startposition : (%f, %f)' % (eclick.xdata, eclick.ydata)) # print(' endposition : (%f, %f)' % (erelease.xdata, erelease.ydata)) # print(' used button : ', eclick.button) self.updateROI( min(eclick.xdata, erelease.xdata), min(eclick.ydata, erelease.ydata), abs(eclick.xdata - erelease.xdata), abs(eclick.ydata - erelease.ydata), ) if self.canvas.parentFrame.fixedNumberCB.IsChecked(): # We are working in the fixed-number mode # We need to find new roi for this center point # The handler will call the update ROI function for us. self.canvas.parentFrame.handleROIforN() def updateROI(self, x, y, w, h): if self.roi is None: # print('upd ROI:', x, y, w, h) self.roi = Rectangle((x, y), w, h, ls="solid", lw=2, color="r", fill=False, zorder=5) self.canvas.figure.axes[0].add_patch(self.roi) else: self.roi.set_bounds(x, y, w, h) self.updateCanvas() def toggle_selector(self): self.selector.set_active(not self.selector.active) def onFixedSize(self, ev): self.fixedSize = ev.IsChecked() self.updateCanvas() def onWidthChange(self, ev): if self.roi: x = self.roi.get_x() w = self.roi.get_width() nw = ev.GetValue() dw = {"C": (w - nw) / 2, "L": 0, "R": w - nw}[self.canvas.parentFrame.anchorRB.GetStringSelection()[0]] self.roi.set_x(x + dw) self.roi.set_width(nw) self.updateCanvas() def onHeightChange(self, ev): if self.roi: y = self.roi.get_y() h = self.roi.get_height() nh = ev.GetValue() dh = {"C": (h - nh) / 2, "B": 0, "T": h - nh}[self.canvas.parentFrame.anchorRB.GetStringSelection()[-1]] self.roi.set_y(y + dh) self.roi.set_height(nh) self.updateCanvas() def updateCanvas(self, redraw=True): if self.roi: self.canvas.parentFrame.showROI( self.roi.get_x(), self.roi.get_y(), self.roi.get_width(), self.roi.get_height() ) self.canvas.parentFrame.setWH(self.roi.get_width(), self.roi.get_height()) if self.fixedSize: self.selector.setSize(self.roi.get_width(), self.roi.get_height()) else: self.selector.setSize() if redraw: self.draw()
class MplRectangularROI(AbstractMplRoi): """ Matplotlib ROI for rectangular selections Parameters ---------- axes : `~matplotlib.axes.Axes` The Matplotlib axes to draw to. """ _roi_cls = RectangularROI def __init__(self, axes): super(MplRectangularROI, self).__init__(axes) self._xi = None self._yi = None self.plot_opts = {'edgecolor': PATCH_COLOR, 'facecolor': PATCH_COLOR, 'alpha': 0.3} self._patch = Rectangle((0., 0.), 1., 1., zorder=100) self._patch.set_visible(False) self._axes.add_patch(self._patch) def start_selection(self, event): if event.inaxes != self._axes: return False if event.key == SCRUBBING_KEY: if not self._roi.defined(): return False elif not self._roi.contains(event.xdata, event.ydata): return False self._store_previous_roi() self._store_background() self._xi = event.xdata self._yi = event.ydata if event.key == SCRUBBING_KEY: self._scrubbing = True self._cx, self._cy = self._roi.center() else: self.reset() self._roi.update_limits(event.xdata, event.ydata, event.xdata, event.ydata) self._mid_selection = True self._sync_patch() self._draw() def update_selection(self, event): if not self._mid_selection or event.inaxes != self._axes: return False if event.key == SCRUBBING_KEY: if not self._roi.defined(): return False if self._scrubbing: self._roi.move_to(self._cx + event.xdata - self._xi, self._cy + event.ydata - self._yi) else: self._roi.update_limits(min(event.xdata, self._xi), min(event.ydata, self._yi), max(event.xdata, self._xi), max(event.ydata, self._yi)) self._sync_patch() self._draw() def finalize_selection(self, event): self._scrubbing = False self._mid_selection = False self._patch.set_visible(False) self._draw() def _sync_patch(self): if self._roi.defined(): corner = self._roi.corner() width = self._roi.width() height = self._roi.height() self._patch.set_xy(corner) self._patch.set_width(width) self._patch.set_height(height) self._patch.set(**self.plot_opts) self._patch.set_visible(True) else: self._patch.set_visible(False) def __str__(self): return "MPL Rectangle: %s" % self._patch