def create_ellipse_ax(self, ax): elliprops = dict(edgecolor = 'black', fill = False, linewidth = 5, linestyle= '-') self._ellipse_selector = EllipseSelector(ax, self._callback_ellipse, drawtype= 'box', useblit= True, rectprops= elliprops, button= [1,3], minspanx = 5, minspany=5, spancoords='pixels', interactive=True) self._disable_ellipse()
def drawCircle(self, click): print("Click, hold, and drag to draw circle.\n\n") self.rs = EllipseSelector(self.ax, self._drawCircleEvent, lineprops=dict(linewidth=1, alpha=0.6, color='k'), drawtype='box', useblit=False, button=[1])
def configure_selector(self, frange=False, peaks=False): self.range_selector = RectangleSelector(self.axs[0], self.rect_onselect, drawtype='box', useblit=True, button=[1, 3], # don't use middle button minspanx=15, minspany=15, spancoords='pixels', #interactive=True, rectprops=dict(alpha=0.5, facecolor='g')) self.peaks_selector = EllipseSelector(self.axs[0], self.ellipse_onselect, drawtype='line', button=[1, 3], # don't use middle button spancoords='pixels', useblit=True, minspanx=10, minspany=10, rectprops=dict(alpha=0.5, facecolor='red')) self.peaks_selector.set_active(peaks) self.range_selector.set_active(frange)
def __init__(self, axes, roi_type): self.axes = axes self.roi_type = roi_type self.patch = None self.lasso_switch = False self.verts = None self.title = 'N/A' self.annotate = None self.intensity = 0 self.global_switch = False if self.roi_type == 'rectangle': self.roi = RectangleSelector(self.axes, self.onselect, drawtype='box', interactive=True) elif self.roi_type == 'ellipse': self.roi = EllipseSelector(self.axes, self.onselect, drawtype='box', interactive=True) else: self.roi = LassoSelector(self.axes, onselect=self.lasso_select)
def __init__(self, RA, DEC, canvas, figure): self.canvas = canvas self.ax = figure self.ax.scatter(RA, DEC) ## Picker = 5 for close radius self.RA = RA self.DEC = DEC self.RA_subset = [] self.DEC_subset = [] self.cache = [] self.ind = [] self.ellipse = EllipseSelector( self.ax, self.line_select_callback, drawtype='box', useblit=False, button=[1, 3], ## No mousewheel minspanx=5, minspany=5, spancoords='pixels', interactive=True)
def refreshLassoWidget(self, keep_paths=False): self.roi_ax.clear() init_lasso = False if self.roi_image is not None: if len(self.roi_mask) > 0: newImage = plot_tools.overlayImage( self.roi_image[:, :, self.current_z_slice], self.roi_mask, 0.5, self.colors, z=self.current_z_slice) else: newImage = self.roi_image[:, :, self.current_z_slice] self.roi_ax.imshow(newImage, cmap=cm.gray) init_lasso = True else: self.roi_ax.imshow(self.blank_image) self.roi_ax.set_axis_off() self.roi_canvas.draw() if not keep_paths: self.roi_path_list = [] if init_lasso: if self.roi_type == 'circle': self.lasso_1 = EllipseSelector(self.roi_ax, onselect=self.newEllipse, button=1) elif self.roi_type == 'freehand': self.lasso_1 = LassoSelector(self.roi_ax, onselect=self.newFreehand, button=1) self.lasso_2 = LassoSelector(self.roi_ax, onselect=self.appendFreehand, button=3) else: print( 'Warning ROI type not recognized. Choose circle or freehand' )
def define_roi(self, frame_number=0): if type(frame_number) != int: raise TypeError('frame number is required to be an int') image = self.read_frames(frame_number)[0, :, :] def line_select_callback(eclick, erelease): 'eclick and erelease are the press and release events' x1, y1 = eclick.xdata, eclick.ydata x2, y2 = erelease.xdata, erelease.ydata def toggle_selector(event): if event.key in ['Q', 'q'] and toggle_selector.ES.active: toggle_selector.ES.set_active(False) plt.close() fig, ax = plt.subplots() ax.imshow(image) fig.tight_layout() toggle_selector.ES = EllipseSelector(ax, line_select_callback, drawtype='box', useblit=True, button=[1, 3], # don't use middle button minspanx=5, minspany=5, spancoords='pixels', interactive=True, lineprops=dict(color='black', linestyle='-', linewidth=2, alpha=0.5)) plt.connect('key_press_event', toggle_selector) plt.show() def ellipse_dimensions(extents): center = (abs(extents[0] - extents[1]) / 2 + min(extents[0:2]), abs(extents[2] - extents[3]) / 2 + min(extents[2:])) radius = (abs(extents[0] - extents[1]), abs(extents[2] - extents[3])) return center, radius[0], radius[1] self.roi_center, self.roi_width, self.roi_height= ellipse_dimensions(toggle_selector.ES.extents) roi_patch = mp.Ellipse(self.roi_center, self.roi_width, self.roi_height, fill=False, hatch='\\') return roi_patch
def selectROI_ellipse(matrice_immagine, titolo='Immagine'): ''' input: ax --> axis su cui fare la selezione della roi output: (x1,y1,x2,y2) ''' (t_lim_inf, t_lim_sup) = set_cmap(matrice_immagine) _, ax = plt.subplots() ax.imshow(matrice_immagine, clim=[t_lim_inf, t_lim_sup]) ax.set(title=titolo) __toggle_selector.ES = EllipseSelector( ax, __onselect, drawtype='box', useblit=True, button=[1, 3], # don't use middle button minspanx=5, minspany=5, spancoords='pixels', interactive=True) plt.connect('key_press_event', __toggle_selector) plt.show() return cordinate
def drawAOI(self): """Function that allows speicification of area of interest (AOI) for analysis. """ with open(self.json_file, "r") as f: json_data = json.load(f) aoi_left_x = 0 aoi_left_y = 0 aoi_right_x = 0 aoi_right_y = 0 display_width = json_data["Analysis_Params"]["EyeTracker"]["Display_width"] display_height = json_data["Analysis_Params"]["EyeTracker"]["Display_height"] cnt = 0 img = None if os.path.isdir(self.path + "/Stimuli/"): for f in os.listdir(self.path + "/Stimuli/"): if f.split(".")[-1] in ['jpg', 'jpeg', 'png']: img = plt.imread(self.path + "/Stimuli/" + f) cnt += 1 break if cnt == 0: img = np.zeros((display_height, display_width, 3)) fig, ax = plt.subplots() fig.canvas.set_window_title("Draw AOI") ax.imshow(img) if self.aoi == "p": def onselect(verts): nonlocal vertices, canvas print('\nSelected points:') x = [] y = [] for i, j in vertices: print(round(i, 3), ",", round(j, 3)) x.append(i) y.append(j) vertices = verts canvas.draw_idle() canvas = ax.figure.canvas _ = PolygonSelector(ax, onselect, lineprops=dict(color='r', linestyle='-', linewidth=2, alpha=0.5), markerprops=dict(marker='o', markersize=7, mec='r', mfc='k', alpha=0.5)) vertices = [] print("1) 'esc' KEY: START A NEW POLYGON") print("2) 'shift' KEY: MOVE ALL VERTICES BY DRAGGING ANY EDGE") print("3) 'ctrl' KEY: MOVE A SINGLE VERTEX") plt.show() return vertices elif self.aoi == "r": def line_select_callback(eclick, erelease): nonlocal aoi_left_x, aoi_left_y, aoi_right_x, aoi_right_y aoi_left_x, aoi_left_y = round(eclick.xdata, 3), round(eclick.ydata, 3) aoi_right_x, aoi_right_y = round(erelease.xdata, 3), round(erelease.ydata, 3) print("Coordinates [(start_x, start_y), (end_x, end_y)]: ", "[(%6.2f, %6.2f), (%6.2f, %6.2f)]" % (aoi_left_x, aoi_left_y, aoi_right_x, aoi_right_y)) RS = RectangleSelector(ax, line_select_callback, drawtype='box', useblit=False, interactive=True) RS.to_draw.set_visible(True) plt.show() return [aoi_left_x, aoi_left_y, aoi_right_x, aoi_right_y] elif self.aoi == "e": x_dia = 0 y_dia = 0 centre = (0,0) def onselect(eclick, erelease): nonlocal x_dia, y_dia, centre x_dia = (erelease.xdata - eclick.xdata) y_dia = (erelease.ydata - eclick.ydata) centre = [round(eclick.xdata + x_dia/2., 3), round(eclick.ydata + y_dia/2., 3)] print("Centre: ", centre) print("X Diameter: ", x_dia) print("Y Diameter: ", y_dia) print() ES = EllipseSelector(ax, onselect, drawtype='box', interactive=True, lineprops=dict(color='g', linestyle='-', linewidth=2, alpha=0.5), marker_props=dict(marker='o', markersize=7, mec='g', mfc='k', alpha=0.5)) plt.show() return [centre, x_dia, y_dia]
def _set_interactive_tool(self, ax_area, ax_button, ax_slider): self.drag_id = None self.area_bbox = ax_area.get_window_extent() self.selector_pen = patches.Circle( xy=(0, 0), edgecolor='black', radius=0.0, fc='gray', alpha=0.5, zorder=5) ax_area.add_patch(self.selector_pen) self.selector_pen.set_visible(True) self.fig._fig.canvas.mpl_connect( 'button_press_event', self._on_click_pen) self.fig._fig.canvas.mpl_connect( 'motion_notify_event', self._on_click_pen) self.selector_rect = RectangleSelector( ax_area, self._on_select_rect, drawtype='box', button=1, rectprops=dict( facecolor='gray', edgecolor='black', alpha=0.5, fill=True, zorder=5), state_modifier_keys=dict( move=' ', clear='escape', square='control', center='space')) self.selector_rect.visible = False self.selector_ellipse = EllipseSelector( ax_area, self._on_select_ellipse, drawtype='box', button=1, rectprops=dict( facecolor='gray', edgecolor='black', alpha=0.5, fill=True, zorder=5), state_modifier_keys=dict( move=' ', clear='escape', square='control', center='space')) self.selector_ellipse.visible = False def _press(ls, event): ls.verts = [ls._get_data(event)] ls.line.set_visible(ls.visible) def _release(ls, event): if ls.verts is not None: ls.verts.append(ls._get_data(event)) ls.onselect(ls.verts, event) ls.line.set_data([[], []]) ls.line.set_visible(False) ls.verts = None LassoSelector._press = _press LassoSelector._release = _release self.selector_lasso = LassoSelector( ax_area, onselect=self._on_select_lasso, button=1, useblit=False, lineprops=dict(linewidth=2.0, color="gray", zorder=1)) self.selector_lasso.visible = False self.button_radio = RadioButtons( ax_button, ["pen", "rectangle", "ellipse", "lasso"]) for _label in self.button_radio.labels: _label.set_fontsize(12) self.button_radio.on_clicked(self._on_change_radio) self.slider_radius = Slider( ax_slider, 'pen\nsize', 0.0, 50.0, valinit=BaseEditor.pen_size, valfmt='%.1f') self.slider_radius.on_changed(self._on_change_radius)
def select_pts(nodepts, elements, values=None, selection=None, shape='ellipse', add=True): ''' This function allows you to interactively select a point, rectangle or ellipse. This info can then be fed to functions to remove nodes/elements or query their properties ''' if selection is None: selection = np.zeros(np.shape(nodepts)[0], dtype=bool) def line_select_callback(eclick, erelease): 'eclick and erelease are the press and release events' x1, y1 = eclick.xdata, eclick.ydata x2, y2 = erelease.xdata, erelease.ydata print("(%3.2f, %3.2f) --> (%3.2f, %3.2f)" % (x1, y1, x2, y2)) print(" The button you used were: %s %s" % (eclick.button, erelease.button)) def toggle_selector(event): print(' Key pressed.') if event.key in ['Q', 'q'] and RS.active: print(' RectangleSelector deactivated.') RS.set_active(False) if event.key in ['A', 'a'] and not RS.active: print(' RectangleSelector activated.') RS.set_active(True) def rect_select_node(rect, selected): for index, node in enumerate(nodepts): if (node[0] > rect[0]) & (node[0] < (rect[0] + rect[2])): if (node[1] > rect[1]) & (node[1] < (rect[1] + rect[3])): selected[index] = add return selected def ellipse_select_node(rect, selected): el = patches.Ellipse((rect[0], rect[1]), rect[2], rect[3]) for index, node in enumerate(nodepts): if el.contains_point(node): selected[index] = add return selected if values is None: values = mesh.default_values(elements) fig, ax = tri_mesh_select_plot(nodepts, elements, selection, show=False) if shape == 'rectangle': RS = RectangleSelector( ax, line_select_callback, drawtype='box', useblit=True, button=[1, 3], # don't use middle button minspanx=5, minspany=5, spancoords='pixels', interactive=True) elif shape == 'ellipse': RS = EllipseSelector( ax, line_select_callback, drawtype='box', useblit=True, button=[1, 3], # don't use middle button minspanx=5, minspany=5, spancoords='pixels', interactive=True) plt.connect('key_press_event', toggle_selector) plt.show() if shape == 'rectangle': edge_centers = RS.edge_centers #[(x,y),width,height] rect = [ edge_centers[0][0], edge_centers[1][1], edge_centers[0][2] - edge_centers[0][0], edge_centers[1][3] - edge_centers[1][1] ] elif shape == 'ellipse': edge_centers = RS.edge_centers rect = [ edge_centers[0][1], edge_centers[1][0], edge_centers[0][2] - edge_centers[0][0], edge_centers[1][3] - edge_centers[1][1] ] if shape == 'rectangle': selection = rect_select_node(rect, selection) elif shape == 'ellipse': selection = ellipse_select_node(rect, selection) tri_mesh_select_plot(nodepts, elements, selection, show=True) return selection
def init_plot(self, embedding, weights, on_selection, on_close, disable_select, top_level=False, labels=None, color_norm=None): """ Set the initial embedding and point weights to create and display the plot at iteration step=0""" # pylint: disable=attribute-defined-outside-init self.top_level = top_level self.labels = labels self.color_norm = color_norm self.disable_select = disable_select self.selection_mask = np.full(weights.shape, False) # Plot and image definition # self.rect = None self.extent = 2.8 self.cleanup = True self.rectangle_selector = None self.lasso_selector = None # Callbacks self.fig.canvas.mpl_connect('motion_notify_event', self.on_over) self.fig.canvas.mpl_connect('key_press_event', self.on_keypress) self.fig.canvas.mpl_connect('button_press_event', self.on_start_select) self.fig.canvas.mpl_connect('close_event', self.handle_close) # Brush support values self.in_selection = False self.in_paint = False self.dim_xy = (None, None) # displacement self.rorg_xy = (None, None) # The bottom left corner print("Show plot") plt.show(block=False) # Need no block for cooperation with tkinter self.embedding = embedding self.on_selection = on_selection self.on_close = on_close # pylint: enable=attribute-defined-outside-init x = embedding[:, 0] y = embedding[:, 1] if self.labels is None: self.scatter = self.ax.scatter(x, y, s=weights * 8, c='b', alpha=0.4, picker=10) else: self.scatter = self.ax.scatter( x, y, s=weights * 8, c=self.labels, # TODO make color map user selectable pylint: disable=fixme cmap=plt.cm.rainbow_r, # # pylint: disable=no-member norm=self.color_norm, alpha=0.4, picker=10) self.update_scatter_plot_limits(embedding) # Drawing selectors rectangle_selector = RectangleSelector(self.ax, self.on_end_rectangle_select, drawtype='box', useblit=True, button=[1, 3], rectprops=dict( facecolor=(1, 0, 0, 0.1), edgecolor=(1, 0, 0, 0.5), fill=False), minspanx=5, minspany=5, spancoords='pixels') lasso_selector = LassoSelector(self.ax, onselect=self.on_end_lasso_select, lineprops=dict(color=(1, 0, 0, 0.5))) ellipse_selector = EllipseSelector(self.ax, onselect=self.on_end_ellipse_select, drawtype='line', lineprops=dict(color=(1, 0, 0, 0.5))) polygon_selector = PolygonSelector(self.ax, onselect=self.on_end_lasso_select, lineprops=dict(color=(1, 0, 0, 0.5))) self.selectors = { DrawingShape.Lasso: lasso_selector, DrawingShape.Ellipse: ellipse_selector, DrawingShape.Rectangle: rectangle_selector, DrawingShape.Polygon: polygon_selector } # pylint: disable=attribute-defined-outside-init self.set_selector() # force rendering of facecolors self.fig.canvas.draw() self.facecolors = self.scatter.get_facecolors()
def process(self, image, **kwargs): if "DISPLAY" not in os.environ: raise Exception("Can't run selectors without a display!") if kwargs["method"] == "mask": mask = np.zeros(image.shape, np.uint8) global drawing drawing = False def paint_draw(event, x, y, flags, param): global ix, iy, drawing if event == cv2.EVENT_LBUTTONDOWN: drawing = True elif event == cv2.EVENT_LBUTTONUP: drawing = False elif event == cv2.EVENT_MOUSEMOVE and drawing: cv2.line(mask, (ix, iy), (x, y), kwargs["color"], kwargs["brush"]) ix, iy = x, y return x, y cv2.namedWindow("Select Mask", cv2.WINDOW_KEEPRATIO) cv2.resizeWindow("Select Mask", image.shape[0], image.shape[1]) cv2.setMouseCallback("Select Mask", paint_draw) while cv2.getWindowProperty("Select Mask", cv2.WND_PROP_VISIBLE) >= 1: cv2.imshow("Select Mask", cv2.addWeighted(image, 0.8, mask, 0.2, 0)) key_code = cv2.waitKey(1) if (key_code & 0xFF) == ord("q"): cv2.destroyAllWindows() break elif (key_code & 0xFF) == ord("+"): kwargs["brush"] += 1 elif (key_code & 0xFF) == ord("-") and kwargs["brush"] > 1: kwargs["brush"] -= 1 mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY) mask[mask != 0] = 255 return {"mask": easycv.image.Image(mask)} mpl.use("Qt5Agg") fig, current_ax = plt.subplots() plt.tick_params( axis="both", which="both", bottom=False, top=False, left=False, right=False, labelbottom=False, labelleft=False, ) def empty_callback(e1, e2): pass def selector(event): if event.key in ["Q", "q"]: plt.close(fig) res = [] current_ax.imshow(prepare_image_to_output(image)) plt.gcf().canvas.set_window_title("Selector") if kwargs["method"] == "rectangle": selector.S = RectangleSelector( current_ax, empty_callback, useblit=True, button=[1, 3], minspanx=5, minspany=5, spancoords="pixels", interactive=True, ) elif kwargs["method"] == "ellipse": selector.S = EllipseSelector( current_ax, empty_callback, drawtype="box", interactive=True, useblit=True, ) else: def onclick(event): if event.xdata is not None and event.ydata is not None: res.append((int(event.xdata), int(event.ydata))) plt.plot( event.xdata, event.ydata, marker="o", color="cyan", markersize=4 ) fig.canvas.draw() if len(res) == kwargs["n"]: plt.close(fig) plt.connect("button_press_event", onclick) plt.connect("key_press_event", selector) plt.show(block=True) if kwargs["method"] == "rectangle": x, y = selector.S.to_draw.get_xy() x = int(round(x)) y = int(round(y)) width = int(round(selector.S.to_draw.get_width())) height = int(round(selector.S.to_draw.get_height())) if width == 0 or height == 0: raise InvalidSelectionError("Must select a rectangle.") return {"rectangle": [(x, y), (x + width, y + height)]} elif kwargs["method"] == "ellipse": width = int(round(selector.S.to_draw.width)) height = int(round(selector.S.to_draw.height)) center = [int(round(x)) for x in selector.S.to_draw.get_center()] if width == 0 or height == 0: raise InvalidSelectionError("Must select an ellipse.") return {"ellipse": [tuple(center), int(width / 2), int(height / 2)]} else: if len(res) != kwargs["n"]: raise InvalidSelectionError( "Must select {} points.".format(kwargs["n"]) ) return {"points": res}
def imshow(self, image, slider=False, normalize=True, roi_callback=None, roi_drawtype='box', **kwargs): ''' Showing an image on the canvas, and optional sliders for colour adjustments. Redrawing image afterwards is quite fast because set_data is used instead imshow (matplotlib). INPUT ARGUMENTS slider Whether to draw the sliders for setting image cap values roi_callback A callable taking in x1,y1,x2,y2 roi_drawtype "box", "ellipse" "line" or "polygon" *kwargs go to imshow Returns the object returned by matplotlib's axes.imshow. ''' if image is None: image = self.imshow_image self.imshow_image = image # Slider if slider: # Check if the sliders exist. If not, create try: self.imshow_sliders except AttributeError: self.slider_axes = [ self.figure.add_axes(rect) for rect in ([0.2, 0.05, 0.6, 0.05], [0.2, 0, 0.6, 0.05]) ] self.imshow_sliders = [] self.imshow_sliders.append( matplotlib.widgets.Slider(self.slider_axes[0], 'Upper %', 0, 100, valinit=90, valstep=1)) self.imshow_sliders.append( matplotlib.widgets.Slider(self.slider_axes[1], 'Lower %', 0, 100, valinit=5, valstep=1)) for slider in self.imshow_sliders: slider.on_changed(lambda slider_val: self.imshow( None, slider=slider, **kwargs)) for ax in self.slider_axes: if ax.get_visible() == False: ax.set_visible(True) # Normalize using the known clipping values #image = image - lower_clip #image = image / upper_clip else: # Hide the sliders if they exist if getattr(self, 'imshow_sliders', None): for ax in self.slider_axes: if ax.get_visible() == True: ax.set_visible(False) print('axes not visible not') if getattr(self, 'imshow_sliders', None): # Check that the lower slider cannot go above the upper. if self.imshow_sliders[0].val < self.imshow_sliders[1].val: self.imshow_sliders[0].val = self.imshow_sliders[1].val upper_clip = np.percentile(image, self.imshow_sliders[0].val) lower_clip = np.percentile(image, self.imshow_sliders[1].val) image = np.clip(image, lower_clip, upper_clip) if normalize: image = image - np.min(image) image = image / np.max(image) # Just set the data or make an imshow plot if self._previous_shape == image.shape and ( roi_callback is None or roi_drawtype == self._previous_roi_drawtype): self.imshow_obj.set_data(image) else: if hasattr(self, 'imshow_obj'): # Fixed here. Without removing the AxesImages object plotting # goes increacingly slow every time when visiting this else block # Not sure if this is the best fix (does it free all memory) but # it seems to work well self.imshow_obj.remove() self.imshow_obj = self.ax.imshow(image, **kwargs) self.figure.subplots_adjust(left=0, bottom=0, right=1, top=1, wspace=None, hspace=None) self.ax.xaxis.set_major_locator(matplotlib.ticker.NullLocator()) self.ax.yaxis.set_major_locator(matplotlib.ticker.NullLocator()) if callable(roi_callback): if getattr(self, "roi_rectangle", None): if self._previous_roi_drawtype == 'line': self.roi_rectangle.disconnect() else: self.roi_rectangle.disconnect_events() if roi_drawtype == 'box': self.roi_rectangle = RectangleSelector( self.ax, self.__onSelectRectangle, useblit=True) elif roi_drawtype == 'ellipse': self.roi_rectangle = EllipseSelector( self.ax, self.__onSelectRectangle, useblit=True) elif roi_drawtype == 'line': self.roi_rectangle = ArrowSelector( self.ax, self.__onSelectRectangle) elif roi_drawtype == 'polygon': self.roi_rectangle = PolygonSelector( self.ax, self.__onSelectPolygon, useblit=True) else: raise ValueError( 'roi_drawtype either "box", "ellipse", "line", or "polygon", got {}' .format(roi_drawtype)) self.roi_callback = roi_callback self._previous_roi_drawtype = roi_drawtype self._previous_shape = image.shape self.canvas.draw() return self.imshow_obj
class EllipsePixelRegion(PixelRegion): """ An ellipse in pixel coordinates. Parameters ---------- center : `~regions.PixCoord` The position of the center of the ellipse. width : `float` The width of the ellipse (before rotation) in pixels height : `float` The height of the ellipse (before rotation) in pixels angle : `~astropy.units.Quantity`, optional The rotation angle of the ellipse, measured anti-clockwise. If set to zero (the default), the width axis is lined up with the x axis. meta : `~regions.RegionMeta` object, optional A dictionary which stores the meta attributes of this region. visual : `~regions.RegionVisual` object, optional A dictionary which stores the visual meta attributes of this region. Examples -------- .. plot:: :include-source: import numpy as np from astropy.modeling.models import Ellipse2D from astropy.coordinates import Angle from regions import PixCoord, EllipsePixelRegion import matplotlib.pyplot as plt x0, y0 = 15, 10 a, b = 8, 5 theta = Angle(30, 'deg') e = Ellipse2D(amplitude=100., x_0=x0, y_0=y0, a=a, b=b, theta=theta.radian) y, x = np.mgrid[0:20, 0:30] fig, ax = plt.subplots(1, 1) ax.imshow(e(x, y), origin='lower', interpolation='none', cmap='Greys_r') center = PixCoord(x=x0, y=y0) reg = EllipsePixelRegion(center=center, width=2*a, height=2*b, angle=theta) patch = reg.as_artist(facecolor='none', edgecolor='red', lw=2) ax.add_patch(patch) """ _params = ('center', 'width', 'height', 'angle') center = ScalarPix('center') width = ScalarLength('width') height = ScalarLength('height') angle = QuantityLength('angle') def __init__(self, center, width, height, angle=0. * u.deg, meta=None, visual=None): self.center = center self.width = width self.height = height self.angle = angle self.meta = meta or RegionMeta() self.visual = visual or RegionVisual() @property def area(self): """Region area (float)""" return math.pi / 4 * self.width * self.height def contains(self, pixcoord): pixcoord = PixCoord._validate(pixcoord, name='pixcoord') cos_angle = np.cos(self.angle) sin_angle = np.sin(self.angle) dx = pixcoord.x - self.center.x dy = pixcoord.y - self.center.y in_ell = ((2 * (cos_angle * dx + sin_angle * dy) / self.width) ** 2 + (2 * (sin_angle * dx - cos_angle * dy) / self.height) ** 2 <= 1.) if self.meta.get('include', True): return in_ell else: return np.logical_not(in_ell) def to_sky(self, wcs): # TODO: write a pixel_to_skycoord_scale_angle center = pixel_to_skycoord(self.center.x, self.center.y, wcs) _, scale, north_angle = skycoord_to_pixel_scale_angle(center, wcs) height = Angle(self.height / scale, 'deg') width = Angle(self.width / scale, 'deg') return EllipseSkyRegion(center, width, height, angle=self.angle - (north_angle - 90 * u.deg), meta=self.meta, visual=self.visual) @property def bounding_box(self): """ The minimal bounding box (`~regions.BoundingBox`) enclosing the exact elliptical region. """ # We use the solution described in http://stackoverflow.com/a/88020 # which is to use the parametric equation of an ellipse and to find # when dx/dt or dy/dt=0. cos_angle = np.cos(self.angle) sin_angle = np.sin(self.angle) tan_angle = np.tan(self.angle) t1 = np.arctan(-self.height * tan_angle / self.width) t2 = t1 + np.pi * u.rad dx1 = 0.5 * self.width * cos_angle * np.cos(t1) - 0.5 * self.height * sin_angle * np.sin(t1) dx2 = 0.5 * self.width * cos_angle * np.cos(t2) - 0.5 * self.height * sin_angle * np.sin(t2) if dx1 > dx2: dx1, dx2 = dx2, dx1 t1 = np.arctan(self.height / tan_angle / self.width) t2 = t1 + np.pi * u.rad dy1 = 0.5 * self.height * cos_angle * np.sin(t1) + 0.5 * self.width * sin_angle * np.cos(t1) dy2 = 0.5 * self.height * cos_angle * np.sin(t2) + 0.5 * self.width * sin_angle * np.cos(t2) if dy1 > dy2: dy1, dy2 = dy2, dy1 xmin = self.center.x + dx1 xmax = self.center.x + dx2 ymin = self.center.y + dy1 ymax = self.center.y + dy2 return BoundingBox.from_float(xmin, xmax, ymin, ymax) def to_mask(self, mode='center', subpixels=5): # NOTE: assumes this class represents a single circle self._validate_mode(mode, subpixels) if mode == 'center': mode = 'subpixels' subpixels = 1 # Find bounding box and mask size bbox = self.bounding_box ny, nx = bbox.shape # Find position of pixel edges and recenter so that ellipse is at origin xmin = float(bbox.ixmin) - 0.5 - self.center.x xmax = float(bbox.ixmax) - 0.5 - self.center.x ymin = float(bbox.iymin) - 0.5 - self.center.y ymax = float(bbox.iymax) - 0.5 - self.center.y if mode == 'subpixels': use_exact = 0 else: use_exact = 1 fraction = elliptical_overlap_grid( xmin, xmax, ymin, ymax, nx, ny, 0.5 * self.width, 0.5 * self.height, self.angle.to(u.rad).value, use_exact, subpixels, ) return RegionMask(fraction, bbox=bbox) def as_artist(self, origin=(0, 0), **kwargs): """ Matplotlib patch object for this region (`matplotlib.patches.Ellipse`). Parameters ---------- origin : array_like, optional The ``(x, y)`` pixel position of the origin of the displayed image. Default is (0, 0). kwargs : `dict` All keywords that a `~matplotlib.patches.Ellipse` object accepts Returns ------- patch : `~matplotlib.patches.Ellipse` Matplotlib ellipse patch """ from matplotlib.patches import Ellipse xy = self.center.x - origin[0], self.center.y - origin[1] width = self.width height = self.height # From the docstring: MPL expects "rotation in degrees (anti-clockwise)" angle = self.angle.to('deg').value mpl_params = self.mpl_properties_default('patch') mpl_params.update(kwargs) return Ellipse(xy=xy, width=width, height=height, angle=angle, **mpl_params) def _update_from_mpl_selector(self, *args, **kwargs): xmin, xmax, ymin, ymax = self._mpl_selector.extents self.center = PixCoord(x=0.5 * (xmin + xmax), y=0.5 * (ymin + ymax)) self.width = (xmax - xmin) self.height = (ymax - ymin) self.angle = 0. * u.deg if self._mpl_selector_callback is not None: self._mpl_selector_callback(self) def as_mpl_selector(self, ax, active=True, sync=True, callback=None, **kwargs): """ Matplotlib editable widget for this region (`matplotlib.widgets.EllipseSelector`) Parameters ---------- ax : `~matplotlib.axes.Axes` The Matplotlib axes to add the selector to. active : bool, optional Whether the selector should be active by default. sync : bool, optional If `True` (the default), the region will be kept in sync with the selector. Otherwise, the selector will be initialized with the values from the region but the two will then be disconnected. callback : func, optional If specified, this function will be called every time the region is updated. This only has an effect if ``sync`` is `True`. If a callback is set, it is called for the first time once the selector has been created. kwargs Additional keyword arguments are passed to matplotlib.widgets.EllipseSelector` Returns ------- selector : `matplotlib.widgets.EllipseSelector` The Matplotlib selector. Notes ----- Once a selector has been created, you will need to keep a reference to it until you no longer need it. In addition, you can enable/disable the selector at any point by calling ``selector.set_active(True)`` or ``selector.set_active(False)``. """ from matplotlib.widgets import EllipseSelector if hasattr(self, '_mpl_selector'): raise Exception("Cannot attach more than one selector to a region.") if self.angle.value != 0: raise NotImplementedError("Cannot create matplotlib selector for rotated ellipse.") if sync: sync_callback = self._update_from_mpl_selector else: def sync_callback(*args, **kwargs): pass self._mpl_selector = EllipseSelector(ax, sync_callback, interactive=True, rectprops={'edgecolor': self.visual.get('color', 'black'), 'facecolor': 'none', 'linewidth': self.visual.get('linewidth', 1), 'linestyle': self.visual.get('linestyle', 'solid')}) self._mpl_selector.extents = (self.center.x - self.width / 2, self.center.x + self.width / 2, self.center.y - self.height / 2, self.center.y + self.height / 2) self._mpl_selector.set_active(active) self._mpl_selector_callback = callback if sync and self._mpl_selector_callback is not None: self._mpl_selector_callback(self) return self._mpl_selector def rotate(self, center, angle): """Make a rotated region. Rotates counter-clockwise for positive ``angle``. Parameters ---------- center : `PixCoord` Rotation center point angle : `~astropy.coordinates.Angle` Rotation angle Returns ------- region : `EllipsePixelRegion` Rotated region (an independent copy) """ center = self.center.rotate(center, angle) angle = self.angle + angle return self.copy(center=center, angle=angle)
def __init__(self): self.window = Tk() self.window.title("Artefact Labeling") self.window.geometry('1425x770') #self.window.geometry('1920x1080') self.window.configure(background="gray38") self.mrt_layer_set = [] self.optionlist = [] self.mrt_layer_names = [] # TODO: replace by dbinfo = DatabaseInfo() # self.mrt_model = dbinfo.get_mrt_model self.mrt_model = { 't1_tse_tra_fs_Becken_0008': '0008', 't1_tse_tra_fs_Becken_Motion_0010': '0010', 't1_tse_tra_fs_mbh_Leber_0004': '0004', 't1_tse_tra_fs_mbh_Leber_Motion_0005': '0005', 't1_tse_tra_Kopf_0002': '0002', 't1_tse_tra_Kopf_Motion_0003': '0003', 't2_tse_tra_fs_Becken_0009': '0009', 't2_tse_tra_fs_Becken_Motion_0011': '0011', 't2_tse_tra_fs_Becken_Shim_xz_0012': '0012', 't2_tse_tra_fs_navi_Leber_0006': '0006', 't2_tse_tra_fs_navi_Leber_Shim_xz_0007': '0007' } self.mrt_smodel = { 't1_tse_tra_fs_Becken_0008': 'Becken', 't1_tse_tra_fs_Becken_Motion_0010': 'Becken', 't1_tse_tra_fs_mbh_Leber_0004': 'Leber', 't1_tse_tra_fs_mbh_Leber_Motion_0005': 'Leber', 't1_tse_tra_Kopf_0002': 'Kopf', 't1_tse_tra_Kopf_Motion_0003': 'Kopf', 't2_tse_tra_fs_Becken_0009': 'Becken', 't2_tse_tra_fs_Becken_Motion_0011': 'Becken', 't2_tse_tra_fs_Becken_Shim_xz_0012': 'Becken', 't2_tse_tra_fs_navi_Leber_0006': 'Leber', 't2_tse_tra_fs_navi_Leber_Shim_xz_0007': 'Leber' } self.mrt_artefact = { 't1_tse_tra_fs_Becken_0008': '', 't1_tse_tra_fs_Becken_Motion_0010': 'Move', 't1_tse_tra_fs_mbh_Leber_0004': '', 't1_tse_tra_fs_mbh_Leber_Motion_0005': 'Move', 't1_tse_tra_Kopf_0002': '', 't1_tse_tra_Kopf_Motion_0003': 'Move', 't2_tse_tra_fs_Becken_0009': '', 't2_tse_tra_fs_Becken_Motion_0011': 'Move', 't2_tse_tra_fs_Becken_Shim_xz_0012': 'Shim', 't2_tse_tra_fs_navi_Leber_0006': '', 't2_tse_tra_fs_navi_Leber_Shim_xz_0007': 'Shim' } self.col_list = {"red": "1", "green": "2", "blue": "3"} self.res_col_list = {"1": "red", "2": "green", "3": "blue"} self.artefact_list = [ "Movement-Artefact", "Shim-Artefact", "Noise-Artefact" ] self.mark_list = ["Rectangle", "Ellipse", "Lasso"] self.list_of_images = [ "icons/Move.png", "icons/Rectangle.png", "icons/Ellipse.png", "icons/Lasso.png", "icons/Lupe.png", "icons/3D.png" ] # TODO: adapt paths self.sFolder = "C:/Users/Sebastian Milde/Pictures/MRT" self.Path_marking = "C:/Users/Sebastian Milde/Pictures/Universitaet/Masterarbeit/Markings/" self.proband = os.listdir(self.sFolder) self.artefact = os.listdir(self.sFolder + "/ab/dicom_sorted") self.panel = Label(self.window, bg="black") self.rahmen1 = Frame(self.window, bg="gray65", bd=3, relief="sunken") self.rahmen1.place(x=5, y=5, width=215, height=250) self.rahmen2 = Frame(self.window, bg="gray65", bd=3, relief="sunken") self.rahmen2.place(x=5, y=260, width=215, height=200) self.text_r1 = Text(self.rahmen1, height=10, width=200) self.text_r1.insert(INSERT, "Choose MRT-Layer") # Define buttons and option menus image = Image.open("icons/open.png") img_open = ImageTk.PhotoImage(image) label = Label(image=img_open) label.image = img_open self.load_button = Button(self.rahmen1, image=img_open, text="Load MRT-Layer", font=('Arial', 11, 'bold'), bg="gray56", activeforeground='grey', borderwidth=4, compound=LEFT, command=self.load_MRT) self.path_entry = Entry(self.rahmen1) self.path_entry.place(x=5, y=50, width=200, height=25) self.path_entry.insert(0, self.sFolder) self.tool_buttons = [] self.activated_button = 0 self.button1_activated = True self.x_clicked = None self.y_clicked = None self.mouse_second_clicked = False def onClick(i): old_button = self.activated_button self.activated_button = i if self.activated_button == 0: toggle_selector.ES.set_active(False) toggle_selector.RS.set_active(False) toggle_selector.LS.set_active(False) self.button1_activated = True if self.activated_button == 2: toggle_selector.ES.set_active(True) toggle_selector.RS.set_active(False) toggle_selector.LS.set_active(False) self.button1_activated = False if self.activated_button == 1: toggle_selector.ES.set_active(False) toggle_selector.RS.set_active(True) toggle_selector.LS.set_active(False) self.button1_activated = False if self.activated_button == 3: toggle_selector.ES.set_active(False) toggle_selector.RS.set_active(False) toggle_selector.LS.set_active(True) self.button1_activated = False if old_button == i: pass else: self.tool_buttons[old_button].configure(relief=RAISED) self.tool_buttons[self.activated_button].configure( relief=SUNKEN) return column = 5 for i in range(0, len(self.list_of_images), 1): image = Image.open(self.list_of_images[i]) img_tool = ImageTk.PhotoImage(image) label = Label(image=img_tool) label.image = img_tool b = Button(self.rahmen2, image=img_tool, bg="gray56", borderwidth=2, command=lambda i=i: onClick(i)) if i == 5: row = 45 column = 5 else: row = 5 b.place(x=column, y=row) column += 40 self.tool_buttons.append(b) self.tool_buttons[self.activated_button].configure(relief=SUNKEN) self.proband_str = StringVar(self.window) self.proband_str.set(self.proband[0]) self.proband_option = OptionMenu(self.rahmen1, self.proband_str, *self.proband) self.proband_option.config(bg="gray56") self.artefact_str = StringVar(self.window) self.artefact_str.set(self.artefact[0]) self.artefact_option = OptionMenu(self.rahmen1, self.artefact_str, *self.artefact) self.artefact_option.config(bg="gray56") self.layer = StringVar(self.window) self.layer.set("(empty)") self.option_layers = OptionMenu(self.rahmen1, self.layer, "(empty)", command=self.change_layer) self.option_layers.config(bg="gray56") self.chooseArtefact = StringVar(self.window) self.chooseArtefact.set(self.artefact_list[0]) self.chooseArtefact_option = OptionMenu(self.rahmen2, self.chooseArtefact, *self.artefact_list) self.chooseArtefact_option.config(bg="gray56") self.set_cnn = Button(self.window, text="Settings for CNN", bg="gray56", font=('Arial', 11, 'bold'), command=self.chooseData) image = Image.open("icons/save.png") img = ImageTk.PhotoImage(image) label = Label(image=img) label.image = img image = Image.open("icons/exit.png") img_exit = ImageTk.PhotoImage(image) label = Label(image=img_exit) label.image = img_exit self.save_button = Button(self.window, image=img, text="Save", bg="gray56", font=('Arial', 11, 'bold'), borderwidth=4, compound=LEFT) self.exit_button = Button(self.window, image=img_exit, text="Exit", bg="gray56", font=('Arial', 11, 'bold'), borderwidth=4, compound=LEFT, command=self.exit) self.number_mrt_label = Label(self.window, bg="#000000", fg="white", font="Aral 23 bold") self.art_mod_label = Label(self.panel, bg="#000000", fg="white", font="Aral 12 bold") self.hint_label = Label(self.window, text="Please load MRT-Layer", bg="#000000", fg="white", font="Aral 25 bold") self.load_button.place( x=5, y=5, width=200, height=40) #self.load_button.place(x=5, y=5, width=200, height=40) self.proband_option.place( x=5, y=80, width=200, height=50 ) #self.proband_option.place(x=5, y=55, width=200, height=50) self.artefact_option.place( x=5, y=135, width=200, height=50 ) # self.artefact_option.place(x=5, y=105, width=200, height=50) self.option_layers.place( x=5, y=190, width=200, height=50 ) #self.option_layers.place(x=5, y=155, width=200, height=50) self.chooseArtefact_option.place(x=5, y=85, width=200, height=50) self.set_cnn.place(x=12.5, y=470, width=200, height=40) self.exit_button.place(x=12, y=725, width=200, height=40) self.save_button.place(x=12, y=680, width=200, height=40) self.panel.place(x=225, y=5, width=1204, height=764) # Visualisation self.fig = plt.figure(dpi=50) #self.fig.patch.set_facecolor('black') self.ax = plt.gca() self.pltc = None #self.ax.set_axis_bgcolor('black') self.ax.text(0.5, 0.5, 'To label MRT-Artefacts load MRT-Layer', horizontalalignment='center', verticalalignment='center', color='white', fontsize=20, transform=self.ax.transAxes) self.canvas = FigureCanvasTkAgg(self.fig, master=self.window) self.canvas.show() self.canvas.get_tk_widget().place(x=600, y=250) # expand=1 def lasso_onselect(verts): print(verts) p = path.Path(verts) current_mrt_layer = self.get_currentLayerNumber() proband = self.art_mod_label['text'][10:self.art_mod_label['text']. find('\n')] model = self.art_mod_label[ 'text'][self.art_mod_label['text'].find('\n') + 9:len(self.art_mod_label['text'])] print(proband) print(model) saveFile = shelve.open(self.Path_marking + proband + ".slv", writeback=True) print(p) patch = None col_str = None if self.chooseArtefact.get() == self.artefact_list[0]: col_str = "31" patch = patches.PathPatch(p, fill=False, edgecolor='red', lw=2) elif self.chooseArtefact.get() == self.artefact_list[1]: col_str = "32" patch = patches.PathPatch(p, fill=False, edgecolor='green', lw=2) elif self.chooseArtefact.get() == self.artefact_list[2]: col_str = "33" patch = patches.PathPatch(p, fill=False, edgecolor='blue', lw=2) self.ax.add_patch(patch) layer_name = model if saveFile.has_key(layer_name): number_str = str( self.mrt_layer_set[current_mrt_layer].get_current_Number( )) + "_" + col_str + "_" + str(len(self.ax.patches) - 1) saveFile[layer_name].update({number_str: p}) else: number_str = str( self.mrt_layer_set[current_mrt_layer].get_current_Number( )) + "_" + col_str + "_" + str(len(self.ax.patches) - 1) saveFile[layer_name] = {number_str: p} saveFile.close() self.fig.canvas.draw_idle() def ronselect(eclick, erelease): 'eclick and erelease are matplotlib events at press and release' col_str = None rect = None ell = None x1, y1 = eclick.xdata, eclick.ydata x2, y2 = erelease.xdata, erelease.ydata current_mrt_layer = self.get_currentLayerNumber() proband = self.art_mod_label['text'][10:self.art_mod_label['text']. find('\n')] model = self.art_mod_label[ 'text'][self.art_mod_label['text'].find('\n') + 9:len(self.art_mod_label['text'])] print(proband) print(model) saveFile = shelve.open(self.Path_marking + proband + ".slv", writeback=True) p = np.array(([x1, y1, x2, y2])) layer_name = model if toggle_selector.RS.active and not toggle_selector.ES.active: if self.chooseArtefact.get() == self.artefact_list[0]: col_str = "11" rect = plt.Rectangle((min(x1, x2), min(y1, y2)), np.abs(x1 - x2), np.abs(y1 - y2), fill=False, edgecolor="red", lw=2) elif self.chooseArtefact.get() == self.artefact_list[1]: col_str = "12" rect = plt.Rectangle((min(x1, x2), min(y1, y2)), np.abs(x1 - x2), np.abs(y1 - y2), fill=False, edgecolor="green", lw=2) elif self.chooseArtefact.get() == self.artefact_list[2]: col_str = "13" rect = plt.Rectangle((min(x1, x2), min(y1, y2)), np.abs(x1 - x2), np.abs(y1 - y2), fill=False, edgecolor="blue", lw=2) self.ax.add_patch(rect) elif toggle_selector.ES.active and not toggle_selector.RS.active: if self.chooseArtefact.get() == self.artefact_list[0]: col_str = "21" ell = Ellipse(xy=(min(x1, x2) + np.abs(x1 - x2) / 2, min(y1, y2) + np.abs(y1 - y2) / 2), width=np.abs(x1 - x2), height=np.abs(y1 - y2), edgecolor="red", fc='None', lw=2) elif self.chooseArtefact.get() == self.artefact_list[1]: col_str = "22" ell = Ellipse(xy=(min(x1, x2) + np.abs(x1 - x2) / 2, min(y1, y2) + np.abs(y1 - y2) / 2), width=np.abs(x1 - x2), height=np.abs(y1 - y2), edgecolor="green", fc='None', lw=2) elif self.chooseArtefact.get() == self.artefact_list[2]: col_str = "23" ell = Ellipse(xy=(min(x1, x2) + np.abs(x1 - x2) / 2, min(y1, y2) + np.abs(y1 - y2) / 2), width=np.abs(x1 - x2), height=np.abs(y1 - y2), edgecolor="blue", fc='None', lw=2) self.ax.add_patch(ell) if saveFile.has_key(layer_name): number_str = str( self.mrt_layer_set[current_mrt_layer].get_current_Number( )) + "_" + col_str + "_" + str(len(self.ax.patches) - 1) saveFile[layer_name].update({number_str: p}) else: number_str = str( self.mrt_layer_set[current_mrt_layer].get_current_Number( )) + "_" + col_str + "_" + str(len(self.ax.patches) - 1) saveFile[layer_name] = {number_str: p} saveFile.close() print(' startposition : (%f, %f)' % (eclick.xdata, eclick.ydata)) print(' endposition : (%f, %f)' % (erelease.xdata, erelease.ydata)) print(' used button : ', eclick.button) def toggle_selector(event): print(' Key pressed.') if self.activated_button == 2 and not toggle_selector.ES.active and ( toggle_selector.LS.active or toggle_selector.RS.active): toggle_selector.ES.set_active(True) toggle_selector.RS.set_active(False) toggle_selector.LS.set_active(False) if self.activated_button == 1 and not toggle_selector.RS.active and ( toggle_selector.LS.active or toggle_selector.ES.active): toggle_selector.ES.set_active(False) toggle_selector.RS.set_active(True) toggle_selector.LS.set_active(False) if self.activated_button == 3 and ( toggle_selector.ES.active or toggle_selector.RS.active ) and not toggle_selector.LS.active: toggle_selector.ES.set_active(False) toggle_selector.RS.set_active(False) toggle_selector.LS.set_active(True) toggle_selector.RS = RectangleSelector( self.ax, ronselect, button=[1] ) #drawtype='box', useblit=False, button=[1], minspanx=5, minspany=5, spancoords='pixels', interactive=True toggle_selector.ES = EllipseSelector( self.ax, ronselect, drawtype='line', button=[1], minspanx=5, minspany=5, spancoords='pixels', interactive=True ) #drawtype='line', minspanx=5, minspany=5, spancoords='pixels', interactive=True toggle_selector.LS = LassoSelector(self.ax, lasso_onselect, button=[1]) toggle_selector.ES.set_active(False) toggle_selector.RS.set_active(False) toggle_selector.LS.set_active(False) self.fig.canvas.mpl_connect('key_press_event', self.click) self.fig.canvas.mpl_connect('button_press_event', self.mouse_clicked) self.fig.canvas.mpl_connect('motion_notify_event', self.mouse_move) self.fig.canvas.mpl_connect('button_release_event', self.mouse_release) #self.fig.canvas.mpl_connect('key_press_event', toggle_selector) #lasso = LassoSelector(self.ax, self.onselect, button=[1]) #self.hint_label.place(x=550, y=200, width = 400, height = 300) self.window.mainloop()
def as_mpl_selector(self, ax, active=True, sync=True, callback=None, **kwargs): """ Matplotlib editable widget for this region (`matplotlib.widgets.EllipseSelector`) Parameters ---------- ax : `~matplotlib.axes.Axes` The Matplotlib axes to add the selector to. active : bool, optional Whether the selector should be active by default. sync : bool, optional If `True` (the default), the region will be kept in sync with the selector. Otherwise, the selector will be initialized with the values from the region but the two will then be disconnected. callback : func, optional If specified, this function will be called every time the region is updated. This only has an effect if ``sync`` is `True`. If a callback is set, it is called for the first time once the selector has been created. kwargs Additional keyword arguments are passed to matplotlib.widgets.EllipseSelector` Returns ------- selector : `matplotlib.widgets.EllipseSelector` The Matplotlib selector. Notes ----- Once a selector has been created, you will need to keep a reference to it until you no longer need it. In addition, you can enable/disable the selector at any point by calling ``selector.set_active(True)`` or ``selector.set_active(False)``. """ from matplotlib.widgets import EllipseSelector if hasattr(self, '_mpl_selector'): raise Exception("Cannot attach more than one selector to a region.") if self.angle.value != 0: raise NotImplementedError("Cannot create matplotlib selector for rotated ellipse.") if sync: sync_callback = self._update_from_mpl_selector else: def sync_callback(*args, **kwargs): pass self._mpl_selector = EllipseSelector(ax, sync_callback, interactive=True, rectprops={'edgecolor': self.visual.get('color', 'black'), 'facecolor': 'none', 'linewidth': self.visual.get('linewidth', 1), 'linestyle': self.visual.get('linestyle', 'solid')}) self._mpl_selector.extents = (self.center.x - self.width / 2, self.center.x + self.width / 2, self.center.y - self.height / 2, self.center.y + self.height / 2) self._mpl_selector.set_active(active) self._mpl_selector_callback = callback if sync and self._mpl_selector_callback is not None: self._mpl_selector_callback(self) return self._mpl_selector
#%% import numpy as np import matplotlib.pyplot as plt from matplotlib.widgets import EllipseSelector def onselect(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) def toggle_selector(event): print(' Key pressed.') if event.key in ['Q', 'q'] and toggle_selector.ES.active: print('EllipseSelector deactivated.') toggle_selector.RS.set_active(False) if event.key in ['A', 'a'] and not toggle_selector.ES.active: print('EllipseSelector activated.') toggle_selector.ES.set_active(True) x = np.arange(100.) / 99 y = np.sin(x) fig, ax = plt.subplots() ax.plot(x, y) toggle_selector.ES = EllipseSelector(ax, onselect, drawtype='line') fig.canvas.mpl_connect('key_press_event', toggle_selector) plt.show()
class FittingDataPlot2D(DataPlotEditorBase): nplots = 2 layout = 'horizontal' range_rect = Any(transient=True) peaks_ellipses = List([],transient=True) frangex = Tuple((0.0, 0.0),transient=True) frangey = Tuple((0.0, 0.0),transient=True) peaks = List([],transient=True) range_selector = Any(transient=True) # Instance(SpanSelector) peaks_selector = Any(transient=True) # (SpanSelector) editing = Enum('Peaks', ['Range', 'Peaks']) has_frange = Property(Bool) has_peaks = Property(Bool) def _get_has_frange(self): if (self.frangex[1]-self.frangex[0])>10 and (self.frangey[1]-self.frangey[0])>10: return True else: return False def _get_has_peaks(self): if len(self.peaks): return True else: return False def clear_patches(self, frange=True, peaks=True): if frange: try: self.range_rect.remove() self.range_rect = None except: pass if peaks: for ellipse in self.peaks_ellipses: try: ellipse.remove() self.peaks_ellipses.remove(ellipse) except: pass def clear_selections(self): self.clear_patches() self.peaks = [] self.frangex = (0.0,0.0) self.frangey = (0.0, 0.0) def draw_patches(self, frange=True, peaks=True): if all([frange, len(self.axs), len(self.frangex), len(self.frangey)]): self.range_rect = self.draw_rectangle(self.frangex, self.frangey, color='g', alpha=0.15) if all([peaks, len(self.axs), len(self.peaks)]): for p in self.peaks: self.peaks_ellipses.append(self.draw_ellipse(*p, color='r', alpha=0.4)) if self.figure is not None: if self.figure.canvas is not None: self.figure.canvas.draw() def mpl_setup(self): self.add_subplots(self.nplots) self.configure_selector(peaks=True) # self.figure.canvas.draw() # self.activate_selector() def draw_rectangle(self,xs,ys,alpha=0.2,color='g'): xy = (min(xs),min(ys)) width = np.abs(np.diff(xs)) height = np.abs(np.diff(ys)) re = Rectangle(xy, width, height, angle=0.0) ax = self.axs[0] ax.add_artist(re) re.set_alpha(alpha=alpha) re.set_facecolor(color) return re def draw_ellipse(self,xmid,ymid,width,height,alpha=0.4,color='r'): el = Ellipse(xy=(xmid, ymid), width=width, height=height, angle=0) ax = self.axs[0] ax.add_artist(el) #el.set_clip_box(ax.bbox) el.set_alpha(alpha=alpha) el.set_facecolor(color) return el def rect_onselect(self, eclick, erelease): xs = [eclick.xdata, erelease.xdata] ys = [eclick.ydata, erelease.ydata] #print xs, ys self.frangex = (min(xs), max(xs)) self.frangey = (min(ys), max(ys)) self.clear_patches(peaks=False) self.draw_patches(peaks=False) def ellipse_onselect(self, eclick, erelease): xs = [eclick.xdata, erelease.xdata] ys = [eclick.ydata, erelease.ydata] xmid, ymid = np.mean(xs), np.mean(ys) width, height = np.abs(np.diff(xs)), np.abs(np.diff(ys)) #print [xmid, ymid, width, height] self.peaks.append([xmid, ymid, width, height]) self.clear_patches(frange=False) self.draw_patches(frange=False) def configure_selector(self, frange=False, peaks=False): self.range_selector = RectangleSelector(self.axs[0], self.rect_onselect, drawtype='box', useblit=True, button=[1, 3], # don't use middle button minspanx=15, minspany=15, spancoords='pixels', #interactive=True, rectprops=dict(alpha=0.5, facecolor='g')) self.peaks_selector = EllipseSelector(self.axs[0], self.ellipse_onselect, drawtype='line', button=[1, 3], # don't use middle button spancoords='pixels', useblit=True, minspanx=10, minspany=10, rectprops=dict(alpha=0.5, facecolor='red')) self.peaks_selector.set_active(peaks) self.range_selector.set_active(frange) def activate_selector(self, frange=False, peaks=False): if self.peaks_selector is not None: self.peaks_selector.set_active(peaks) if self.range_selector is not None: self.range_selector.set_active(frange) def _editing_changed(self, new): if new == 'Range': self.configure_selector(frange=True, peaks=False) elif new == 'Peaks': self.configure_selector(frange=False, peaks=True)