def __add_xy_values_as_polygon__(self, xy: list, color: str, closed=False, fill=False, alpha=0.2, line_width=2): xy = PlotterInterface.get_xy_from_timestamp_to_date_number(xy) polygon = Polygon(np.array(xy), closed=closed, fill=fill) polygon.set_visible(True) polygon.set_color(color) polygon.set_alpha(alpha) polygon.set_linewidth(line_width) self.axes_for_candlesticks.add_patch(polygon)
def __plot_single_fibonacci_wave__(self, fib_wave: FibonacciWave, color: str, suffix: str = ''): if self.sys_config.config.fibonacci_detail_print: fib_wave.print(suffix) xy = fib_wave.get_xy_parameter() xy = PlotterInterface.get_xy_from_timestamp_to_date_number(xy) fib_polygon = Polygon(np.array(xy), closed=False, fill=False) fib_polygon.set_visible(True) fib_polygon.set_color(color) fib_polygon.set_linewidth(1) self.axes_for_candlesticks.add_patch(fib_polygon) fib_wave_patch = FibonacciWavePatch(fib_wave, fib_polygon) self.fibonacci_patch_container.add_patch(fib_wave_patch) fib_wave_patch.add_retracement_patch_list_to_axis(self.axes_for_candlesticks)
def __add_to_ranges_polygon_dic__(self, polygon: Polygon, for_main: bool, range: PatternRange): polygon.set_visible(False) polygon.set_color('r' if for_main else 'k') polygon.set_linewidth(1) self.axes_for_candlesticks.add_patch(polygon) for ticks in range.tick_list: if for_main: if ticks.f_var not in self.ranges_polygon_dic_list: self.ranges_polygon_dic_list[ticks.f_var] = [polygon] else: self.ranges_polygon_dic_list[ticks.f_var].append(polygon) else: if ticks.f_var not in self.ranges_opposite_polygon_dic_list: self.ranges_opposite_polygon_dic_list[ticks.f_var] = [polygon] else: self.ranges_opposite_polygon_dic_list[ticks.f_var].append(polygon)
class WidthPolygon(object): def __init__(self, ax, x, y, *args, **kwargs): self.ax, self.x, self.y = ax, x, y self.data = list(zip(x, y)) # [(x[0],y[0])] + zip(x,y) + [(x[-1],y[-1])] self.polygon = Polygon(self.data, *args, **kwargs) self.ax.add_patch(self.polygon) self.continuum, = self.ax.plot([x[0], x[-1]], [y[0], y[-1]], color='black', lw=1) def set_data(self, x, y): self.data = list(zip(x, y)) self.polygon.set_xy(self.data) self.continuum.set_data([[x[0], x[-1]], [y[0], y[-1]]]) def set_color(self, color): self.polygon.set_facecolor(color) def set_visible(self, visible): self.polygon.set_visible(visible) self.continuum.set_visible(visible) def __setattr__(self, name, value): if name == 'zoom_ignore': self.polygon.zoom_ignore = value self.continuum.zoom_ignore = value else: object.__setattr__(self, name, value) def delete(self): self.ax.patches.remove(self.polygon) self.ax.lines.remove(self.continuum)
class MplPolygonalROI(AbstractMplRoi): """ Matplotlib ROI for polygon selections Parameters ---------- axes : `~matplotlib.axes.Axes` The Matplotlib axes to draw to. roi : `~glue.core.roi.Roi`, optional If specified, this ROI will be used and updated, otherwise a new one will be created. """ _roi_cls = PolygonalROI def __init__(self, axes, roi=None): super(MplPolygonalROI, self).__init__(axes, roi=roi) self.plot_opts = {'edgecolor': PATCH_COLOR, 'facecolor': PATCH_COLOR, 'alpha': 0.3} self._patch = Polygon(np.array(list(zip([0, 1], [0, 1]))), zorder=100) self._patch.set_visible(False) self._axes.add_patch(self._patch) def _sync_patch(self): if self._roi.defined(): x, y = self._roi.to_polygon() self._patch.set_xy(list(zip(x + [x[0]], y + [y[0]]))) self._patch.set_visible(True) self._patch.set(**self.plot_opts) else: self._patch.set_visible(False) def start_selection(self, event, scrubbing=False): if event.inaxes != self._axes: return False if scrubbing or 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 scrubbing or event.key == SCRUBBING_KEY: self._scrubbing = True self._cx = event.xdata self._cy = event.ydata else: self.reset() self._roi.add_point(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(event.xdata - self._cx, event.ydata - self._cy) self._cx = event.xdata self._cy = event.ydata else: self._roi.add_point(event.xdata, event.ydata) self._sync_patch() self._draw() def finalize_selection(self, event): self._scrubbing = False self._mid_selection = False self._patch.set_visible(False) self._draw()
class ScatterPlotWidget(wx.Panel, ManageBusyCursorMixin): def __init__(self, parent, scatt_id, scatt_mgr, transpose, id=wx.ID_ANY): # TODO should not be transpose and scatt_id but x, y wx.Panel.__init__(self, parent, id) # bacause of aui (if floatable it can not take cursor from parent) ManageBusyCursorMixin.__init__(self, window=self) self.parent = parent self.full_extend = None self.mode = None self._createWidgets() self._doLayout() self.scatt_id = scatt_id self.scatt_mgr = scatt_mgr self.cidpress = None self.cidrelease = None self.rend_dt = {} self.transpose = transpose self.inverse = False self.SetSize((200, 100)) self.Layout() self.base_scale = 1.2 self.Bind(wx.EVT_CLOSE, lambda event: self.CleanUp()) self.plotClosed = Signal("ScatterPlotWidget.plotClosed") self.cursorMove = Signal("ScatterPlotWidget.cursorMove") self.contex_menu = ScatterPlotContextMenu(plot=self) self.ciddscroll = None self.canvas.mpl_connect('motion_notify_event', self.Motion) self.canvas.mpl_connect('button_press_event', self.OnPress) self.canvas.mpl_connect('button_release_event', self.OnRelease) self.canvas.mpl_connect('draw_event', self.DrawCallback) self.canvas.mpl_connect('figure_leave_event', self.OnCanvasLeave) def DrawCallback(self, event): self.polygon_drawer.DrawCallback(event) self.axes.draw_artist(self.zoom_rect) def _createWidgets(self): # Create the mpl Figure and FigCanvas objects. # 5x4 inches, 100 dots-per-inch # self.dpi = 100 self.fig = Figure((1.0, 1.0), dpi=self.dpi) self.fig.autolayout = True self.canvas = FigCanvas(self, -1, self.fig) self.axes = self.fig.add_axes([0.0, 0.0, 1, 1]) pol = Polygon(list(zip([0], [0])), animated=True) self.axes.add_patch(pol) self.polygon_drawer = PolygonDrawer(self.axes, pol=pol, empty_pol=True) self.zoom_wheel_coords = None self.zoom_rect_coords = None self.zoom_rect = Polygon(list(zip([0], [0])), facecolor='none') self.zoom_rect.set_visible(False) self.axes.add_patch(self.zoom_rect) def ZoomToExtend(self): if self.full_extend: self.axes.axis(self.full_extend) self.canvas.draw() def SetMode(self, mode): self._deactivateMode() if mode == 'zoom': self.ciddscroll = self.canvas.mpl_connect('scroll_event', self.ZoomWheel) self.mode = 'zoom' elif mode == 'zoom_extend': self.mode = 'zoom_extend' elif mode == 'pan': self.mode = 'pan' elif mode: self.polygon_drawer.SetMode(mode) def SetSelectionPolygonMode(self, activate): self.polygon_drawer.SetSelectionPolygonMode(activate) def _deactivateMode(self): self.mode = None self.polygon_drawer.SetMode(None) if self.ciddscroll: self.canvas.mpl_disconnect(self.ciddscroll) self.zoom_rect.set_visible(False) self._stopCategoryEdit() def GetCoords(self): coords = self.polygon_drawer.GetCoords() if coords is None: return if self.transpose: for c in coords: tmp = c[0] c[0] = c[1] c[1] = tmp return coords def SetEmpty(self): return self.polygon_drawer.SetEmpty() def OnRelease(self, event): if not self.mode == "zoom": return self.zoom_rect.set_visible(False) self.ZoomRectangle(event) self.canvas.draw() def OnPress(self, event): 'on button press we will see if the mouse is over us and store some data' if not event.inaxes: return if self.mode == "zoom_extend": self.ZoomToExtend() if event.xdata and event.ydata: self.zoom_wheel_coords = {'x': event.xdata, 'y': event.ydata} self.zoom_rect_coords = {'x': event.xdata, 'y': event.ydata} else: self.zoom_wheel_coords = None self.zoom_rect_coords = None def _stopCategoryEdit(self): 'disconnect all the stored connection ids' if self.cidpress: self.canvas.mpl_disconnect(self.cidpress) if self.cidrelease: self.canvas.mpl_disconnect(self.cidrelease) # self.canvas.mpl_disconnect(self.cidmotion) def _doLayout(self): self.main_sizer = wx.BoxSizer(wx.VERTICAL) self.main_sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW) self.SetSizer(self.main_sizer) self.main_sizer.Fit(self) def Plot(self, cats_order, scatts, ellipses, styles): """Redraws the figure """ callafter_list = [] if self.full_extend: cx = self.axes.get_xlim() cy = self.axes.get_ylim() c = cx + cy else: c = None q = Queue() _rendDtMemmapsToFiles(self.rend_dt) p = Process(target=MergeImg, args=(cats_order, scatts, styles, self.rend_dt, q)) p.start() merged_img, self.full_extend, self.rend_dt = q.get() p.join() _rendDtFilesToMemmaps(self.rend_dt) merged_img = np.memmap(filename=merged_img['dt'], shape=merged_img['sh']) #merged_img, self.full_extend = MergeImg(cats_order, scatts, styles, None) self.axes.clear() self.axes.axis('equal') if self.transpose: merged_img = np.transpose(merged_img, (1, 0, 2)) img = imshow(self.axes, merged_img, extent=[int(ceil(x)) for x in self.full_extend], origin='lower', interpolation='nearest', aspect="equal") callafter_list.append([self.axes.draw_artist, [img]]) callafter_list.append([grass.try_remove, [merged_img.filename]]) for cat_id in cats_order: if cat_id == 0: continue if cat_id not in ellipses: continue e = ellipses[cat_id] if not e: continue colors = styles[cat_id]['color'].split(":") if self.transpose: e['theta'] = 360 - e['theta'] + 90 if e['theta'] >= 360: e['theta'] = abs(360 - e['theta']) e['pos'] = [e['pos'][1], e['pos'][0]] ellip = Ellipse(xy=e['pos'], width=e['width'], height=e['height'], angle=e['theta'], edgecolor="w", linewidth=1.5, facecolor='None') self.axes.add_artist(ellip) callafter_list.append([self.axes.draw_artist, [ellip]]) color = [ int(v) / 255.0 for v in styles[cat_id]['color'].split(":")[:3] ] ellip = Ellipse(xy=e['pos'], width=e['width'], height=e['height'], angle=e['theta'], edgecolor=color, linewidth=1, facecolor='None') self.axes.add_artist(ellip) callafter_list.append([self.axes.draw_artist, [ellip]]) center = Line2D( [e['pos'][0]], [e['pos'][1]], marker='x', markeredgecolor='w', # markerfacecolor=color, markersize=2) self.axes.add_artist(center) callafter_list.append([self.axes.draw_artist, [center]]) callafter_list.append([self.fig.canvas.blit, []]) if c: self.axes.axis(c) wx.CallAfter(lambda: self.CallAfter(callafter_list)) def CallAfter(self, funcs_list): while funcs_list: fcn, args = funcs_list.pop(0) fcn(*args) self.canvas.draw() def CleanUp(self): self.plotClosed.emit(scatt_id=self.scatt_id) self.Destroy() def ZoomWheel(self, event): # get the current x and y limits if not event.inaxes: return # tcaswell # http://stackoverflow.com/questions/11551049/matplotlib-plot-zooming-with-scroll-wheel cur_xlim = self.axes.get_xlim() cur_ylim = self.axes.get_ylim() xdata = event.xdata ydata = event.ydata if event.button == 'up': scale_factor = 1 / self.base_scale elif event.button == 'down': scale_factor = self.base_scale else: scale_factor = 1 extend = (xdata - (xdata - cur_xlim[0]) * scale_factor, xdata + (cur_xlim[1] - xdata) * scale_factor, ydata - (ydata - cur_ylim[0]) * scale_factor, ydata + (cur_ylim[1] - ydata) * scale_factor) self.axes.axis(extend) self.canvas.draw() def ZoomRectangle(self, event): # get the current x and y limits if not self.mode == "zoom": return if event.inaxes is None: return if event.button != 1: return cur_xlim = self.axes.get_xlim() cur_ylim = self.axes.get_ylim() x1, y1 = event.xdata, event.ydata x2 = deepcopy(self.zoom_rect_coords['x']) y2 = deepcopy(self.zoom_rect_coords['y']) if x1 == x2 or y1 == y2: return if x1 > x2: tmp = x1 x1 = x2 x2 = tmp if y1 > y2: tmp = y1 y1 = y2 y2 = tmp self.axes.axis((x1, x2, y1, y2)) # self.axes.set_xlim(x1, x2)#, auto = True) # self.axes.set_ylim(y1, y2)#, auto = True) self.canvas.draw() def Motion(self, event): self.PanMotion(event) self.ZoomRectMotion(event) if event.inaxes is None: return self.cursorMove.emit(x=event.xdata, y=event.ydata, scatt_id=self.scatt_id) def OnCanvasLeave(self, event): self.cursorMove.emit(x=None, y=None, scatt_id=self.scatt_id) def PanMotion(self, event): 'on mouse movement' if not self.mode == "pan": return if event.inaxes is None: return if event.button != 1: return cur_xlim = self.axes.get_xlim() cur_ylim = self.axes.get_ylim() x, y = event.xdata, event.ydata mx = (x - self.zoom_wheel_coords['x']) * 0.6 my = (y - self.zoom_wheel_coords['y']) * 0.6 extend = (cur_xlim[0] - mx, cur_xlim[1] - mx, cur_ylim[0] - my, cur_ylim[1] - my) self.zoom_wheel_coords['x'] = x self.zoom_wheel_coords['y'] = y self.axes.axis(extend) # self.canvas.copy_from_bbox(self.axes.bbox) # self.canvas.restore_region(self.background) self.canvas.draw() def ZoomRectMotion(self, event): if not self.mode == "zoom": return if event.inaxes is None: return if event.button != 1: return x1, y1 = event.xdata, event.ydata self.zoom_rect.set_visible(True) x2 = self.zoom_rect_coords['x'] y2 = self.zoom_rect_coords['y'] self.zoom_rect.xy = ((x1, y1), (x1, y2), (x2, y2), (x2, y1), (x1, y1)) # self.axes.draw_artist(self.zoom_rect) self.canvas.draw()
class ScatterPlotWidget(wx.Panel, ManageBusyCursorMixin): def __init__(self, parent, scatt_id, scatt_mgr, transpose, id=wx.ID_ANY): # TODO should not be transpose and scatt_id but x, y wx.Panel.__init__(self, parent, id) # bacause of aui (if floatable it can not take cursor from parent) ManageBusyCursorMixin.__init__(self, window=self) self.parent = parent self.full_extend = None self.mode = None self._createWidgets() self._doLayout() self.scatt_id = scatt_id self.scatt_mgr = scatt_mgr self.cidpress = None self.cidrelease = None self.rend_dt = {} self.transpose = transpose self.inverse = False self.SetSize((200, 100)) self.Layout() self.base_scale = 1.2 self.Bind(wx.EVT_CLOSE, lambda event: self.CleanUp()) self.plotClosed = Signal("ScatterPlotWidget.plotClosed") self.cursorMove = Signal("ScatterPlotWidget.cursorMove") self.contex_menu = ScatterPlotContextMenu(plot=self) self.ciddscroll = None self.canvas.mpl_connect('motion_notify_event', self.Motion) self.canvas.mpl_connect('button_press_event', self.OnPress) self.canvas.mpl_connect('button_release_event', self.OnRelease) self.canvas.mpl_connect('draw_event', self.DrawCallback) self.canvas.mpl_connect('figure_leave_event', self.OnCanvasLeave) def DrawCallback(self, event): self.polygon_drawer.DrawCallback(event) self.axes.draw_artist(self.zoom_rect) def _createWidgets(self): # Create the mpl Figure and FigCanvas objects. # 5x4 inches, 100 dots-per-inch # self.dpi = 100 self.fig = Figure((1.0, 1.0), dpi=self.dpi) self.fig.autolayout = True self.canvas = FigCanvas(self, -1, self.fig) self.axes = self.fig.add_axes([0.0, 0.0, 1, 1]) pol = Polygon(list(zip([0], [0])), animated=True) self.axes.add_patch(pol) self.polygon_drawer = PolygonDrawer(self.axes, pol=pol, empty_pol=True) self.zoom_wheel_coords = None self.zoom_rect_coords = None self.zoom_rect = Polygon(list(zip([0], [0])), facecolor='none') self.zoom_rect.set_visible(False) self.axes.add_patch(self.zoom_rect) def ZoomToExtend(self): if self.full_extend: self.axes.axis(self.full_extend) self.canvas.draw() def SetMode(self, mode): self._deactivateMode() if mode == 'zoom': self.ciddscroll = self.canvas.mpl_connect( 'scroll_event', self.ZoomWheel) self.mode = 'zoom' elif mode == 'zoom_extend': self.mode = 'zoom_extend' elif mode == 'pan': self.mode = 'pan' elif mode: self.polygon_drawer.SetMode(mode) def SetSelectionPolygonMode(self, activate): self.polygon_drawer.SetSelectionPolygonMode(activate) def _deactivateMode(self): self.mode = None self.polygon_drawer.SetMode(None) if self.ciddscroll: self.canvas.mpl_disconnect(self.ciddscroll) self.zoom_rect.set_visible(False) self._stopCategoryEdit() def GetCoords(self): coords = self.polygon_drawer.GetCoords() if coords is None: return if self.transpose: for c in coords: tmp = c[0] c[0] = c[1] c[1] = tmp return coords def SetEmpty(self): return self.polygon_drawer.SetEmpty() def OnRelease(self, event): if not self.mode == "zoom": return self.zoom_rect.set_visible(False) self.ZoomRectangle(event) self.canvas.draw() def OnPress(self, event): 'on button press we will see if the mouse is over us and store some data' if not event.inaxes: return if self.mode == "zoom_extend": self.ZoomToExtend() if event.xdata and event.ydata: self.zoom_wheel_coords = {'x': event.xdata, 'y': event.ydata} self.zoom_rect_coords = {'x': event.xdata, 'y': event.ydata} else: self.zoom_wheel_coords = None self.zoom_rect_coords = None def _stopCategoryEdit(self): 'disconnect all the stored connection ids' if self.cidpress: self.canvas.mpl_disconnect(self.cidpress) if self.cidrelease: self.canvas.mpl_disconnect(self.cidrelease) # self.canvas.mpl_disconnect(self.cidmotion) def _doLayout(self): self.main_sizer = wx.BoxSizer(wx.VERTICAL) self.main_sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW) self.SetSizer(self.main_sizer) self.main_sizer.Fit(self) def Plot(self, cats_order, scatts, ellipses, styles): """Redraws the figure """ callafter_list = [] if self.full_extend: cx = self.axes.get_xlim() cy = self.axes.get_ylim() c = cx + cy else: c = None q = Queue() _rendDtMemmapsToFiles(self.rend_dt) p = Process(target=MergeImg, args=(cats_order, scatts, styles, self.rend_dt, q)) p.start() merged_img, self.full_extend, self.rend_dt = q.get() p.join() _rendDtFilesToMemmaps(self.rend_dt) merged_img = np.memmap( filename=merged_img['dt'], shape=merged_img['sh']) #merged_img, self.full_extend = MergeImg(cats_order, scatts, styles, None) self.axes.clear() self.axes.axis('equal') if self.transpose: merged_img = np.transpose(merged_img, (1, 0, 2)) img = imshow(self.axes, merged_img, extent=[int(ceil(x)) for x in self.full_extend], origin='lower', interpolation='nearest', aspect="equal") callafter_list.append([self.axes.draw_artist, [img]]) callafter_list.append([grass.try_remove, [merged_img.filename]]) for cat_id in cats_order: if cat_id == 0: continue if cat_id not in ellipses: continue e = ellipses[cat_id] if not e: continue colors = styles[cat_id]['color'].split(":") if self.transpose: e['theta'] = 360 - e['theta'] + 90 if e['theta'] >= 360: e['theta'] = abs(360 - e['theta']) e['pos'] = [e['pos'][1], e['pos'][0]] ellip = Ellipse(xy=e['pos'], width=e['width'], height=e['height'], angle=e['theta'], edgecolor="w", linewidth=1.5, facecolor='None') self.axes.add_artist(ellip) callafter_list.append([self.axes.draw_artist, [ellip]]) color = map( lambda v: int(v) / 255.0, styles[cat_id]['color'].split(":")) ellip = Ellipse(xy=e['pos'], width=e['width'], height=e['height'], angle=e['theta'], edgecolor=color, linewidth=1, facecolor='None') self.axes.add_artist(ellip) callafter_list.append([self.axes.draw_artist, [ellip]]) center = Line2D([e['pos'][0]], [e['pos'][1]], marker='x', markeredgecolor='w', # markerfacecolor=color, markersize=2) self.axes.add_artist(center) callafter_list.append([self.axes.draw_artist, [center]]) callafter_list.append([self.fig.canvas.blit, []]) if c: self.axes.axis(c) wx.CallAfter(lambda: self.CallAfter(callafter_list)) def CallAfter(self, funcs_list): while funcs_list: fcn, args = funcs_list.pop(0) fcn(*args) self.canvas.draw() def CleanUp(self): self.plotClosed.emit(scatt_id=self.scatt_id) self.Destroy() def ZoomWheel(self, event): # get the current x and y limits if not event.inaxes: return # tcaswell # http://stackoverflow.com/questions/11551049/matplotlib-plot-zooming-with-scroll-wheel cur_xlim = self.axes.get_xlim() cur_ylim = self.axes.get_ylim() xdata = event.xdata ydata = event.ydata if event.button == 'up': scale_factor = 1 / self.base_scale elif event.button == 'down': scale_factor = self.base_scale else: scale_factor = 1 extend = (xdata - (xdata - cur_xlim[0]) * scale_factor, xdata + (cur_xlim[1] - xdata) * scale_factor, ydata - (ydata - cur_ylim[0]) * scale_factor, ydata + (cur_ylim[1] - ydata) * scale_factor) self.axes.axis(extend) self.canvas.draw() def ZoomRectangle(self, event): # get the current x and y limits if not self.mode == "zoom": return if event.inaxes is None: return if event.button != 1: return cur_xlim = self.axes.get_xlim() cur_ylim = self.axes.get_ylim() x1, y1 = event.xdata, event.ydata x2 = deepcopy(self.zoom_rect_coords['x']) y2 = deepcopy(self.zoom_rect_coords['y']) if x1 == x2 or y1 == y2: return if x1 > x2: tmp = x1 x1 = x2 x2 = tmp if y1 > y2: tmp = y1 y1 = y2 y2 = tmp self.axes.axis((x1, x2, y1, y2)) # self.axes.set_xlim(x1, x2)#, auto = True) # self.axes.set_ylim(y1, y2)#, auto = True) self.canvas.draw() def Motion(self, event): self.PanMotion(event) self.ZoomRectMotion(event) if event.inaxes is None: return self.cursorMove.emit( x=event.xdata, y=event.ydata, scatt_id=self.scatt_id) def OnCanvasLeave(self, event): self.cursorMove.emit(x=None, y=None, scatt_id=self.scatt_id) def PanMotion(self, event): 'on mouse movement' if not self.mode == "pan": return if event.inaxes is None: return if event.button != 1: return cur_xlim = self.axes.get_xlim() cur_ylim = self.axes.get_ylim() x, y = event.xdata, event.ydata mx = (x - self.zoom_wheel_coords['x']) * 0.6 my = (y - self.zoom_wheel_coords['y']) * 0.6 extend = ( cur_xlim[0] - mx, cur_xlim[1] - mx, cur_ylim[0] - my, cur_ylim[1] - my) self.zoom_wheel_coords['x'] = x self.zoom_wheel_coords['y'] = y self.axes.axis(extend) # self.canvas.copy_from_bbox(self.axes.bbox) # self.canvas.restore_region(self.background) self.canvas.draw() def ZoomRectMotion(self, event): if not self.mode == "zoom": return if event.inaxes is None: return if event.button != 1: return x1, y1 = event.xdata, event.ydata self.zoom_rect.set_visible(True) x2 = self.zoom_rect_coords['x'] y2 = self.zoom_rect_coords['y'] self.zoom_rect.xy = ((x1, y1), (x1, y2), (x2, y2), (x2, y1), (x1, y1)) # self.axes.draw_artist(self.zoom_rect) self.canvas.draw()
class MplPolygonalROI(AbstractMplRoi): """ Defines and displays polygonal ROIs on matplotlib plots 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, roi=None): """ :param axes: A matplotlib Axes object to attach the graphical ROI to """ AbstractMplRoi.__init__(self, axes, roi=roi) self.plot_opts = { 'edgecolor': PATCH_COLOR, 'facecolor': PATCH_COLOR, 'alpha': 0.3 } self._setup_patch() def _setup_patch(self): self._patch = Polygon(np.array(list(zip([0, 1], [0, 1])))) self._patch.set_zorder(100) self._patch.set(**self.plot_opts) self._axes.add_patch(self._patch) self._patch.set_visible(False) self._sync_patch() def _roi_factory(self): return PolygonalROI() def _sync_patch(self): # Update geometry if not self._roi.defined(): self._patch.set_visible(False) else: x, y = self._roi.to_polygon() self._patch.set_xy(list(zip(x + [x[0]], y + [y[0]]))) self._patch.set_visible(True) # Update appearance self._patch.set(**self.plot_opts) # Refresh self._axes.figure.canvas.draw() def start_selection(self, event, scrubbing=False): if event.inaxes != self._axes: return False if scrubbing or 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 scrubbing or event.key == SCRUBBING_KEY: self._scrubbing = True self._cx = event.xdata self._cy = event.ydata else: self.reset() self._roi.add_point(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(event.xdata - self._cx, event.ydata - self._cy) self._cx = event.xdata self._cy = event.ydata else: self._roi.add_point(event.xdata, event.ydata) self._sync_patch() def finalize_selection(self, event): self._scrubbing = False self._mid_selection = False self._patch.set_visible(False) self._axes.figure.canvas.draw()
class MplPolygonalROI(AbstractMplRoi): """ Defines and displays polygonal ROIs on matplotlib plots 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.plot_opts = {'edgecolor': PATCH_COLOR, 'facecolor': PATCH_COLOR, 'alpha': 0.3} self._setup_patch() def _setup_patch(self): self._patch = Polygon(np.array(list(zip([0, 1], [0, 1])))) self._patch.set_zorder(100) self._patch.set(**self.plot_opts) self._axes.add_patch(self._patch) self._patch.set_visible(False) self._sync_patch() def _roi_factory(self): return PolygonalROI() def _sync_patch(self): # Update geometry if not self._roi.defined(): self._patch.set_visible(False) else: x, y = self._roi.to_polygon() self._patch.set_xy(list(zip(x + [x[0]], y + [y[0]]))) self._patch.set_visible(True) # Update appearance self._patch.set(**self.plot_opts) # Refresh self._axes.figure.canvas.draw() 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._cx = event.xdata self._cy = event.ydata else: self.reset() self._roi.add_point(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(event.xdata - self._cx, event.ydata - self._cy) self._cx = event.xdata self._cy = event.ydata else: self._roi.add_point(event.xdata, event.ydata) self._sync_patch() def finalize_selection(self, event): self._scrubbing = False self._mid_selection = False self._patch.set_visible(False) self._axes.figure.canvas.draw()
class PolygonEditor(object): ''' This edits the polygons drawn on the map ''' show_verts = True epsilon = 3 #threshold def __init__(self, axis, canvas): ''' initialises the editable polygon object ''' self.axis = axis self.polygon = None self.line = None self.xy_values = np.array([]) self._ind = None self.background = None #background copying self._callback_ids = list() self._callback_ids.append( canvas.mpl_connect('draw_event', self.draw_callback)) self._callback_ids.append( canvas.mpl_connect('button_press_event', self.button_press_callback)) self._callback_ids.append( canvas.mpl_connect('button_release_event', self.button_release_callback)) self._callback_ids.append( canvas.mpl_connect('motion_notify_event', self.motion_notify_callback)) self.canvas = canvas def add_point(self, xval, yval): """ adds an new point to the selection list and redraws the selection tool""" if self.xy_values.shape[0] == 0: self.xy_values = np.array([ (xval, yval), ]) else: self.xy_values = np.concatenate((self.xy_values, [ [xval, yval], ]), axis=0) self.refresh() def refresh(self): """ This method looks at the list of points available and depending on the number of points in the list creates a point or line or a polygon and draws them""" if self.xy_values.shape[0] == 0: # No points available self.reset_line() self.reset_polygon() elif self.xy_values.shape[0] <= 2: # point or line for 1 or 2 points xval, yval = zip(*self.xy_values) if self.line == None: self.line = Line2D(xval, yval, marker='o', markerfacecolor='r', animated=True) self.axis.add_line(self.line) else: self.line.set_data(zip(*self.xy_values)) self.reset_polygon() else: # more than 2 points if polygon is not created then creates one and draws if self.polygon == None: self.polygon = Polygon(self.xy_values, animated=True, alpha=polygon_alpha) self.polygon.add_callback(self.polygon_changed) self.axis.add_patch(self.polygon) else: self.polygon.xy = self.xy_values self.line.set_data(zip(*self.xy_values)) self.draw_callback(None) self.canvas.draw() def reset_line(self): """ resets the line i.e removes the line from the axes and resets to None """ if self.line != None: self.line.remove() self.line = None def reset_polygon(self): """ resets the polygon ie. removes the polygon from the axis and reset to None """ if self.polygon != None: self.polygon.remove() self.polygon = None def draw_line(self): """ draws the line if available """ if self.line != None: self.axis.draw_artist(self.line) def draw_polygon(self): """ draws polygon if available""" if self.polygon != None: self.axis.draw_artist(self.polygon) def disable(self): """ disables the events and the selection """ self.set_visibility(False) for callback_id in self._callback_ids: self.canvas.mpl_disconnect(callback_id) self.canvas = None def enable(self): """ enables the selection """ self.set_visibility(True) def set_visibility(self, status): """ sets the visibility of the selection object """ if self.polygon != None: self.polygon.set_visible(status) if self.line != None: self.line.set_visible(status) self.canvas.blit(self.axis.bbox) def draw_callback(self, dummy_event): """ this method draws the selection object """ self.background = self.canvas.copy_from_bbox(self.axis.bbox) self.draw_polygon() self.draw_line() self.canvas.blit(self.axis.bbox) def polygon_changed(self, poly): """ redraws the polygon """ vis = self.line.get_visible() Artist.update_from(self.line, poly) self.line.set_visible(vis) def get_index_under_point(self, event): """ gets the index of the point under the event (mouse click) """ if self.xy_values.shape[0] == 0: return None xy_values = self.xy_values xt_values, yt_values = xy_values[:, 0], xy_values[:, 1] dist = np.sqrt((xt_values - event.xdata)**2 + (yt_values - event.ydata)**2) indseq = np.nonzero(np.equal(dist, np.amin(dist)))[0] ind = indseq[0] if dist[ind] >= self.epsilon: ind = None return ind def button_press_callback(self, event): """ callback to mouse press event """ if not self.show_verts: return if event.inaxes == None: return if event.button != 1: return self._ind = self.get_index_under_point(event) if self._ind == None: self.insert_datapoint(event) def button_release_callback(self, event): """ callback to mouse release event """ if not self.show_verts: return if event.button == 2: self.insert_datapoint(event) return if event.button == 3: self.delete_datapoint(event) return if event.button != 1: return self._ind = None def insert_datapoint(self, event): """ inserts a new data point between the segment that is closest in polygon """ if self.xy_values.shape[0] <= 2: self.add_point(event.xdata, event.ydata) else: event_point = event.xdata, event.ydata prev_d = dist_point_to_segment(event_point, self.xy_values[0], self.xy_values[-1]) prev_i = len(self.xy_values) for i in range(len(self.xy_values) - 1): seg_start = self.xy_values[i] seg_end = self.xy_values[i + 1] dist_p_s = dist_point_to_segment(event_point, seg_start, seg_end) if dist_p_s < prev_d: prev_i = i prev_d = dist_p_s self.xy_values = np.array( list(self.xy_values[:prev_i + 1]) + [(event.xdata, event.ydata)] + list(self.xy_values[prev_i + 1:])) self.refresh() def delete_datapoint(self, event): """ deletes the data point under the point in event """ ind = self.get_index_under_point(event) if ind is not None: self.xy_values = np.array( [tup for i, tup in enumerate(self.xy_values) if i != ind]) self.refresh() self.canvas.draw() def motion_notify_callback(self, event): """ callback for the mouse motion with button press. this is to move the edge points of the polygon""" if not self.show_verts: return if self._ind is None: return if event.inaxes is None: return if event.button != 1: return xval, yval = event.xdata, event.ydata self.xy_values[self._ind] = xval, yval self.refresh() self.canvas.restore_region(self.background) self.axis.draw_artist(self.polygon) self.axis.draw_artist(self.line) self.canvas.blit(self.axis.bbox) def reset(self): """ resets the points in the selection deleting the line and polygon""" self.xy_values = np.array([]) self.reset_line() self.reset_polygon()
def ScatterGraph(self): AnnotatedArtists = [] # # Compute the scatter plot for this cluster # NumberOfFrames = self.Data.GetNumberOfFrames() NumberOfObjects = self.Data.GetNumberOfObjects() FirstObject = self.Data.GetFirstObject() - 2 # Include filtered and noise LastObject = self.Data.GetLastObject() TasksPerFrame = self.Data.GetTasksPerFrame() SelectedFrame = self.GUI.GetSelectedFrame() SelectedCluster = self.GUI.GetSelectedCluster() SelectedMetricX = self.GUI.GetSelectedMetricX() SelectedMetricY = self.GUI.GetSelectedMetricY() if self.GUI.in_3D(): SelectedMetricZ = self.GUI.GetSelectedMetricZ() # cursor = Cursor(self.ScatterPlotAxes, useblit=True, color='black', linewidth=1 ) for current_frame in range(1, NumberOfFrames+1): for current_object in range(FirstObject, LastObject+1): (r, g, b) = Decorations.RGBColor0_1(current_object) # # Compute the scatter plot for this cluster # xdata = self.Data.GetClusterData( current_frame, current_object, SelectedMetricX ) ydata = self.Data.GetClusterData( current_frame, current_object, SelectedMetricY ) if (len(xdata) == 0) or (len(ydata) == 0): continue if self.GUI.in_3D(): zdata = self.Data.GetClusterData( current_frame, current_object, SelectedMetricZ ) if (len(zdata) == 0): continue if (self.GUI.in_Trajectory_View()): if self.GUI.RatioX(): xdata = xdata * TasksPerFrame[current_frame-1] if self.GUI.RatioY(): ydata = ydata * TasksPerFrame[current_frame-1] if self.GUI.in_3D() and self.GUI.RatioZ(): zdata = zdata * TasksPerFrame[current_frame-1] if self.GUI.in_3D(): scatter = self.ScatterPlotAxes.scatter( xdata, ydata, zdata, color=(r, g, b), zorder=2, s=50, marker=Decorations.ChooseMarker(current_object), picker=True ) else: scatter = self.ScatterPlotAxes.scatter( xdata, ydata, color=(r, g, b), zorder=2, s=50, marker=Decorations.ChooseMarker(current_object), picker=True ) thumb = self.GUI.GetThumbAxes(current_frame).scatter( xdata, ydata, color=(r, g, b), zorder=2, s=100, marker=Decorations.ChooseMarker(current_object)) thumb.set_visible( False ) self.Thumbs[(current_object, current_frame)] = thumb scatter.set_gid( self.Data.PrettyCluster(current_object) ) scatter.set_visible( False ) self.Scatters[(current_object, current_frame)] = scatter AnnotatedArtists.append( scatter ) # # Compute the centroid for this cluster # centroid_x = nanmean( xdata ) centroid_y = nanmean( ydata ) if self.GUI.in_3D(): centroid_z = nanmean( zdata ) centroid = self.ScatterPlotAxes.scatter( centroid_x, centroid_y, centroid_z, s=50, color=(r, g, b), edgecolor="black", marker="o", zorder=3, picker=True ) self.Trajectories[(current_object, current_frame)] = (centroid_x, centroid_y, centroid_z) else: centroid = self.ScatterPlotAxes.scatter( centroid_x, centroid_y, s=50, color=(r, g, b), edgecolor="black", marker="o", zorder=3, picker=True) self.Trajectories[(current_object, current_frame)] = (centroid_x, centroid_y) centroid.set_gid( self.Data.PrettyCluster(current_object) ) centroid.set_visible(False) self.Centroids[(current_object, current_frame)] = centroid AnnotatedArtists.append( centroid ) # # Compute the convex hull for this cluster # if (AvailableHulls) and self.GUI.in_2D(): points = np.array( zip(xdata, ydata) ) if (len(points) < 3): continue try: hull = ConvexHull( points, qhull_options='Pp' ) vertices = hull.vertices except: vertices = [] if (len(vertices) > 0): polygon_points = [] for vertice in vertices: polygon_points.append( (points[vertice][0], points[vertice][1]) ) hull_polygon = Polygon(polygon_points, closed=True, alpha=0.5, color=Decorations.RGBColor0_1(current_object), zorder=4, lw=10) hull_polygon.set_gid( self.Data.PrettyCluster(current_object) ) hull_polygon.set_visible(False) self.Hulls[(current_object, current_frame)] = hull_polygon self.ScatterPlotAxes.add_artist( hull_polygon ) AnnotatedArtists.append( hull_polygon ) # Compute the arrows for the trajectories for current_object in range(FirstObject, LastObject+1): (r, g, b) = Decorations.RGBColor0_1(current_object) from_frame = 1 to_frame = from_frame + 1 while (to_frame <= NumberOfFrames): tail = (current_object, from_frame) head = (current_object, to_frame) if not tail in self.Trajectories: from_frame = to_frame to_frame = from_frame +1 continue else: if not head in self.Trajectories: to_frame = to_frame + 1 continue from_x = self.Trajectories[tail][0] from_y = self.Trajectories[tail][1] to_x = self.Trajectories[head][0] to_y = self.Trajectories[head][1] if self.GUI.in_3D(): from_z = self.Trajectories[tail][2] to_z = self.Trajectories[head][2] if ((to_x - from_x != 0) or (to_y - from_y != 0) or (self.GUI.in_3D() and (to_z - from_z != 0))): if (not (math.isnan(from_x) or math.isnan(from_y) or math.isnan(to_x) or math.isnan(to_y))): if (self.GUI.in_3D() and (not (math.isnan(from_z) or math.isnan(to_z)))): arrow = Arrow3D((from_x,to_x), (from_y, to_y), (from_z, to_z), arrowstyle='-|>', mutation_scale=20, color=(r, g, b), linewidth=1) else: arrow = FancyArrowPatch((from_x,from_y), (to_x,to_y), arrowstyle='-|>', mutation_scale=20, color=(r, g, b), linewidth=1) arrow.set_visible(False) self.Arrows[current_object].append(arrow) self.ScatterPlotAxes.add_artist(arrow) from_frame = to_frame to_frame = from_frame +1 self.Annotations = DataCursor(AnnotatedArtists)