def test_Polygon_close(): #: Github issue #1018 identified a bug in the Polygon handling #: of the closed attribute; the path was not getting closed #: when set_xy was used to set the vertices. # open set of vertices: xy = [[0, 0], [0, 1], [1, 1]] # closed set: xyclosed = xy + [[0, 0]] # start with open path and close it: p = Polygon(xy, closed=True) assert_array_equal(p.get_xy(), xyclosed) p.set_xy(xy) assert_array_equal(p.get_xy(), xyclosed) # start with closed path and open it: p = Polygon(xyclosed, closed=False) assert_array_equal(p.get_xy(), xy) p.set_xy(xyclosed) assert_array_equal(p.get_xy(), xy) # start with open path and leave it open: p = Polygon(xy, closed=False) assert_array_equal(p.get_xy(), xy) p.set_xy(xy) assert_array_equal(p.get_xy(), xy) # start with closed path and leave it closed: p = Polygon(xyclosed, closed=True) assert_array_equal(p.get_xy(), xyclosed) p.set_xy(xyclosed) assert_array_equal(p.get_xy(), xyclosed)
class HighLight(): def __init__(self): self.polygon = Polygon([[0, 0], [0, 0]], facecolor='lightyellow', edgecolor='green', linewidth=2) # dummy data for xs,ys def update_polygon(self, tri): if tri == -1: points = [(0, 0), (0, 0)] else: points = draggablePolygon.List[tri].sq.vertices # dps[tri].poly.set_edgecolor('green') # dps[tri].poly.set_color('red') self.polygon.set_xy(zip(*points)) self.polygon.set_zorder(tri + 1e6)
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 Polygon(object): def __init__(self, ax, xy, **kwargs): self._pol = MplPol(xy, kwargs) ax.add_patch(self._pol) @property def xy(self): return self._pol.get_xy() @xy.setter def xy(self, xy): self._pol.set_xy(xy) def remove(self): self._pol.remove() def anim_update(self, *args): pass
class Part: def __init__(self, cont, color, parent, alpha=0.8): self.parent = parent self.pts = cont self.poly = Polygon(cont, True, zorder=3, alpha=alpha, color=color) self.x = 0.0 self.y = 0.0 self.a = 0.0 @property def alpha(self): return self.poly.alpha @alpha.setter def alpha(self, value): self.poly.alpha = value def move(self, x=0, y=0, a=0): R''' move part to the pose (x,y,angle) wrt parent ''' self.x = x self.y = y self.a = a self.update() def update(self): px = self.parent.x py = self.parent.y pa = self.parent.a pR = rotmat(pa) wa = pa + self.a wx, wy = [px, py] + pR @ [self.x, self.y] pts = affine(self.pts, wx, wy, wa) self.poly.set_xy(pts) def patch(): return self.poly
class Roi(object): def __init__(self, xy, name, colour, linewidth=None): ''' A ROI is defined by its vertices (xy coords), a name, and a colour. Input: xy Coordinates of the ROI as a numpy array of shape (2, N). name Name of the ROI, string. colour Colour definition in any format acceptable to matplotlib, ie named (e.g. 'white') or RGBA format (e,g. (1.0, 1.0, 1.0, 1.0)). ''' super(Roi, self).__init__() self.polygon = Polygon(xy, lw=linewidth) self.polygon.set_facecolor('none') self.name = name self.set_colour(colour) def set_colour(self, colour): self.polygon.set_edgecolor(colour) def get_colour(self): return self.polygon.get_edgecolor() def set_name(self, name): self.name = name def get_name(self): return self.name def set_xy(self): return self.polygon.set_xy() def get_xy(self): return self.polygon.get_xy() def get_polygon(self): return self.polygon
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 BranchMaskCreator(MaskCreator): default_radius = 5. @MaskCreator.enabled.setter def enabled(self, e): """Extend the active setter of MaskCreator to also remove any artists if deactivated""" # call base class property setter MaskCreator.enabled.fset(self, e) # handle own derived stuff if self.artist is not None: self.artist.remove() self.artist = None self.x, self.y, self.r = [], [], [] self.update() def __init__(self, axes, canvas, update, notify, enabled=False): """ Arguments: axes, the axes where the interactive creation takes place canvas, the figure canvas, required to connec to signals update, a callable which will be called after adding a pixel to the current mask. notify, a callable that will get evoked with the coordinates of all pixels of a finished mask. enabled, should mask creation be enabled from the begininig (default False) """ self.artist = None # container for x,y and radius values self.x, self.y, self.r = [], [], [] super(BranchMaskCreator, self).__init__(axes=axes, canvas=canvas, update=update, notify=notify, enabled=enabled) def onclick(self, event): self.x.append(event.xdata) self.y.append(event.ydata) # reuse last radius for consecutive segments if len(self.r) > 0: self.r.append(self.r[-1]) else: self.r.append(BranchMaskCreator.default_radius) self.__update_artist() self.update() def __update_artist(self): # check if this is the first point of a branch if self.artist is None: self.artist = Circle([self.x[0], self.y[0]], radius=self.r[0], fill=False, lw=2, color='red') self.axes.add_artist(self.artist) elif len(self.x) == 0: self.artist.remove() self.artist = None elif len(self.x) == 1: self.artist.remove() self.artist = Circle([self.x[0], self.y[0]], radius=self.r[0], fill=False, lw=2, color='red') self.axes.add_artist(self.artist) # change from circle to polygon if more than 1 points are available elif len(self.x) == 2: self.artist.remove() branch = Branch(x=self.x, y=self.y, z=[0 for i in self.x], r=self.r) self.artist = Polygon(branch.outline, fill=False, color='red', lw=2) self.axes.add_artist(self.artist) else: assert (len(self.x) > 2) branch = Branch(x=self.x, y=self.y, z=[0 for i in self.x], r=self.r) self.artist.set_xy(branch.outline) def onkey(self, event): if self.artist is not None: if event.key == '+': self.r[-1] = self.r[-1] + 1 self.__update_artist() self.update() elif event.key == '-': self.r[-1] = self.r[-1] - 1 self.__update_artist() self.update() elif event.key == 'z': print event print dir(event) self.r = self.r[:-1] self.x = self.x[:-1] self.y = self.y[:-1] self.__update_artist() self.update() elif event.key == 'enter': self.artist.remove() self.update() self.artist = None if len(self.x) == 1: # shift by 0.5 to compensate for pixel offset in imshow mask = CircleMask( center=[self.x[0] + 0.5, self.y[0] + 0.5], radius=self.r[0]) else: import numpy dtype = [('x', float), ('y', float), ('z', float), ('radius', float)] x = numpy.array(self.x) + 0.5 y = numpy.array(self.y) + 0.5 z = [0 for i in self.x] r = self.r data = numpy.rec.fromarrays([x, y, z, r], dtype=dtype) # shift by 0.5 to compensate for pixel offset in imshow mask = BranchMask(data=data) self.x, self.y, self.r = [], [], [] self.notify(mask) self.enabled = False
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 PolygonInteractor(QtCore.QObject): """ Polygon Interactor Parameters ---------- axtmp : matplotlib axis matplotlib axis pntxy : """ showverts = True epsilon = 5 # max pixel distance to count as a vertex hit polyi_changed = QtCore.pyqtSignal(list) def __init__(self, axtmp, pntxy): QtCore.QObject.__init__(self) self.ax = axtmp self.poly = Polygon([(1, 1)], animated=True) self.ax.add_patch(self.poly) self.canvas = self.poly.figure.canvas self.poly.set_alpha(0.5) self.pntxy = pntxy self.ishist = True self.background = self.canvas.copy_from_bbox(self.ax.bbox) xtmp, ytmp = list(zip(*self.poly.xy)) self.line = Line2D(xtmp, ytmp, marker='o', markerfacecolor='r', color='y', animated=True) self.ax.add_line(self.line) self.poly.add_callback(self.poly_changed) self._ind = None # the active vert self.canvas.mpl_connect('button_press_event', self.button_press_callback) self.canvas.mpl_connect('button_release_event', self.button_release_callback) self.canvas.mpl_connect('motion_notify_event', self.motion_notify_callback) def draw_callback(self): """ Draw callback """ self.background = self.canvas.copy_from_bbox(self.ax.bbox) QtWidgets.QApplication.processEvents() self.canvas.restore_region(self.background) self.ax.draw_artist(self.poly) self.ax.draw_artist(self.line) self.canvas.update() def new_poly(self, npoly): """ New Polygon """ self.poly.set_xy(npoly) self.line.set_data(list(zip(*self.poly.xy))) self.canvas.draw() self.update_plots() def poly_changed(self, poly): """ Changed Polygon """ # this method is called whenever the polygon object is called # only copy the artist props to the line (except visibility) vis = self.line.get_visible() Artist.update_from(self.line, poly) self.line.set_visible(vis) # don't use the poly visibility state def get_ind_under_point(self, event): """get the index of vertex under point if within epsilon tolerance""" # display coords xytmp = np.asarray(self.poly.xy) xyt = self.poly.get_transform().transform(xytmp) xtt, ytt = xyt[:, 0], xyt[:, 1] dtt = np.sqrt((xtt - event.x) ** 2 + (ytt - event.y) ** 2) indseq = np.nonzero(np.equal(dtt, np.amin(dtt)))[0] ind = indseq[0] if dtt[ind] >= self.epsilon: ind = None return ind def button_press_callback(self, event): """whenever a mouse button is pressed""" if event.inaxes is None: return if event.button != 1: return self._ind = self.get_ind_under_point(event) if self._ind is None: xys = self.poly.get_transform().transform(self.poly.xy) ptmp = event.x, event.y # display coords if len(xys) == 1: self.poly.xy = np.array( [(event.xdata, event.ydata)] + [(event.xdata, event.ydata)]) self.line.set_data(list(zip(*self.poly.xy))) self.canvas.restore_region(self.background) self.ax.draw_artist(self.poly) self.ax.draw_artist(self.line) self.canvas.update() return dmin = -1 imin = -1 for i in range(len(xys) - 1): s0tmp = xys[i] s1tmp = xys[i + 1] dtmp = dist_point_to_segment(ptmp, s0tmp, s1tmp) if dmin == -1: dmin = dtmp imin = i elif dtmp < dmin: dmin = dtmp imin = i i = imin self.poly.xy = np.array(list(self.poly.xy[:i + 1]) + [(event.xdata, event.ydata)] + list(self.poly.xy[i + 1:])) self.line.set_data(list(zip(*self.poly.xy))) self.canvas.restore_region(self.background) self.ax.draw_artist(self.poly) self.ax.draw_artist(self.line) self.canvas.update() def button_release_callback(self, event): """Whenever a mouse button is released""" if event.button != 1: return self._ind = None self.update_plots() def update_plots(self): """ Update Plots """ polymask = Path(self.poly.xy).contains_points(self.pntxy) self.polyi_changed.emit(polymask.tolist()) def motion_notify_callback(self, event): """on mouse movement""" if self._ind is None: return if event.inaxes is None: return if event.button != 1: return xtmp, ytmp = event.xdata, event.ydata self.poly.xy[self._ind] = xtmp, ytmp if self._ind == 0: self.poly.xy[-1] = xtmp, ytmp self.line.set_data(list(zip(*self.poly.xy))) self.canvas.restore_region(self.background) self.ax.draw_artist(self.poly) self.ax.draw_artist(self.line) self.canvas.update()
class Gate(object): """Gate class implements gating using Matplotlib animation and events. Right click to add vertex. Left click and drag vertex to move. When vertices >= 3, polygonal gate will display. Double click within gate to extract gated events and zoom to gated region. """ def __init__(self, fcm, idxs, ax): self.fcm = fcm self.idxs = idxs ax.scatter(fcm[:, idxs[0]], fcm[:, idxs[1]], s=1, c='b', edgecolors='none') self.gate = None self.canvas = ax.figure.canvas self.ax = ax self.vertices = [] self.poly = None self.background = None self.t = time.time() self.double_click_t = 1.0 self.cid_press = self.canvas.mpl_connect('button_press_event', self.onclick) self.cid_draw = self.canvas.mpl_connect('draw_event', self.update_background) def add_vertex(self, vertex): # print vertex.center self.ax.add_patch(vertex) dv = DraggableVertex(vertex, self) dv.connect() self.vertices.append(dv) self.update() def update_background(self, event): self.background = self.canvas.copy_from_bbox(self.ax.bbox) def update(self): # print "updating" if len(self.vertices) >= 3: xy = numpy.array([v.circle.center for v in self.vertices]) # bug in matplotlib? patch is not closed without this xy = numpy.concatenate([xy, [xy[0]]]) if self.poly is None: self.poly = Polygon(xy, closed=True, alpha=0.5, facecolor='pink') self.ax.add_patch(self.poly) else: self.poly.set_xy(xy) if self.background is not None: self.canvas.restore_region(self.background) if self.poly is not None: self.ax.draw_artist(self.poly) for vertex in self.vertices: self.ax.draw_artist(vertex.circle) # print ">>>", self.ax.bbox self.canvas.blit(self.ax.bbox) def onclick(self, event): xmin, xmax, unused_ymin, unused_ymax = self.ax.axis() w = xmax - xmin if event.button == 3: vertex = Circle((event.xdata, event.ydata), radius=0.01 * w) self.add_vertex(vertex) # double left click triggers gating xy = numpy.array([v.circle.center for v in self.vertices]) xypoints = numpy.array([[event.xdata, event.ydata]]) if self.poly: if (event.button == 1 and points_inside_poly(xypoints, xy)): if (time.time() - self.t < self.double_click_t): self.zoom_to_gate(event) self.t = time.time() def zoom_to_gate(self, event): xy = numpy.array([v.circle.center for v in self.vertices]) gate = g(xy, self.idxs) gate.gate(self.fcm) self.gate = gate self.vertices = [] self.poly = None self.ax.patches = [] # get rid of old points del self.ax.collections[0] plt.close() def disconnect(self): 'disconnect all the stored connection ids' self.canvas.mpl_disconnect(self.cid_press) self.canvas.mpl_disconnect(self.cid_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 Blaschke3 : #Metodo para inicializar las variables def __init__(self,ax,fig) : self.polygon = [] self.cont = 0 self.polygon_exist = False self.num_points = 20 self.touched_circle = False self.list_circles = [] self.ax = ax self.fig = fig self.cid_press = fig.canvas.mpl_connect('button_press_event', self.on_press) self.cid_move = fig.canvas.mpl_connect('motion_notify_event', self.on_move) self.cid_release = fig.canvas.mpl_connect('button_release_event', self.on_release) #Metodo que se activa cuando se pulsa un punto def on_press(self, event): #Comprobamos si hemos pulsado en un punto antiguo para moverlo for circle in self.list_circles: contains, attr = circle.contains(event) if contains: self.touched_circle = circle self.exists_touched_circle = True self.pressed_event = event self.touched_x0, self.touched_y0 = circle.center return #Limpiamos los ejes y pintamos todos los puntos plt.cla() if self.cont==2: self.list_circles.remove(self.list_circles[0]) c = Circle((event.xdata,event.ydata),0.02) ax.add_patch(Circle((0,0),1,color='blue', fill = False)) self.list_circles.append(c) for circle in self.list_circles : self.ax.add_patch(circle) #Guardamos el nuevo punto (borrando el primero si ya habia dos) new_point = [event.xdata,event.ydata] if not(self.polygon_exist) : self.polygon.append(new_point) self.P = Polygon(self.polygon, closed = False,color = 'red', fill = False) self.polygon_exist = True else : if self.cont==2: self.polygon.remove(self.polygon[0]) self.polygon.append(new_point) self.P.set_xy(self.polygon) self.ax.add_patch(self.P) self.fig.canvas.draw() #Si a1 y a2 se encuentran dentro del disco unidad: if self.cont<2: self.cont=self.cont+1 if self.cont==2: a1 = self.polygon[0] a2 = self.polygon[1] if np.linalg.norm(a1)<=1 and np.linalg.norm(a2)<=1: self.calculate_Blaschke3(a1,a2) #Metodo que se activa cuando se mueve un punto def on_move(self,event) : if self.touched_circle and self.cont==2: dx = event.xdata - self.pressed_event.xdata dy = event.ydata - self.pressed_event.ydata x0, y0 = self.touched_circle.center self.touched_circle.center = self.touched_x0 + dx, self.touched_y0 + dy plt.cla() ax.add_patch(Circle((0,0),1,color='blue', fill = False)) for circle in self.list_circles : self.ax.add_patch(circle) self.polygon = [circle.center for circle in self.list_circles] self.P.set_xy(self.polygon) self.ax.add_patch(self.P) self.fig.canvas.draw() if self.cont==2: a1 = self.polygon[0] a2 = self.polygon[1] if np.linalg.norm(a1)<=1 and np.linalg.norm(a2)<=1: self.calculate_Blaschke3(a1,a2) #Metodo que se activa cuando se suelta un punto def on_release(self, event) : self.touched_circle = False #Funcion principal def calculate_Blaschke3(self, a1, a2): a1 = complex(a1[0],a1[1]) a2 = complex(a2[0],a2[1]) t = np.linspace(0,2*np.pi,self.num_points) #Para cada punto del disco unidad, calculamos sus tres imagenes inversas for interv in t: z = np.exp(interv*1j) #Resolvemos la ecuacion para calcular las tres raices a = 1 b = -(a1+a2+a1.conjugate()*a2.conjugate()*z) c = (a1*a2+a1.conjugate()*z+a2.conjugate()*z) d = -z solucion = np.roots([a, b, c, d]) sol1=complex(solucion[0]) sol2=complex(solucion[1]) sol3=complex(solucion[2]) #Dibujamos las 3 rectas plane=[] plane.append([sol1.real,sol1.imag]) plane.append([sol2.real,sol2.imag]) plane.append([sol3.real,sol3.imag]) Pdraw = Polygon(plane, closed = True,color = 'red', fill = False) ax.add_patch(Pdraw)
class PlotWidget(FigureCanvas): """a QtWidget and FigureCanvasAgg that displays the model plots""" def __init__(self, parent=None, name=None, width=5, height=4, dpi=100, bgcolor=None): self.fig = Figure(figsize=(width, height), dpi=dpi, facecolor=bgcolor, edgecolor=bgcolor) self.axes = self.fig.add_axes([0.125,0.1,0.6,0.8]) #self.fig.add_subplot(111) self.have_range = [] self.axes.set_xlabel('Time (years)') self.axes.set_ylabel( "Greenhouse Gas \nEmissions/Removals (t CO"+SUB_2+ "e / ha)", multialignment='center') self.axes.axhline(y=0.,ls=':',color='k') self.axes.text(0, 0,'Emission',va='bottom') self.axes.text(0, 0,'Removal',va='top') self.emission_patch = None self.removal_patch = None self.updateShading() self.totalsBox = self.fig.text(0.75,0.1,"") FigureCanvas.__init__(self, self.fig) self.setParent(parent) self.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) self.updateGeometry() self.plots = {} self.totals = {} def addPlot(self,data,plotID,name): # No support for ranges (uncertainties) yet plots = [] plots += self.axes.plot( np.array(range(len(data)))+1, # to make it start at year 1 data,color=COLOURS[plotID],label=name) totals = (name,np.sum(data)) self.axes.autoscale(enable=True) self.axes.relim() self.plots[plotID] = plots self.totals[plotID] = totals self.updateLegend() self.updateTotals() self.updateShading() self.draw() def updateShading(self): # update vertical limits xlim = self.axes.get_xlim() ylim = self.axes.get_ylim() ylim = (min(ylim[0],-1),max(ylim[1],1)) self.axes.set_ylim(ylim) upper = [(xlim[0],0),(xlim[1],0),(xlim[1],ylim[1]),(xlim[0],ylim[1])] lower = [(xlim[0],ylim[0]),(xlim[1],ylim[0]),(xlim[1],0),(xlim[0],0)] # shade positive and negative values if self.emission_patch == None: self.emission_patch = Polygon( upper, facecolor='r', alpha=0.25, fill=True, edgecolor=None, zorder=-1000) self.axes.add_patch(self.emission_patch) else: self.emission_patch.set_xy(upper) if self.removal_patch == None: self.removal_patch = Polygon( lower, facecolor='b', alpha=0.25, fill=True, edgecolor=None, zorder=-1000) self.axes.add_patch(self.removal_patch) else: self.removal_patch.set_xy(lower) #self.removal_patch = None def updateTotals(self): # No support for ranges (yet) # get model names (as keys) models = {} for c in self.totals: models[self.totals[c][0]] = self.totals[c][1:] ms = sorted(models.keys()) years = self.axes.dataLim.get_points()[1,0] outstr = "Total Emissions/Removals\nover %d years " % cfg.N_ACCT outstr += "(t CO"+SUB_2+"e / ha):\n" for m in ms: outstr += '%s: %.1f\n' % (m, models[m][0]) # Figure out total of project - baseline for each project if len(self.totals)>1 and 0 in self.totals: outstr+="\nNet impact (t CO"+SUB_2+"e / ha):\n" for c in self.totals: if c == 0: continue outstr += "%s: %.1f\n" % ( self.totals[c][0], self.totals[c][1]-self.totals[0][1]) self.totalsBox.set_text(outstr) def removePlot(self,plotID): if plotID in self.plots: for p in self.plots[plotID]: p.remove() self.draw() del self.totals[plotID] del self.plots[plotID] if plotID in self.have_range: self.have_range.remove(plotID) self.updateLegend() self.updateTotals() def updateLegend(self): if len(self.plots.keys())>0: handles, labels = self.axes.get_legend_handles_labels() if len(self.have_range) > 0: l = Line2D([0,1],[0,1],linestyle="--",color='k') handles.append(l) labels.append("range") self.axes.legend(handles,labels,bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.) else: self.axes.legend_ = None def saveFigure(self,fname): self.fig.savefig(fname) def sizeHint(self): w = self.fig.get_figwidth() h = self.fig.get_figheight() return QtCore.QSize(w, h) def minimumSizeHint(self): return QtCore.QSize(10, 10)
class FieldAnimation(FieldPlotter): def __init__(self, fields, ax=None, dates=None, facecolors=None, alphas=None, edgecolors=None, inclcax=False): """ """ super().__init__(ax=ax, inclcax=inclcax) self.set_fields(fields) self.set_dates(dates) self.set_properties(facecolors=facecolors, alphas=alphas, edgecolors=edgecolors) # ================= # # Methods # # ================= # def set_dates(self, dates): """ """ self._dates = np.atleast_1d(dates) if dates is not None else None def set_fields(self, fields): """ """ self._fields = fields self._unique_fields = np.unique(self._fields) self._field_vertices = { i: v for i, v in zip(self._unique_fields, self.get_field_vertices(self._unique_fields)) } def set_properties(self, facecolors=None, edgecolors=None, alphas=None): """ """ self._display_prop = {} self._set_prop_("facecolor", facecolors, "0.7") self._set_prop_("edgecolor", edgecolors, "None") self._set_prop_("alpha", alphas, 1) def _set_prop_(self, key, value, default=None): """ """ if not hasattr(self, "_display_prop"): self._display_prop = {} if value is None: value = default if len(np.atleast_1d(value)) == 1: self.display_prop[key] = np.atleast_1d(value) self.display_prop[f"unique_{key}"] = True else: self.display_prop[key] = value self.display_prop[f"unique_{key}"] = False # ---------- # # SETUP # # ---------- # def reset(self): """ """ self.intpoly_ = Polygon(self.field_vertices[self.fields[0]], facecolor=self.display_prop["facecolor"][0], edgecolor=self.display_prop["edgecolor"][0], alpha=self.display_prop["alpha"][0]) if self._dates is not None: self.inttext_ = self.fig.text(0.01, 0.99, self._dates[0], va="top", ha="left", weight="bold") p_ = self.ax.add_patch(self.intpoly_) return self.intpoly_ # ---------- # # Animate # # ---------- # def update_field_to(self, i): """ """ try: self.intpoly_.set_xy(self.field_vertices[self.fields[i]]) if self.dates is not None and len(self.dates) > 1: self.inttext_.set_text(self.dates[i]) except: print(f"FAILES for i={i}") for key in ["facecolor", "edgecolor", "alpha"]: if not self.display_prop[f"unique_{key}"]: getattr(self.intpoly_, f"set_{key}")(self.display_prop[key][i]) return self.intpoly_ def launch(self, interval=5, repeat=False, blit=True, savefile=None): """ """ from matplotlib import animation self.anim = animation.FuncAnimation(self.fig, self.update_field_to, init_func=self.reset, frames=self.nfields, interval=interval, repeat=repeat, blit=blit) # ================= # # Properties # # ================= # @property def fields(self): """ Fields that should be shown """ return self._fields @property def dates(self): """ Observation dates if any """ return self._dates @property def nfields(self): """ size of self.fields """ return len(self.fields) @property def field_vertices(self): """ vertices of the fields """ return self._field_vertices @property def display_prop(self): """ """ return self._display_prop
class PolygonInteractor(QtCore.QObject): """ Polygon Interactor Parameters ---------- axtmp : matplotlib axis matplotlib axis pntxy : """ showverts = True epsilon = 5 # max pixel distance to count as a vertex hit polyi_changed = QtCore.pyqtSignal(list) def __init__(self, axtmp, pntxy): QtCore.QObject.__init__(self) self.ax = axtmp self.poly = Polygon([(1, 1)], animated=True) self.ax.add_patch(self.poly) self.canvas = self.poly.figure.canvas self.poly.set_alpha(0.5) self.pntxy = pntxy self.ishist = True self.background = self.canvas.copy_from_bbox(self.ax.bbox) xtmp, ytmp = list(zip(*self.poly.xy)) self.line = Line2D(xtmp, ytmp, marker='o', markerfacecolor='r', color='y', animated=True) self.ax.add_line(self.line) self.poly.add_callback(self.poly_changed) self._ind = None # the active vert self.canvas.mpl_connect('button_press_event', self.button_press_callback) self.canvas.mpl_connect('button_release_event', self.button_release_callback) self.canvas.mpl_connect('motion_notify_event', self.motion_notify_callback) def draw_callback(self): """ Draw callback """ self.background = self.canvas.copy_from_bbox(self.ax.bbox) QtWidgets.QApplication.processEvents() self.canvas.restore_region(self.background) self.ax.draw_artist(self.poly) self.ax.draw_artist(self.line) self.canvas.update() def new_poly(self, npoly): """ New Polygon """ self.poly.set_xy(npoly) self.line.set_data(list(zip(*self.poly.xy))) self.canvas.draw() self.update_plots() def poly_changed(self, poly): """ Changed Polygon """ # this method is called whenever the polygon object is called # only copy the artist props to the line (except visibility) vis = self.line.get_visible() Artist.update_from(self.line, poly) self.line.set_visible(vis) # don't use the poly visibility state def get_ind_under_point(self, event): """get the index of vertex under point if within epsilon tolerance""" # display coords xytmp = np.asarray(self.poly.xy) xyt = self.poly.get_transform().transform(xytmp) xtt, ytt = xyt[:, 0], xyt[:, 1] dtt = np.sqrt((xtt - event.x) ** 2 + (ytt - event.y) ** 2) indseq = np.nonzero(np.equal(dtt, np.amin(dtt)))[0] ind = indseq[0] if dtt[ind] >= self.epsilon: ind = None return ind def button_press_callback(self, event): """whenever a mouse button is pressed""" if event.inaxes is None: return if event.button != 1: return self._ind = self.get_ind_under_point(event) if self._ind is None: xys = self.poly.get_transform().transform(self.poly.xy) ptmp = self.poly.get_transform().transform([event.xdata, event.ydata]) # ptmp = event.x, event.y # display coords if len(xys) == 1: self.poly.xy = np.array( [(event.xdata, event.ydata)] + [(event.xdata, event.ydata)]) self.line.set_data(list(zip(*self.poly.xy))) self.canvas.restore_region(self.background) self.ax.draw_artist(self.poly) self.ax.draw_artist(self.line) self.canvas.update() return dmin = -1 imin = -1 for i in range(len(xys) - 1): s0tmp = xys[i] s1tmp = xys[i + 1] dtmp = dist_point_to_segment(ptmp, s0tmp, s1tmp) if dmin == -1: dmin = dtmp imin = i elif dtmp < dmin: dmin = dtmp imin = i i = imin # breakpoint() self.poly.xy = np.array(list(self.poly.xy[:i + 1]) + [(event.xdata, event.ydata)] + list(self.poly.xy[i + 1:])) self.line.set_data(list(zip(*self.poly.xy))) self.canvas.restore_region(self.background) self.ax.draw_artist(self.poly) self.ax.draw_artist(self.line) self.canvas.update() def button_release_callback(self, event): """Whenever a mouse button is released""" if event.button != 1: return self._ind = None self.update_plots() def update_plots(self): """ Update Plots """ polymask = Path(self.poly.xy).contains_points(self.pntxy) self.polyi_changed.emit(polymask.tolist()) def motion_notify_callback(self, event): """on mouse movement""" if self._ind is None: return if event.inaxes is None: return if event.button != 1: return xtmp, ytmp = event.xdata, event.ydata self.poly.xy[self._ind] = xtmp, ytmp if self._ind == 0: self.poly.xy[-1] = xtmp, ytmp self.line.set_data(list(zip(*self.poly.xy))) self.canvas.restore_region(self.background) self.ax.draw_artist(self.poly) self.ax.draw_artist(self.line) self.canvas.update()
# read robot orientation returnCode, orientation = vrep.simxGetObjectOrientation( clientID, robotHandle, stageHandle, vrep.simx_opmode_buffer) if returnCode == vrep.simx_error_noerror: (_, _, angle) = orientation robot.update_angle(angle) # read depth data returnCode, resolution, data = vrep.simxGetVisionSensorDepthBuffer( clientID, sensorHandle, vrep.simx_opmode_buffer) if returnCode == vrep.simx_error_noerror: # get positions from rays walls = robot.gen_wall_position(data, stageWidth, stageHeight) if len(walls) == 0: continue robotVisionToken.set_xy(list(map(grid.position, walls))) # update grid grid.update_grid(walls, sensorRange) # update image grid.draw() # update motion panning state motion.update() # delay time time.sleep(0.05) except KeyboardInterrupt: print("KeyBoardInterrupt")
class Gate(object): """Gate class implements gating using Matplotlib animation and events. Right click to add vertex. Left click and drag vertex to move. When vertices >= 3, polygonal gate will display. Double click within gate to extract gated events and zoom to gated region. """ def __init__(self, fcm, idxs, ax): self.fcm = fcm self.idxs = idxs ax.scatter(fcm[:, idxs[0]], fcm[:, idxs[1]], s=1, c='b', edgecolors='none') self.gate = None self.canvas = ax.figure.canvas self.ax = ax self.vertices = [] self.poly = None self.background = None self.t = time.time() self.double_click_t = 1.0 self.cid_press = self.canvas.mpl_connect( 'button_press_event', self.onclick) self.cid_draw = self.canvas.mpl_connect( 'draw_event', self.update_background) def add_vertex(self, vertex): # print vertex.center self.ax.add_patch(vertex) dv = DraggableVertex(vertex, self) dv.connect() self.vertices.append(dv) self.update() def update_background(self, event): self.background = self.canvas.copy_from_bbox(self.ax.bbox) def update(self): # print "updating" if len(self.vertices) >= 3: xy = numpy.array([v.circle.center for v in self.vertices]) # bug in matplotlib? patch is not closed without this xy = numpy.concatenate([xy, [xy[0]]]) if self.poly is None: self.poly = Polygon(xy, closed=True, alpha=0.5, facecolor='pink') self.ax.add_patch(self.poly) else: self.poly.set_xy(xy) if self.background is not None: self.canvas.restore_region(self.background) if self.poly is not None: self.ax.draw_artist(self.poly) for vertex in self.vertices: self.ax.draw_artist(vertex.circle) # print ">>>", self.ax.bbox self.canvas.blit(self.ax.bbox) def onclick(self, event): xmin, xmax, unused_ymin, unused_ymax = self.ax.axis() w = xmax - xmin if event.button == 3: vertex = Circle((event.xdata, event.ydata), radius=0.01 * w) self.add_vertex(vertex) # double left click triggers gating xy = numpy.array([v.circle.center for v in self.vertices]) xypoints = numpy.array([[event.xdata, event.ydata]]) if self.poly: if (event.button == 1 and points_inside_poly(xypoints, xy)): if (time.time() - self.t < self.double_click_t): self.zoom_to_gate(event) self.t = time.time() def zoom_to_gate(self, event): xy = numpy.array([v.circle.center for v in self.vertices]) gate = g(xy, self.idxs) gate.gate(self.fcm) self.gate = gate self.vertices = [] self.poly = None self.ax.patches = [] # get rid of old points del self.ax.collections[0] plt.close() def disconnect(self): 'disconnect all the stored connection ids' self.canvas.mpl_disconnect(self.cid_press) self.canvas.mpl_disconnect(self.cid_draw)
class ChannelBody(object): ''' when the channel is avulsed, convert it to a ChannelBody type ''' def __init__(self, channel): nState = len(channel.stateList) # shapeState = np.shape(channel.stateList) stateBoxes = [] QwList = np.zeros((nState, 1)) sigList = np.zeros((nState, 1)) for s, i in zip(iter(channel.stateList), np.arange(nState)): stateBoxes.append(self.rect2box(s.ll, s.Bc, s.H)) # different way to do this? # instead go straight polygon to union? QwList[i] = s.Qw sigList[i] = s.sig self.y_upper = channel.stateList[-1].y_upper self.conversionFlag = "same" # option to select how to convert states to bodies if self.conversionFlag == "same": # same method for all stateSeriesConvexHull = [] for i, j in zip(stateBoxes[1:], stateBoxes[:-1]): seriesUnionTemp = so.cascaded_union([i, j]) stateSeriesConvexHull.append(seriesUnionTemp.convex_hull) stateUnion = so.cascaded_union(stateSeriesConvexHull) self.polygonAsArray = np.asarray(stateUnion.exterior) elif self.conversionFlag == "diff": # different methods for polygon and multipolygon stateUnion = so.cascaded_union(stateBoxes) # try so.cascaded_union(stateBoxes[::2]) for speed? # if type is polygon uniontype = stateUnion.geom_type if uniontype == 'Polygon': self.polygonAsArray = np.asarray(stateUnion.exterior) elif uniontype == 'MultiPolygon': stateSeriesConvexHull = [] for i, j in zip(stateBoxes[1:], stateBoxes[:-1]): seriesUnionTemp = so.cascaded_union([i, j]) stateSeriesConvexHull.append(seriesUnionTemp.convex_hull) stateUnion = so.cascaded_union(stateSeriesConvexHull) self.polygonAsArray = np.asarray(stateUnion.exterior) else: raise ValueError("invalid conversionFlag in ChannelBody") self.polygonXs = self.polygonAsArray[:,0] self.polygonYs = self.polygonAsArray[:,1] self.patch = Polygon(self.polygonAsArray) # get all the "means" of variables for coloring values self.age = channel.age self.Qw = QwList.mean() self.avul_num = channel.avul_num self.sig = sigList.mean() def subside(self, dz): # subside method to be called each iteration self.polygonYs -= dz # self.y_upper = self.polygonYs.max() xsys = np.column_stack((self.polygonXs, self.polygonYs)) self.patch.set_xy(xsys) def get_patch(self): return self.patch def rect2box(self, ll, Bc, H): box = sg.box(ll[0], ll[1], ll[0] + Bc, ll[1] + H) return box
class CreatePolygon: def __init__(self): self.circle_list = [] self.x0 = None self.y0 = None self.fig = plt.figure() self.ax = plt.subplot(111) self.ax.set_xlim(-20, 20) self.ax.set_ylim(-20, 20) self.ax.set_title( 'Bot' + u'ó' + 'n izq. para poner puntos y moverlos, derecho para cerrar y terminar' ) self.cidpress = self.fig.canvas.mpl_connect('button_press_event', self.on_press) self.cidrelease = self.fig.canvas.mpl_connect('button_release_event', self.on_release) self.cidmove = self.fig.canvas.mpl_connect('motion_notify_event', self.on_move) self.press_event = None self.current_circle = None self.points = None self.poly = None def on_press(self, event): if event.button == 3: #Cerrar y desconectar self.poly.set_closed(True) self.fig.canvas.draw() self.fig.canvas.mpl_disconnect(self.cidpress) self.fig.canvas.mpl_disconnect(self.cidrelease) self.fig.canvas.mpl_disconnect(self.cidmove) self.points = [list(circle.center) for circle in self.circle_list] return self.points x0, y0 = int(event.xdata), int(event.ydata) #Buscamos el circulo que contiene al evento, si lo hay for circle in self.circle_list: contains, attr = circle.contains(event) if contains: self.press_event = event self.current_circle = circle self.x0, self.y0 = self.current_circle.center return #Si no hemos encontrado ningun circulo: c = Circle((x0, y0), 0.5) self.ax.add_patch(c) self.circle_list.append(c) self.current_circle = None num_circles = len(self.circle_list) if num_circles == 1: self.fig.canvas.draw() else: self.points = [list(circle.center) for circle in self.circle_list] if self.poly == None: self.poly = Polygon(np.array(self.points), fill=False, closed=False) self.ax.add_patch(self.poly) self.fig.canvas.draw() else: self.poly.set_xy(np.array(self.points)) print self.poly.get_xy() self.fig.canvas.draw() self.fig.canvas.draw() def on_release(self, event): self.press_event = None self.current_circle = None def on_move(self, event): if (self.press_event is None or event.inaxes != self.press_event.inaxes or self.current_circle == None): return dx = event.xdata - self.press_event.xdata dy = event.ydata - self.press_event.ydata self.current_circle.center = int(self.x0 + dx), int(self.y0 + dy) self.points = [list(circle.center) for circle in self.circle_list] self.poly.set_xy(np.array(self.points)) self.fig.canvas.draw()