def custom_plot(image, box=None, polygons=None): #target.extra_fields['masks'].polygons è una lista in cui ogni elemento ha un .polygons # che è una lista di tensor fig, ax = plt.subplots(1) ax.imshow(image) if box is not None: for bb in box: rect = Rectangle((int(bb[0]), int(bb[1])), int(bb[2]), int(bb[3]), linewidth=1, edgecolor='r', facecolor='none') ax.add_patch(rect) if polygons is not None: patches = [] for p in polygons: for p2 in p.polygons: polygon = Polygon(p2.numpy().reshape((-1, 2)), False) patches.append(polygon) p = PatchCollection(patches, alpha=0.4) p.set_linewidth(2.0) p.set_edgecolor('r') ax.add_collection(p) plt.show()
def create_pixels(lons,lats,widths,heights,alphas,color,label): """ Plot of pixels using centers (lons,lats), with sizes (widhts,heights), angle alphas, and color color. :param lons: array of longitude coordinates at the center of the pixels :param lats: array of latitude coordinates at the center of the pixels :param widths: array of widhts of the pixels :param heights: array of heights of the pixels :param alphas: array of angles of the pixels :param color: tuple with RGB color values :return col: collection of rectangles with the pixels Developed in Python 2.7.15 :: Anaconda 4.5.10, on MACINTOSH. Angel Farguell ([email protected]) 2018-12-28 """ # Create pixels pixels=[] for x, y, h, w, a in zip(lons, lats, heights, widths, alphas): xpos = x - w/2 # The x position will be half the width from the center ypos = y - h/2 # same for the y position, but with height rect = Rectangle( (xpos, ypos), w, h, a) # Create a rectangle pixels.append(rect) # Add the rectangle patch to our list # Create a collection from the rectangles col = PatchCollection(pixels) # set the alpha for all rectangles col.set_alpha(0.5) # Set the colors using the colormap col.set_facecolor( [color]*len(lons) ) # No lines col.set_linewidth( 0 ) return col
def get_annotations(tiles_w, image_size, indices, coordinates): patches = [] colors = [] for index in range(canvas.shape[0]): x = index % tiles_w y = int(np.floor(index / tiles_w)) tile = int(indices[index]) if tile == -1: continue else: (lat, lon) = coordinates[tile] if np.isnan(lat) or np.isnan(lon): continue fc = lonlat2rgba(lon, lat) rect = mpatches.Rectangle((x * image_size, y * image_size), image_size, image_size) patches.append(rect) colors.append(fc) #image[((y + 1) * image_size, x * image_size):(x + 1) * image_size] = canvas[index] #colors = 100 * np.random.rand(len(patches)) collection = PatchCollection(patches, alpha=0.35) collection.set_facecolors(colors) collection.set_edgecolors(colors) collection.set_linewidth(0.1) #collection.set_array(np.array(colors)) return collection
def draw(self, ax, colour='k', alpha=1., linestyle='-', linewidth=1., markers=None, facecolor='none', dashes=(1, 1), zorder=0): """ Draw the polygon on ax """ # Add the last point ptstoplot = self.verts.tolist() ptstoplot.append(ptstoplot[0]) ptstoplot = np.array(ptstoplot) if facecolor == 'none': try: if linestyle == '--': ax.plot(ptstoplot[:, 0], ptstoplot[:, 1], c=colour, alpha=alpha, ls=linestyle, dashes=dashes, lw=linewidth, marker=markers, zorder=zorder) else: ax.plot(ptstoplot[:, 0], ptstoplot[:, 1], c=colour, alpha=alpha, ls=linestyle, lw=linewidth, marker=markers, zorder=zorder) except IndexError: pass else: patches = [] filled_pol = mp.Polygon(self.verts) patches.append(filled_pol) collection = PatchCollection(patches, facecolors=facecolor) ax.add_collection(collection) collection.set_alpha(alpha) collection.set_edgecolor(colour) collection.set_linewidth(linewidth) collection.set_linestyle(linestyle)
def mark_pixel(pixels, color='g', ax=None, linewidth=None): ''' surrounds pixels given by pixels with a border ''' pixel_x, pixel_y = get_pixel_coords() if ax is None: ax = plt.gca() patches = [] for xy in zip(pixel_x[pixels], pixel_y[pixels]): patches.append( RegularPolygon( xy=xy, numVertices=6, radius=9.5 / np.sqrt(3), orientation=0., # in radians fill=False, )) if linewidth is None: linewidth = calc_linewidth(ax=ax) collection = PatchCollection(patches, picker=0) collection.set_linewidth(linewidth) collection.set_edgecolors(color) collection.set_facecolor('none') ax.add_collection(collection) plt.draw_if_interactive() return collection
def add_circles(self, ax, centers, radis): circles = [] for c, r in zip(centers, radis): circles.append(patches.Circle(tuple(c), r)) patch_collection = PatchCollection(circles) patch_collection.set_facecolor("none") patch_collection.set_edgecolor("blue") patch_collection.set_linewidth(1.5) patch_collection.set_linestyle("dashed") ax.add_collection(patch_collection) print "added %d circles" % len(circles)
def plotpatchcollection(self, mypatches, mycolors=[], mylw=[]): self.canvas.figure.clf() ax = self.canvas.figure.subplots() p = PatchCollection(mypatches) # , alpha=0.4) p.set_facecolor(tuple(mycolors)) p.set_linewidth(mylw) ax.add_collection(p) ax.autoscale(enable=True, axis="both", tight=None) self.canvas.draw()
def get_mpas_patch_collection(nVertices, vertexDegree, interiorVertex, cellsOnVertex, xCell, yCell, mpasArray, cmap, vmin, vmax, limitPatches=False, rasterizePatches=False): patches = [] colours = [] minval = 1.0e30 maxval = -1.0e30 nPatches = 0 for iVertex in range(0, nVertices): if (interiorVertex[iVertex] == 1 and (math.fabs(mpasArray[iVertex]) > 1e-3 or not limitPatches)): polygonVertices = [] for iVertexDegree in range(0, vertexDegree): iCell = cellsOnVertex[iVertex, iVertexDegree] - 1 polygonVertices.append((xCell[iCell], yCell[iCell])) polygon = Polygon(polygonVertices) patches.append(polygon) colours.append(mpasArray[iVertex]) minval = min(minval, mpasArray[iVertex]) maxval = max(maxval, mpasArray[iVertex]) nPatches = nPatches + 1 print("nPatches: ", nPatches, limitPatches) patchCollection = PatchCollection(patches, cmap=cmap, rasterized=rasterizePatches) patchCollection.set_array(np.array(colours)) patchCollection.set_linewidth(0) patchCollection.set_clim(vmin=vmin, vmax=vmax) return patchCollection, minval, maxval
def draw_bboxes(bboxes, ax=None, color='red', linewidth=1, **kw): if ax is None: ax = plt.gca() patches = [ mpatches.Rectangle((i[1], i[0]), i[3] - i[1], i[2] - i[0]) for i in bboxes ] boxcoll = PatchCollection(patches, **kw) boxcoll.set_facecolor('none') boxcoll.set_edgecolor(color) boxcoll.set_linewidth(linewidth) ax.collections = [] ax.add_collection(boxcoll)
def get_shape_collections(data: Dict): shapes = [] for points in data.values(): shapes.append( Polygon(np.array([points['lons'], points['lats']]).T, closed=True)) collection = PatchCollection(shapes) collection.set_facecolor('#eeeeee') collection.set_edgecolor('black') collection.set_linewidth(0.2) return collection
def VoronoiPlot(points: Sequence, values: Sequence, vmin: float = None, vmax: float = None, cmap=None): """ plot the voronoi regions of the poins with the given colormap """ from matplotlib.patches import Polygon from matplotlib.collections import PatchCollection from scipy.spatial import Voronoi, voronoi_plot_2d from matplotlib import cm if cmap is None: cmap = cm.get_cmap('viridis') vor = Voronoi(points) # %% patches = [] dist_list = [] excluded_indices = [] for index, p in enumerate(points): # print(index) reg = vor.regions[vor.point_region[index]] if -1 in reg: # plt.plot(p[0], p[1], 'ok', alpha=0.3, ms=1) excluded_indices.append(index) continue distances = np.linalg.norm(np.array([vor.vertices[i] for i in reg]) - p, axis=1) if np.max(distances) > 2: # plt.plot(p[0], p[1], 'ok', alpha=0.3, ms=1) excluded_indices.append(index) continue region = np.array([vor.vertices[i] for i in reg]) polygon = Polygon(region, True) patches.append(polygon) dists = values[index] dist_list.append(dists) # plt.plot(p[0], p[1], 'ok', alpha=0.3, ms=1) p = PatchCollection(patches, cmap=cmap) p.set_clim([vmin, vmax]) p.set_array(np.array(dist_list)) p.set_linewidth(10) plt.gca().add_collection(p) plt.xticks([]) plt.yticks([]) return p, excluded_indices
def zoneLines(self, edgecolour='black'): #was 'red' """ Set boundary colour for defined ESRI shapes edgecolour -- HTML colour name for boundary """ pc2 = PatchCollection(self.patches, match_original=True) pc2.set_facecolor('none') pc2.set_edgecolor(edgecolour) pc2.set_alpha(0.5) #5.0 pc2.set_linewidth(0.5) pc2.set_zorder(25) # 500 sq2 = self.ax.add_collection(pc2)
def plot_trajectory_ellipse(frame, varx="attr_VARX", vary="attr_VARY", covxy="attr_COVXY", opacity_factor=1): """ Draw the trajectory and uncertainty ellipses around teach point. 1) Scatter of points 2) Trajectory lines 3) Ellipses :param frame: Trajectory :param opacity_factor: all opacity values are multiplied by this. Useful when used to plot multiple Trajectories in an overlay plot. :return: axis """ ellipses = [] segments = [] start_point = None for i, pnt in frame.iterrows(): # The ellipse U, s, V = np.linalg.svd(np.array([[pnt[varx], pnt[covxy]], [pnt[covxy], pnt[vary]]]), full_matrices=True) w, h = s**.5 theta = np.arctan(V[1][0]/V[0][0]) # == np.arccos(-V[0][0]) ellipse = {"xy":pnt[list(frame.geo_cols)].values, "width":w, "height":h, "angle":theta} ellipses.append(Ellipse(**ellipse)) # The line segment x, y = pnt[list(frame.geo_cols)][:2] if start_point: segments.append([start_point, (x, y)]) start_point = (x, y) ax = plt.gca() ellipses = PatchCollection(ellipses) ellipses.set_facecolor('none') ellipses.set_color("green") ellipses.set_linewidth(2) ellipses.set_alpha(.4*opacity_factor) ax.add_collection(ellipses) frame.plot(kind="scatter", x=frame.geo_cols[0], y=frame.geo_cols[1], marker=".", ax=plt.gca(), alpha=opacity_factor) lines = LineCollection(segments) lines.set_color("gray") lines.set_linewidth(1) lines.set_alpha(.2*opacity_factor) ax.add_collection(lines) return ax
def get_mpas_patch_collection(nVertices, vertexDegree, cellsOnVertex, xCell, yCell, zCell, latVertex, mpasArray, cmap, vmin, vmax, minX, maxX, minY, maxY): minval = 1.0e30 maxval = -1.0e30 patches = [] colours = [] for iVertex in range(0, nVertices): if (math.fabs(latVertex[iVertex]) > math.radians(20.0)): useVertex = False polygonVertices = [] for iCellOnVertex in range(0, vertexDegree[iVertex]): iCell = cellsOnVertex[iVertex, iCellOnVertex] x, y, z = ortho_projection(xCell[iCell], yCell[iCell], zCell[iCell]) if (x >= minX and x <= maxX and \ y >= minY and y <= maxY and \ z > 0.0): useVertex = True polygonVertices.append((x, y)) # create patch and add to collection if (useVertex): polygon = Polygon(polygonVertices) patches.append(polygon) colours.append(mpasArray[iVertex]) minval = min(minval, mpasArray[iVertex]) maxval = max(maxval, mpasArray[iVertex]) patchCollection = PatchCollection(patches, cmap=cmap, rasterized=True) patchCollection.set_array(np.array(colours)) patchCollection.set_linewidth(0) patchCollection.set_clim(vmin=vmin, vmax=vmax) return patchCollection, minval, maxval
def zoneColour(self, colours): """ Set display colours for defined ESRI shapes colours -- list containing HTML colour names """ self.colours = colours if not (isinstance(self.colours, list)): raise Exception('Invalid list of zone colours') pc = PatchCollection(self.patches, match_original=True) pc.set_facecolor(self.colours) pc.set_edgecolor('none') pc.set_alpha(0.5) pc.set_linewidth(0.5) pc.set_zorder(20) sq = self.ax.add_collection(pc)
def get_mpas_patch_collection(nVertices, vertexDegree, cellsOnVertex, xCell, yCell, zCell, latVertex, mpasArray, cmap, vmin, vmax, minX, maxX, minY, maxY): patches = [] colours = [] minval = 1.0e30 maxval = -1.0e30 for iVertex in range(0, nVertices): if (latVertex[iVertex] > math.radians(20.0)): polygonVertices = [] useVertex = False for iCellOnVertex in range(0, vertexDegree[iVertex]): iCell = cellsOnVertex[iVertex, iCellOnVertex] polygonVertices.append((xCell[iCell], yCell[iCell])) if (xCell[iCell] >= minX and xCell[iCell] <= maxX and \ yCell[iCell] >= minY and yCell[iCell] <= maxY): useVertex = True if (useVertex): polygon = Polygon(polygonVertices) patches.append(polygon) colours.append(mpasArray[iVertex]) minval = min(minval, mpasArray[iVertex]) maxval = max(maxval, mpasArray[iVertex]) patchCollection = PatchCollection(patches, cmap=cmap, rasterized=True) patchCollection.set_array(np.array(colours)) patchCollection.set_linewidth(0) patchCollection.set_clim(vmin=vmin, vmax=vmax) return patchCollection, minval, maxval
def _render_matplotlib(vertices, faces, face_color, borders, new_figure): """ Render the data in matplotlib: This is segmented to allow for openGL renderer Input: vertices (np.ndarray) Array of vertices faces (nd.array) Array of Faces face_color (nd.array) RGBA array of color and alpha of all vertices new_figure (bool) Create new Figure or render in currrent axis? """ patches = [] for i in range(faces.shape[0]): polygon = Polygon(vertices[faces[i],0:2], True) patches.append(polygon) p = PatchCollection(patches) p.set_facecolor(face_color) p.set_linewidth(0.0) # Get the current axis and plot it if new_figure: fig = plt.figure(figsize=(7,7)) ax = plt.gca() ax.add_collection(p) xrang = [np.nanmin(vertices[:,0]),np.nanmax(vertices[:,0])] yrang = [np.nanmin(vertices[:,1]),np.nanmax(vertices[:,1])] ax.set_xlim(xrang[0],xrang[1]) ax.set_ylim(yrang[0],yrang[1]) ax.axis('equal') ax.axis('off') if borders is not None: ax.plot(borders[:,0],borders[:,1],color='k', marker='.', linestyle=None, markersize=2,linewidth=0) return ax
def get_mpas_patch_collection(nCells, nEdgesOnCell, verticesOnCell, xVertex, yVertex, zVertex, mpasArray, cmap): patches = [] colours = [] minval = 1.0e30 maxval = -1.0e30 for iCell in range(0, nCells): polygonVertices = [] lUse = True for iVertexOnCell in range(0, nEdgesOnCell[iCell]): iVertex = verticesOnCell[iCell, iVertexOnCell] - 1 polygonVertices.append((xVertex[iVertex], zVertex[iVertex])) if (yVertex[iVertex] < 0.0): lUse = False if (lUse): polygon = Polygon(polygonVertices) patches.append(polygon) colours.append(mpasArray[iCell]) minval = min(minval, mpasArray[iCell]) maxval = max(maxval, mpasArray[iCell]) patchCollection = PatchCollection(patches, cmap=cmap, rasterized=False) patchCollection.set_array(np.array(colours)) patchCollection.set_linewidth(0) patchCollection.set_clim(vmin=0.0, vmax=1.0) return patchCollection, minval, maxval
def draw_map(map: GeographicalMap, mode='random', data=None): fig, ax = plt.subplots(figsize=(18, 10)) ax.set_xlim(map.xmin, map.xmax) ax.set_ylim(map.ymin, map.ymax) patches = PatchCollection( [matplotlib.patches.Polygon(p, fill=False) for p in map.polygons]) to_line = lambda e: map.centroids[(e.v1, e.v2), :] land_edges = [to_line(e) for e in map.edges.values() if e.type == 'land'] air_edges = [to_line(e) for e in map.edges.values() if e.type == 'air'] land_edges = LineCollection(land_edges, linewidths=0.3, colors='red') air_edges = LineCollection(air_edges, linewidths=0.1, colors='green') ax.add_collection(patches) if mode == 'random': patches.set_array(np.random.randint(0, 20, size=map.N)) patches.set_cmap(matplotlib.cm.jet) elif mode == 'population': patches.set_array(map.population) patches.set_cmap(matplotlib.cm.jet) patches.set_norm(matplotlib.colors.LogNorm()) plt.colorbar(patches, ax=ax) elif mode == 'graph': patches.set_color('black') patches.set_facecolor('white') patches.set_linewidth(0.1) ax.scatter(map.centroids[:, 0], map.centroids[:, 1], s=5) # Plot edges. ax.add_collection(land_edges) ax.add_collection(air_edges) elif mode == 'data': patches.set_array(data) patches.set_cmap(matplotlib.cm.jet) plt.colorbar(patches, ax=ax) plt.show()
class ArrayDisplay: """ Display a top-town view of a telescope array """ def __init__(self, telx, tely, tel_type=None, radius=20, axes=None, title="Array", autoupdate=True): if tel_type is None: tel_type = np.ones(len(telx)) patches = [ Rectangle(xy=(x - radius / 2, y - radius / 2), width=radius, height=radius, fill=False) for x, y in zip(telx, tely) ] self.autoupdate = autoupdate self.telescopes = PatchCollection(patches, match_original=True) self.telescopes.set_clim(1, 9) rgb = matplotlib.cm.Set1((tel_type - 1) / 9) self.telescopes.set_edgecolor(rgb) self.telescopes.set_linewidth(2.0) self.axes = axes if axes is not None else plt.gca() self.axes.add_collection(self.telescopes) self.axes.set_aspect(1.0) self.axes.set_title(title) self.axes.set_xlim(-1000, 1000) self.axes.set_ylim(-1000, 1000) self.axes_hillas = axes if axes is not None else plt.gca() @property def values(self): """An array containing a value per telescope""" return self.telescopes.get_array() @values.setter def values(self, values): """ set the telescope colors to display """ self.telescopes.set_array(values) self._update() def _update(self): """ signal a redraw if necessary """ if self.autoupdate: plt.draw() def add_ellipse(self, centroid, length, width, angle, **kwargs): """ plot an ellipse on top of the camera Parameters ---------- centroid: (float, float) position of centroid length: float major axis width: float minor axis angle: float rotation angle wrt x-axis about the centroid, anticlockwise, in radians asymmetry: float 3rd-order moment for directionality if known kwargs: any MatPlotLib style arguments to pass to the Ellipse patch """ ellipse = Ellipse(xy=centroid, width=length, height=width, angle=np.degrees(angle), fill=True, **kwargs) self.axes.add_patch(ellipse) return ellipse def add_polygon(self, centroid, radius, nsides=3, **kwargs): """ plot a polygon on top of the camera Parameters ---------- centroid: (float, float) position of centroid radius: float radius nsides: int Number of points on polygon kwargs: any MatPlotLib style arguments to pass to the RegularPolygon patch """ polygon = RegularPolygon(xy=centroid, radius=radius, numVertices=nsides, **kwargs) self.axes.add_patch(polygon) return polygon def overlay_moments(self, momparams, tel_position, scale_fac, **kwargs): """helper to overlay ellipse from a `reco.MomentParameters` structure Parameters ---------- momparams: `reco.MomentParameters` structuring containing Hillas-style parameterization tel_position: list (x, y) positions of each telescope scale_fac: float scaling factor to apply to width and length when overlaying moments kwargs: key=value any style keywords to pass to matplotlib (e.g. color='red' or linewidth=6) """ # strip off any units ellipse_list = list() size_list = list() i = 0 for h in momparams: length = u.Quantity(momparams[h].length).value * scale_fac width = u.Quantity(momparams[h].width).value * scale_fac size_list.append(u.Quantity(momparams[h].size).value) tel_x = u.Quantity(tel_position[0][i]).value tel_y = u.Quantity(tel_position[1][i]).value i += 1 ellipse = Ellipse(xy=(tel_x, tel_y), width=length, height=width, angle=np.degrees(momparams[h].psi.rad)) ellipse_list.append(ellipse) patches = PatchCollection(ellipse_list, **kwargs) patches.set_clim(0, 1000) # Set ellipse colour based on image size patches.set_array(np.asarray(size_list)) self.axes_hillas.add_collection(patches) def overlay_axis(self, momparams, tel_position, **kwargs): """helper to overlay ellipse from a `reco.MomentParameters` structure Parameters ---------- momparams: `reco.MomentParameters` structuring containing Hillas-style parameterization tel_position: list (x, y) positions of each telescope kwargs: key=value any style keywords to pass to matplotlib (e.g. color='red' or linewidth=6) """ # strip off any units line_list = list() size_list = list() i = 0 for h in momparams: tel_x = u.Quantity(tel_position[0][i]).value tel_y = u.Quantity(tel_position[1][i]).value psi = u.Quantity(momparams[h].psi).value x_sc = [tel_x - np.cos(psi) * 10000, tel_x + np.cos(psi) * 10000] y_sc = [tel_y - np.sin(psi) * 10000, tel_y + np.sin(psi) * 10000] i += 1 self.axes_hillas.add_line( Line2D(x_sc, y_sc, linestyle='dashed', color='black'))
def factcamera(self, data, pixelcoords=None, cmap='gray', vmin=None, vmax=None, pixelset=None, pixelsetcolour='g', linewidth=None, intersectcolour='b', picker=True, ): """ Attributes ---------- data : array like with shape 1440 the data you want to plot into the pixels pixelset : boolean array with shape 1440 the pixels where pixelset is True are marked with 'pixelsetcolour' [default: None] pixelsetcolour : a matplotlib conform colour representation the colour for the pixels in 'pixelset', [default: green] pixelcoords : the coordinates for the pixels in form [x-values, y-values] if None, the package resource is used [default: None] cmap : str or matplotlib colormap instance the colormap to use for plotting the 'dataset' [default: gray] vmin : float the minimum for the colorbar, if None min(dataset[event]) is used [default: None] vmax : float the maximum for the colorbar, if None max(dataset[event]) is used [default: None] picker: bool if True then the the pixel are made clickable to show information """ self.set_aspect('equal') if picker is True: fig = self.get_figure() fig.canvas.mpl_connect("pick_event", onpick) # if the axes limit is still (0,1) assume new axes if self.get_xlim() == (0, 1) and self.get_ylim() == (0, 1): self.set_xlim(-200, 200) self.set_ylim(-200, 200) if pixelcoords is None: pixel_x, pixel_y = get_pixel_coords() else: pixel_x, pixel_y = pixelcoords if vmin is None: vmin = np.min(data) if vmax is None: vmax = np.max(data) edgecolors = np.array(1440*["k"]) if pixelset is None: pixelset = np.zeros(1440, dtype=np.bool) _pixelset = np.array(pixelset) if _pixelset.ndim == 1: if _pixelset.shape != (1440,): pixelset = np.zeros(1440, dtype=np.bool) pixelset[_pixelset] = True else: pixelset = np.array(_pixelset, dtype=np.bool) edgecolors[pixelset] = pixelsetcolour elif _pixelset.ndim == 2: for pixelset, colour in zip(_pixelset, pixelsetcolour): edgecolors[pixelset] = colour intersect = np.logical_and(_pixelset[0], _pixelset[1]) edgecolors[intersect] = intersectcolour else: raise ValueError( """pixelset needs to be one of: 1. list of pixelids 2. 1d bool array with shape (1440,) 3. 2d bool array with shape (2, 1440) """ ) patches = [] for x, y, ec in zip(pixel_x, pixel_y, edgecolors): patches.append( RegularPolygon( xy=(x, y), numVertices=6, radius=0.95*9.5/np.sqrt(3), orientation=0., # in radians ) ) if linewidth is None: linewidth = calc_linewidth(self) collection = PatchCollection(patches, picker=0) collection.set_linewidth(linewidth) collection.set_edgecolors(edgecolors) collection.set_cmap(cmap) collection.set_array(data) collection.set_clim(vmin, vmax) self.add_collection(collection) return collection
def plot_multifolder_old(folder_list, Zlist, pointing, ap): rw = 0.5 rh = 0.1 numfree = 1334 - 5 - 1 minchi = np.inf maxchi = 0 for f in folder_list: stepfile = glob("{:}/P{:}_*{:02n}_steps.dat".format(f, pointing, ap))[0] print stepfile chi = np.loadtxt(stepfile, usecols=(12,), unpack=True) chi = chi[chi == chi] upperlim = np.median(chi) + 1.3 * np.min(chi) if chi[-1] < minchi: minchi = chi[-1] if upperlim > maxchi: maxchi = upperlim fig = plt.figure() grid = ImageGrid( fig, 111, nrows_ncols=(1, 1), cbar_mode="each", cbar_location="top", cbar_pad="1%", axes_class=None ) ax = grid[0] ax.set_xlabel("$Z/Z_{\odot}$") ax.set_ylabel("MLWA") goodage = [] bigZ = np.zeros(len(folder_list)) for z, f in enumerate(folder_list): stepfile = glob("{:}/P{:}_*{:02n}_steps.dat".format(f, pointing, ap))[0] print stepfile MLWA, chi = np.loadtxt(stepfile, usecols=(6, 12), unpack=True) idx = chi == chi chi = chi[idx] MLWA = MLWA[idx] idx = MLWA == MLWA chi = chi[idx] MLWA = MLWA[idx] # good = np.where(chi < 80) # chi = chi[good] # MLWA = MLWA[good] chi -= minchi patches = [] for i in range(MLWA.size): # patches.append(Circle((z,MLWA[i]),radius=0.1,linewidth=0)) width = rw * ((minchi + 5000) / (chi[i] + 5000)) # width = rw * (minchi/chi[i]) patches.append(Rectangle((z - width / 2, MLWA[i] - rh / 2), width, rh)) collection = PatchCollection( np.array(patches)[::-1], cmap=plt.get_cmap("gnuplot"), norm=matplotlib.colors.Normalize(vmin=minchi, vmax=maxchi), ) collection.set_alpha(0.7) collection.set_linewidth(0.0) collection.set_array(chi[::-1]) ax.add_collection(collection) # ax.axhline(y=MLWA[-1],color='k',ls=':',alpha=0.6) ax.hlines(MLWA[-1], z - 0.3, z + 0.3, color="g", lw=2) prob = 1 - ss.chi2.cdf(chi[-1] * numfree, numfree) if prob >= 0.68: goodage.append(MLWA[-1]) bigZ[z] = 1 ax.text(z + 0.5, MLWA[-1], "{:4.2f}\n{:4.2f}".format(prob, chi[-1]), fontsize=10) collection.set_alpha(1.0) cbar = ax.cax.colorbar(collection) ci = [68.27, 50.0, 80.0, 40.0] dc = [4.72, 3.36, 5.99, 2.75] # for (c, d) in zip(ci, dc): # ax.cax.axvline(x = np.log10(d), color='g') # ax.cax.text(np.log10(d) - 0.03, 2, '{}'.format(c), # transform=ax.cax.transData, # fontsize=8) collection.set_alpha(0.1) cbar.set_label_text(r"$\Delta\chi^2_{\nu}$") ax.set_xlim(-1, len(Zlist) + 1) ax.set_ylim(0, 12) ax.set_xticks(np.arange(len(Zlist))) ax.set_xticklabels(Zlist) # fig.show() return fig, np.mean(goodage), np.std(goodage), bigZ
class CameraPlot(object): '''A Class for a camera pixel''' def __init__( self, telescope, ax, data=None, cmap='gray', vmin=None, vmax=None, ): ''' :telescope: the telescope class for the pixel :data: array-like with one value for each pixel :cmap: a matpixellib colormap string or instance :vmin: minimum value of the colormap :vmax: maximum value of the colormap ''' self.telescope = telescope if data is None: data = np.zeros(telescope.n_pixel) patches = [] if telescope.pixel_shape == 'hexagon': for xy in zip(telescope.pixel_x, telescope.pixel_y): patches.append( RegularPolygon( xy=xy, numVertices=6, radius=telescope.pixel_size, orientation=telescope.pixel_orientation, ) ) self.pixel = PatchCollection(patches) self.pixel.set_linewidth(0) self.pixel.set_cmap(cmap) self.pixel.set_array(data) self.pixel.set_clim(vmin, vmax) self.vmin = vmin self.vmax = vmax self.ax = ax self.ax.add_collection(self.pixel) self.ax.set_xlim( self.telescope.pixel_x.min() - 2 * self.telescope.pixel_size, self.telescope.pixel_x.max() + 2 * self.telescope.pixel_size, ) self.ax.set_ylim( self.telescope.pixel_y.min() - 2 * self.telescope.pixel_size, self.telescope.pixel_y.max() + 2 * self.telescope.pixel_size, ) @property def data(self): return self.pixel.get_array() @data.setter def data(self, data): self.pixel.set_array(data) if not self.vmin or not self.vmax: self.pixel.autoscale() self.pixel.changed()
def draw(self, ax, draw_polygons=True, colour='k', line_alpha=1., fill_alpha=1., linestyle='-', linewidth=1., markers=None, values=None, precompv=None, vmin=None, vmax=None, title=None, cmap=None, cblabel=None, logscale=False, allowed_cbticklabels=(None, ), extend='neither', zorder=0): """ Draw the diagram """ drawvalues = values is not None if drawvalues: patches = [] colours = np.zeros(self.nc) for i, pol in self.polygons.items(): # Colours and filled polygons if drawvalues: filled_pol = mp.Polygon(self.cellverts[i]) patches.append(filled_pol) if values == 'areas': colours[i] = pol.area if values == 'inv_areas': colours[i] = 1. / self.free_areas[i] if values == 'free_areas': colours[i] = self.free_areas[i] if values == 'precomputed': if logscale: colours[i] = np.abs(precompv[i]) else: colours[i] = precompv[i] # Colour for the polygon contours if colour == 'same_as_facecolors': pc_ = colours[i] else: pc_ = colour # Draw the polygon if draw_polygons: pol.draw(ax=ax, colour=pc_, alpha=line_alpha, linestyle=linestyle, linewidth=linewidth, markers=markers, zorder=zorder) # Line colours if drawvalues: if vmin is None: vmin = colours.min() if vmax is None: vmax = colours.max() if logscale: vmin = np.abs(vmin) vmax = np.abs(vmax) norm = LogNorm(vmin=vmin, vmax=vmax) else: norm = Normalize(vmin=vmin, vmax=vmax) m = plt.cm.ScalarMappable(norm=norm, cmap=cmap) line_colours = m.to_rgba(colours) print(line_colours) if drawvalues: collection = PatchCollection(patches, cmap=cmap, norm=norm) ax.add_collection(collection) collection.set_alpha(fill_alpha) collection.set_array(colours) if logscale: collection.set_clim(vmin=vmin, vmax=vmax) else: collection.set_clim(vmin=0., vmax=vmax) if colour == 'same_as_facecolors': collection.set_edgecolors(line_colours) else: collection.set_edgecolor(colour) collection.set_linewidth(linewidth) if values == 'precomputed': collection.set_clim(vmin=vmin, vmax=vmax) # Color bar if logscale: l_f = LogFormatter(10, labelOnlyBase=False) cb = plt.colorbar(collection, ax=ax, orientation='vertical', format=l_f, extend=extend) # Set minor ticks # We need to nomalize the tick locations so that they're in the range from 0-1... # minorticks = p.norm(np.arange(1, 10, 2)) # Minimum and maximum exponents min_exp = int(np.log10(min(vmin, vmax))) max_exp = int(np.log10(max(vmin, vmax))) + 1 # Ticks for the colorbar in case it's logscale minorticks = 10.**np.arange(min_exp, max_exp + 1, 1) minorticks_ = minorticks.tolist() for i in range(2, 10, 1): minorticks_ = minorticks_ + (float(i) * minorticks).tolist() minorticks_.sort() minorticks = np.array(minorticks_) minorticks = minorticks[np.where(minorticks >= vmin)] minorticks = minorticks[np.where(minorticks <= vmax)] print(minorticks) cb.set_ticks(minorticks) cb.set_ticklabels([ str(int(x)) if x in allowed_cbticklabels else '' for x in minorticks ]) else: cb = plt.colorbar(collection, ax=ax, orientation='vertical', extend=extend) cb.set_label(cblabel) if title is not None: ax.set_title(title) ax.set_xlabel(r'$\rm x$ ($\rm \mu m$)') ax.set_ylabel(r'$\rm y$ ($\rm \mu m$)')
color = 'y' elif zone == 'C': color = 'c' elif zone == 'M': color = 'darkmagenta' elif zone == 'O': color = 'ivory' elif zone == 'P': color = 'forestgreen' patches = [mplPolygon(np.array(shape), True)] pc = PatchCollection(patches) pc.set_alpha(.7) pc.set_facecolor(color) pc.set_zorder(2) pc.set_linewidth(.1) pc.set_edgecolor('k') ax.add_collection(pc) ##################################################################### # Add Roads shapefile to map # ##################################################################### map.readshapefile('RoadCenterlines/RoadCenterlines_2', 'RoadCenterlines_2', linewidth=.2) ##################################################################### # TRY CODE HERE # ##################################################################### c = fiona.open('ZoningDistrict/ZoningDistrict_test_2.shp')
def plotter(self, mesh=True): """ Plots solution and overlays mesh """ # approx=self.nodal_values() xy = np.array([self.x[:], self.y[:]]).T patches = [] for coords in xy[self.con_array[:]]: quad = Polygon(coords, facecolor='none', fill=False) patches.append(quad) n = 50 X, Y = np.meshgrid(np.linspace(min(self.x), max(self.x), n), np.linspace(min(self.y), max(self.y), n)) # X=X.ravel(); Y=Y.ravel() # Z=np.zeros(n**2) # print(X,Y) # for i in range(n**2): # print(self.approx_function(X[i],Y[i]),i) # Z[i]=self.approx_function(X[i],Y[i]) # f=scipy.interpolate.interp2d(self.x,self.y,self.approx) # Z=f(np.linspace(min(self.x),max(self.x),n),np.linspace(min(self.y),max(self.y),n)) # X=X.reshape((n,n)); Y=Y.reshape((n,n)); Z=Z.reshape((n,n)) Z = scipy.interpolate.griddata((self.x, self.y), self.approx, (X, Y)) ticks = np.linspace(min(self.approx), max(self.approx), 5) # return (X,Y,Z.astype('float')) fig, ax = plt.subplots() cs = ax.contourf(X, Y, Z, cmap="coolwarm", levels=np.linspace(min(self.approx), max(self.approx), 30)) cbar = fig.colorbar(cs, ax=ax, ticks=ticks) p = PatchCollection(patches, match_original=True) p.set_linewidth(0.1) if mesh == False: p.set_linewidth(0) plt.xticks(np.linspace(-400, 400, 5)) plt.yticks(np.linspace(-400, 400, 5)) ax.add_collection(p) ax.set_aspect('equal') ax.set_xlim([-400, 400]) ax.set_ylim([-400, 400]) props = dict(boxstyle='square', facecolor='white', alpha=1.) plt.gcf().subplots_adjust(bottom=0.15) plt.text(0.5, 0.9, 'Degrees of freedom= %s' % len(self.F), ha='center', va='center', transform=ax.transAxes, bbox=props, fontsize=14) plt.xlabel('x [m]', fontsize=18) plt.ylabel('y [m]', fontsize=18) plt.tick_params(labelsize=18) cbar.ax.tick_params(labelsize=18) cbar.set_label('Pressure [MPa]', labelpad=10, size=18) return plt
polygon = Polygon(np.array([x, y]).transpose(), True, color='gray') patches_polygon.append(polygon) pcc = PatchCollection(patches_circle, match_original=False) pcp = PatchCollection(patches_polygon, match_original=False) if args.collision_status: pcc.set_color('#85878b') pcp.set_color('#85878b') pcc.set_alpha(0.3) pcp.set_alpha(0.3) pcc.set_linestyle('dashed') pcp.set_linestyle('dashed') pcc.set_edgecolor('#73cdc9') pcp.set_edgecolor('#73cdc9') pcc.set_linewidth(0.4) pcp.set_linewidth(0.4) pcc.set_joinstyle('round') pcp.set_joinstyle('round') else: pcc.set_color('gray') pcp.set_color('gray') ax.add_collection(pcc) ax.add_collection(pcp) if args.safety_certificate: xyrs = [] for line in open(args.safety_certificate, 'r').readlines(): l = line.strip() if not l: continue xyrs.append([float(x) for x in l.split(' ')])
def plot_multiZ(prefix, minval=0, maxval=200, bluefree=702): fraclist = np.array([0.005, 0.02, 0.2, 0.4, 1, 2.5]) rw = 0.5 rh = 0.05 minchi = np.inf for z in range(fraclist.size): stepfile = "{}_Z{:04}_steps.dat".format(prefix, int(fraclist[z] * 1000)) blueChi = np.loadtxt(stepfile, usecols=(17,), unpack=True) blueChi *= bluefree if blueChi[-1] < minchi: minchi = blueChi[-1] fig = plt.figure() grid = ImageGrid( fig, 111, nrows_ncols=(1, 1), cbar_mode="each", cbar_location="top", cbar_pad="1%", axes_class=None ) ax = grid[0] ax.set_xlabel("$Z/Z_{\odot}$") ax.set_ylabel("MLWA") for z in range(fraclist.size): stepfile = "{}_Z{:04}_steps.dat".format(prefix, int(fraclist[z] * 1000)) MLWA, TAUV, Chi, blueChi = np.loadtxt(stepfile, usecols=(12, 13, 15, 17), unpack=True) blueChi *= bluefree # good = np.where(blueChi < 80) # blueChi = blueChi[good] # MLWA = MLWA[good] blueChi -= minchi patches = [] print np.log10(blueChi.min()), np.log10(blueChi.max()) for i in range(MLWA.size): # patches.append(Circle((z,MLWA[i]),radius=0.1,linewidth=0)) width = rw * ((minchi + 5000) / (blueChi[i] + 5000)) # width = rw * (minchi/blueChi[i]) patches.append(Rectangle((z - width / 2, MLWA[i] - rh / 2), width, rh)) collection = PatchCollection( np.array(patches)[::-1], cmap=plt.get_cmap("gnuplot"), norm=matplotlib.colors.Normalize(vmin=minval, vmax=maxval), ) collection.set_alpha(0.1) collection.set_linewidth(0.0) collection.set_array(np.log10(blueChi)[::-1]) ax.add_collection(collection) # ax.axhline(y=MLWA[-1],color='k',ls=':',alpha=0.6) ax.hlines(MLWA[-1], z - 0.5, z + 0.5, color="g", lw=2) ax.text( z + 0.5, MLWA[-1], "{:5.2f}%, {:4.1f}".format(100 - 100 * ss.chi2.cdf(blueChi[-1], bluefree + 5), blueChi[-1]), ) collection.set_alpha(1.0) cbar = ax.cax.colorbar(collection) ci = [68.27, 50.0, 80.0, 40.0] dc = [4.72, 3.36, 5.99, 2.75] # for (c, d) in zip(ci, dc): # ax.cax.axvline(x = np.log10(d), color='g') # ax.cax.text(np.log10(d) - 0.03, 2, '{}'.format(c), # transform=ax.cax.transData, # fontsize=8) collection.set_alpha(0.1) cbar.set_label_text("Log( $\Delta\chi^2_{\mathrm{blue}}$ )") ax.set_xlim(-1, fraclist.size + 1) ax.set_ylim(0, 12) ax.set_xticks(np.arange(fraclist.size)) ax.set_xticklabels(fraclist) fig.show() return fig
#ax.set_xlim(-(seg_bar_height+1.25), (seg_bar_height+1.25)) #ax.set_ylim(-(seg_bar_height+1.25), (seg_bar_height+1.25)) chrom_set = set() for i in path: chrom_set.add(segSeqD[i[0]][0]) sorted_chrom = sorted(chrom_set, key=lambda x: x.rsplit("chr")[-1]) sorted_chrom_colors = [chromosome_colors[x] for x in sorted_chrom] legend_patches = [] for chrom, color in zip(sorted_chrom, sorted_chrom_colors): legend_patches.append(mpatches.Patch(color=color, label=chrom)) # plt.legend(handles=legend_patches,fontsize=8,loc=3,bbox_to_anchor=(-.3,.15)) plt.legend( handles=legend_patches, fontsize=10, bbox_to_anchor=(0, 0)) # bbox_to_anchor=(0,-1.5))#,bbox_to_anchor=(.09,-1.5)) p = PatchCollection(patches) p.set_facecolor(f_color_v) p.set_edgecolor(e_color_v) p.set_linewidth(lw_v) ax.add_collection(p) ax.set_aspect(1.0) plt.axis('off') plt.savefig(fname + '.png', dpi=600) plt.savefig(fname + '.pdf', format='pdf') plt.close() print("finished")
#! /home/kshan/anaconda2/bin/python import numpy as np import matplotlib.pyplot as plt import matplotlib.path as mpath import matplotlib.lines as mlines import matplotlib.patches as mpatches from matplotlib.collections import PatchCollection fig, ax = plt.subplots() patches = [] colors = ["red"] collection = PatchCollection(patches, alpha=1) collection.set_color(colors) collection.set_edgecolor("black") collection.set_linewidth(1) ax.add_collection(collection) plt.plot((13.96, 8.05175), (7.93333, 7.34158), color='r') plt.plot((13.96, 19.754), (7.93333, 7.2273), color='r') plt.plot((8.05175, 8.87409), (7.34158, 4.66392), color='g') plt.plot((8.05175, 9.09689), (7.34158, 9.79644), color='g') plt.plot((19.754, 18.3777), (7.2273, 5.10356), color='g') plt.plot((19.754, 19.7798), (7.2273, 10.7015), color='g') plt.plot((6.1265, 9.30722), (3.40278, 3.47205), color='m') plt.plot((8.87409, 9.30722), (4.66392, 3.47205), color='m') plt.plot((8.87409, 9.17591), (4.66392, 5.9871), color='m') plt.plot((12.3072, 9.17591), (6.10582, 5.9871), color='m') plt.plot((7.46506, 10.1029), (9.78961, 9.17742), color='m') plt.plot((9.09689, 10.1029), (9.79644, 9.17742), color='m') plt.plot((9.09689, 8.6289), (9.79644, 10.9534), color='m')
class ArrayDisplay: """ Display a top-town view of a telescope array. This can be used in two ways: by default, you get a display of all telescopes in the subarray, colored by telescope type, however you can also color the telescopes by a value (like trigger pattern, or some other scalar per-telescope parameter). To set the color value, simply set the ``value`` attribute, and the fill color will be updated with the value. You might want to set the border color to zero to avoid confusion between the telescope type color and the value color ( ``array_disp.telescope.set_linewidth(0)``) To display a vector field over the telescope positions, e.g. for reconstruction, call `set_vector_uv()` to set cartesian vectors, or `set_vector_rho_phi()` to set polar coordinate vectors. These both take an array of length N_tels, or a single value. Parameters ---------- subarray: ctapipe.instrument.SubarrayDescription the array layout to display axes: matplotlib.axes.Axes matplotlib axes to plot on, or None to use current one title: str title of array plot tel_scale: float scaling between telescope mirror radius in m to displayed size autoupdate: bool redraw when the input changes radius: Union[float, list, None] set telescope radius to value, list/array of values. If None, radius is taken from the telescope's mirror size. """ def __init__( self, subarray, axes=None, autoupdate=True, tel_scale=2.0, alpha=0.7, title=None, radius=None, frame=GroundFrame(), ): self.frame = frame self.subarray = subarray self.axes = axes or plt.gca() # get the telescope positions. If a new frame is set, this will # transform to the new frame. self.tel_coords = subarray.tel_coords.transform_to(frame).cartesian self.unit = self.tel_coords.x.unit # set up colors per telescope type tel_types = [str(tel) for tel in subarray.tels.values()] if radius is None: # set radius to the mirror radius (so big tels appear big) radius = [ np.sqrt(tel.optics.mirror_area.to("m2").value) * tel_scale for tel in subarray.tel.values() ] self.radii = radius else: self.radii = np.ones(len(tel_types)) * radius if title is None: title = subarray.name # get default matplotlib color cycle (depends on the current style) color_cycle = cycle(plt.rcParams["axes.prop_cycle"].by_key()["color"]) # map a color to each telescope type: tel_type_to_color = {} for tel_type in list(set(tel_types)): tel_type_to_color[tel_type] = next(color_cycle) tel_color = [tel_type_to_color[ttype] for ttype in tel_types] patches = [] for x, y, r, c in zip( list(self.tel_coords.x.to_value("m")), list(self.tel_coords.y.to_value("m")), list(radius), tel_color, ): patches.append( Circle(xy=(x, y), radius=r, fill=True, color=c, alpha=alpha)) # build the legend: legend_elements = [] for ttype in list(set(tel_types)): color = tel_type_to_color[ttype] legend_elements.append( Line2D( [0], [0], marker="o", color=color, label=ttype, markersize=10, alpha=alpha, linewidth=0, )) self.axes.legend(handles=legend_elements) self.add_radial_grid() # create the plot self.tel_colors = tel_color self.autoupdate = autoupdate self.telescopes = PatchCollection(patches, match_original=True) self.telescopes.set_linewidth(2.0) self.axes.add_collection(self.telescopes) self.axes.set_aspect(1.0) self.axes.set_title(title) xunit = self.tel_coords.x.unit.to_string("latex") yunit = self.tel_coords.y.unit.to_string("latex") xname, yname, _ = frame.get_representation_component_names().keys() self.axes.set_xlabel(f"{xname} [{xunit}] $\\rightarrow$") self.axes.set_ylabel(f"{yname} [{yunit}] $\\rightarrow$") self._labels = [] self._quiver = None self.axes.autoscale_view() @property def values(self): """An array containing a value per telescope""" return self.telescopes.get_array() @values.setter def values(self, values): """set the telescope colors to display""" self.telescopes.set_array(np.ma.masked_invalid(values)) self._update() def add_radial_grid(self, spacing=100 * u.m): """add some dotted rings for distance estimation. The number of rings is estimated automatically from the spacing and the array footprint. Parameters ---------- spacing: Quantity spacing between rings """ n_circles = np.round( (np.sqrt(self.subarray.footprint / np.pi) / spacing).to_value(""), 0, ) circle_radii = np.arange(1, n_circles + 2, 1) * spacing.to_value( self.unit) circle_patches = PatchCollection( [ Circle( xy=(0, 0), radius=r, fill=False, fc="none", linestyle="dotted", color="gray", alpha=0.1, lw=1, ) for r in circle_radii ], color="#eeeeee", ls="dotted", fc="none", lw=3, ) self.axes.add_collection(circle_patches) def set_vector_uv(self, uu, vv, c=None, **kwargs): """sets the vector field U,V and color for all telescopes Parameters ---------- uu: array[num_tels] x-component of direction vector vv: array[num_tels] y-component of direction vector c: color or list of colors vector color for each telescope (or one for all) kwargs: extra args passed to plt.quiver(), ignored on subsequent updates """ coords = self.tel_coords uu = u.Quantity(uu).to_value("m") vv = u.Quantity(vv).to_value("m") N = len(coords.x) # matplotlib since 3.2 does not allow scalars anymore # if quiver was already created with a certain number of arrows if np.isscalar(uu): uu = np.full(N, uu) if np.isscalar(vv): vv = np.full(N, vv) # passing in None for C does not work, we need to provide # a variadic number of arguments args = [coords.x.to_value("m"), coords.y.to_value("m"), uu, vv] if c is None: # use colors by telescope type if the user did not provide any kwargs["color"] = kwargs.get("color", self.tel_colors) else: # same as above, enable use of scalar to set all values at once if np.isscalar(c): c = np.full(N, c) args.append(c) if self._quiver is None: self._quiver = self.axes.quiver(*args, scale_units="xy", angles="xy", scale=1, **kwargs) else: self._quiver.set_UVC(uu, vv, c) def set_vector_rho_phi(self, rho, phi, c=None, **kwargs): """sets the vector field using R, Phi for each telescope Parameters ---------- rho: float or array[float] vector magnitude for each telescope phi: array[Angle] vector angle for each telescope c: color or list of colors vector color for each telescope (or one for all) """ phi = Angle(phi).rad uu, vv = polar_to_cart(rho, phi) self.set_vector_uv(uu, vv, c=c, **kwargs) def set_vector_hillas(self, hillas_dict, core_dict, length, time_gradient, angle_offset): """ Function to set the vector angle and length from a set of Hillas parameters. In order to proper use the arrow on the ground, also a dictionary with the time gradients for the different telescopes is needed. If the gradient is 0 the arrow is not plotted on the ground, whereas if the value of the gradient is negative, the arrow is rotated by 180 degrees (Angle(angle_offset) not added). This plotting behaviour has been tested with the timing_parameters function in ctapipe/image. Parameters ---------- hillas_dict: Dict[int, HillasParametersContainer] mapping of tel_id to Hillas parameters core_dict : Dict[int, CoreParameters] mapping of tel_id to CoreParametersContainer length: Float length of the arrow (in meters) time_gradient: Dict[int, value of time gradient (no units)] dictionary for value of the time gradient for each telescope angle_offset: Float This should be the ``event.pointing.array_azimuth`` parameter """ # rot_angle_ellipse is psi parameter in HillasParametersContainer rho = np.zeros(self.subarray.num_tels) * u.m rot_angle_ellipse = np.zeros(self.subarray.num_tels) * u.deg for tel_id, params in hillas_dict.items(): idx = self.subarray.tel_indices[tel_id] rho[idx] = u.Quantity(length, u.m) psi = core_dict[tel_id] if time_gradient[tel_id] > 0.01: angle_offset = Angle(angle_offset) rot_angle_ellipse[idx] = psi + angle_offset + 180 * u.deg elif time_gradient[tel_id] < -0.01: rot_angle_ellipse[idx] = psi + angle_offset else: rho[idx] = 0 * u.m self.set_vector_rho_phi(rho=rho, phi=rot_angle_ellipse) def set_line_hillas(self, hillas_dict, core_dict, range, **kwargs): """ Plot the telescope-wise direction of the shower as a segment. Each segment will be centered with a point on the telescope position and will be 2*range long. Parameters ---------- hillas_dict: Dict[int, HillasParametersContainer] mapping of tel_id to Hillas parameters core_dict : Dict[int, CoreParameters] mapping of tel_id to CoreParametersContainer range: float half of the length of the segments to be plotted (in meters) """ coords = self.tel_coords c = self.tel_colors r = np.array([-range, range]) for tel_id, params in hillas_dict.items(): idx = self.subarray.tel_indices[tel_id] x_0 = coords[idx].x.to_value(u.m) y_0 = coords[idx].y.to_value(u.m) psi = core_dict[tel_id] x = x_0 + np.cos(psi).value * r y = y_0 + np.sin(psi).value * r self.axes.plot(x, y, color=c[idx], **kwargs) self.axes.scatter(x_0, y_0, color=c[idx]) def add_labels(self): px = self.tel_coords.x.to_value("m") py = self.tel_coords.y.to_value("m") for tel, x, y, r in zip(self.subarray.tels, px, py, self.radii): name = str(tel) lab = self.axes.text( x, y - r * 1.8, name, fontsize=8, clip_on=True, horizontalalignment="center", verticalalignment="top", ) self._labels.append(lab) def remove_labels(self): for lab in self._labels: lab.remove() self._labels = [] def _update(self): """signal a redraw if necessary""" if self.autoupdate: plt.draw() def background_contour(self, x, y, background, **kwargs): """ Draw image contours in background of the display, useful when likelihood fitting Parameters ---------- x: ndarray array of image X coordinates y: ndarray array of image Y coordinates background: ndarray Array of image to use in background kwargs: key=value any style keywords to pass to matplotlib """ # use zorder to ensure the contours appear under the telescopes. self.axes.contour(x, y, background, zorder=0, **kwargs)
# for i in range(1,24): # chrom_set.add("chr" + str(i)) sorted_chrom = sorted(chrom_set,key=lambda x:int(x.rsplit("chr")[-1])) sorted_chrom_colors = [chromosome_colors[x] for x in sorted_chrom] legend_patches = [] for chrom,color in zip(sorted_chrom,sorted_chrom_colors): legend_patches.append(mpatches.Patch(color=color,label=chrom)) plt.legend(handles=legend_patches,fontsize=8,loc=3,bbox_to_anchor=(-.3,.15)) p = PatchCollection(patches) p.set_facecolor(f_color_v) p.set_edgecolor(e_color_v) p.set_linewidth(lw_v) ax.add_collection(p) ax.set_aspect(1.0) plt.axis('off') plt.savefig(fname + '.png',dpi=600) plt.savefig(fname + '.pdf',format='pdf') plt.close() print "done plotting bionano" #handles basic (non-bionano case) if args.feature_labels: #make a separate figure plt.clf() fig, ax = plt.subplots() patches = []
def Plot2D(self, xy=None, elecon=None, u=None, color=None, ax=None, show=0, weight=None, colorby=None, linestyle='-', label=None, xlim=None, ylim=None, filename=None, **kwds): assert self.dimensions == 2 from matplotlib.patches import Polygon import matplotlib.lines as mlines from matplotlib.collections import PatchCollection from matplotlib.cm import coolwarm, Spectral import matplotlib.pyplot as plt if xy is None: xy = array(self.coord) if elecon is None: elecon = [] for blk in self.eleblx: elecon.extend(blk.elecon.tolist()) elecon = asarray(elecon) if u is not None: xy += u.reshape(xy.shape) patches = [] for points in xy[elecon[:]]: quad = Polygon(points, True) patches.append(quad) if ax is None: fig, ax = plt.subplots() #colors = 100 * random.rand(len(patches)) p = PatchCollection(patches, linewidth=weight, **kwds) if colorby is not None: colorby = asarray(colorby).flatten() if len(colorby) == len(xy): # average value in element colorby = array([average(colorby[points]) for points in elecon]) p.set_cmap(Spectral) #coolwarm) p.set_array(colorby) p.set_clim(vmin=colorby.min(), vmax=colorby.max()) fig.colorbar(p) else: p.set_edgecolor(color) p.set_facecolor('None') p.set_linewidth(weight) p.set_linestyle(linestyle) if label: ax.plot([], [], color=color, linestyle=linestyle, label=label) ax.add_collection(p) if not ylim: ymin, ymax = amin(xy[:,1]), amax(xy[:,1]) dy = max(abs(ymin*.05), abs(ymax*.05)) ax.set_ylim([ymin-dy, ymax+dy]) else: ax.set_ylim(ylim) if not xlim: xmin, xmax = amin(xy[:,0]), amax(xy[:,0]) dx = max(abs(xmin*.05), abs(xmax*.05)) ax.set_xlim([xmin-dx, xmax+dx]) else: ax.set_xlim(xlim) ax.set_aspect('equal') if show: plt.show() if filename is not None: plt.legend() plt.savefig(filename, transparent=True, bbox_inches="tight", pad_inches=0) return ax
class ArrayDisplay: """ Display a top-town view of a telescope array. This can be used in two ways: by default, you get a display of all telescopes in the subarray, colored by telescope type, however you can also color the telescopes by a value (like trigger pattern, or some other scalar per-telescope parameter). To set the color value, simply set the `value` attribute, and the fill color will be updated with the value. You might want to set the border color to zero to avoid confusion between the telescope type color and the value color ( `array_disp.telescope.set_linewidth(0)`) To display a vector field over the telescope positions, e.g. for reconstruction, call `set_uv()` to set cartesian vectors, or `set_r_phi()` to set polar coordinate vectors. These both take an array of length N_tels, or a single value. Parameters ---------- subarray: ctapipe.instrument.SubarrayDescription the array layout to display axes: matplotlib.axes.Axes matplotlib axes to plot on, or None to use current one title: str title of array plot tel_scale: float scaling between telescope mirror radius in m to displayed size autoupdate: bool redraw when the input changes radius: Union[float, list, None] set telescope radius to value, list/array of values. If None, radius is taken from the telescope's mirror size. """ def __init__(self, subarray, axes=None, autoupdate=True, tel_scale=2.0, alpha=0.7, title=None, radius=None, frame=GroundFrame()): self.frame = frame self.subarray = subarray # get the telescope positions. If a new frame is set, this will # transform to the new frame. self.tel_coords = subarray.tel_coords.transform_to(frame) # set up colors per telescope type tel_types = [str(tel) for tel in subarray.tels.values()] if radius is None: # set radius to the mirror radius (so big tels appear big) radius = [np.sqrt(tel.optics.mirror_area.to("m2").value) * tel_scale for tel in subarray.tel.values()] if title is None: title = subarray.name # get default matplotlib color cycle (depends on the current style) color_cycle = cycle(plt.rcParams['axes.prop_cycle'].by_key()['color']) # map a color to each telescope type: tel_type_to_color = {} for tel_type in list(set(tel_types)): tel_type_to_color[tel_type] = next(color_cycle) tel_color = [tel_type_to_color[ttype] for ttype in tel_types] patches = [] for x, y, r, c in zip(list(self.tel_coords.x.value), list(self.tel_coords.y.value), list(radius), tel_color): patches.append( Circle( xy=(x, y), radius=r, fill=True, color=c, alpha=alpha, ) ) # build the legend: legend_elements = [] for ttype in list(set(tel_types)): color = tel_type_to_color[ttype] legend_elements.append( Line2D([0], [0], marker='o', color=color, label=ttype, markersize=10, alpha=alpha, linewidth=0) ) plt.legend(handles=legend_elements) self.tel_colors = tel_color self.autoupdate = autoupdate self.telescopes = PatchCollection(patches, match_original=True) self.telescopes.set_linewidth(2.0) self.axes = axes or plt.gca() self.axes.add_collection(self.telescopes) self.axes.set_aspect(1.0) self.axes.set_title(title) self._labels = [] self._quiver = None self.axes.autoscale_view() @property def values(self): """An array containing a value per telescope""" return self.telescopes.get_array() @values.setter def values(self, values): """ set the telescope colors to display """ self.telescopes.set_array(values) self._update() def set_vector_uv(self, u, v, c=None, **kwargs): """ sets the vector field U,V and color for all telescopes Parameters ---------- u: array[num_tels] x-component of direction vector v: array[num_tels] y-component of direction vector c: color or list of colors vector color for each telescope (or one for all) kwargs: extra args passed to plt.quiver(), ignored on subsequent updates """ if c is None: c = self.tel_colors if self._quiver is None: coords = self.tel_coords self._quiver = self.axes.quiver( coords.x, coords.y, u, v, color=c, scale_units='xy', angles='xy', scale=1, **kwargs ) else: self._quiver.set_UVC(u, v) def set_vector_rho_phi(self, rho, phi, c=None, **kwargs): """sets the vector field using R, Phi for each telescope Parameters ---------- rho: float or array[float] vector magnitude for each telescope phi: array[Angle] vector angle for each telescope c: color or list of colors vector color for each telescope (or one for all) """ phi = Angle(phi).rad u, v = polar_to_cart(rho, phi) self.set_vector_uv(u, v, c=c, **kwargs) def set_vector_hillas(self, hillas_dict, length, time_gradient, angle_offset): """ Function to set the vector angle and length from a set of Hillas parameters. In order to proper use the arrow on the ground, also a dictionary with the time gradients for the different telescopes is needed. If the gradient is 0 the arrow is not plotted on the ground, whereas if the value of the gradient is negative, the arrow is rotated by 180 degrees (Angle(angle_offset) not added). This plotting behaviour has been tested with the timing_parameters function in ctapipe/image. Parameters ---------- hillas_dict: Dict[int, HillasParametersContainer] mapping of tel_id to Hillas parameters length: Float length of the arrow (in meters) time_gradient: Dict[int, value of time gradient (no units)] dictionary for value of the time gradient for each telescope angle_offset: Float This should be the event.mcheader.run_array_direction[0] parameter """ # rot_angle_ellipse is psi parameter in HillasParametersContainer rho = np.zeros(self.subarray.num_tels) * u.m rot_angle_ellipse = np.zeros(self.subarray.num_tels) * u.deg for tel_id, params in hillas_dict.items(): idx = self.subarray.tel_indices[tel_id] rho[idx] = length * u.m if time_gradient[tel_id] > 0.01: params.psi = Angle(params.psi) angle_offset = Angle(angle_offset) rot_angle_ellipse[idx] = params.psi + angle_offset + 180 * u.deg elif time_gradient[tel_id] < -0.01: rot_angle_ellipse[idx] = params.psi + angle_offset else: rho[idx] = 0 * u.m self.set_vector_rho_phi(rho=rho, phi=rot_angle_ellipse) def set_line_hillas(self, hillas_dict, range, **kwargs): """ Function to plot a segment of length 2*range for each telescope from a set of Hillas parameters. The segment is centered on the telescope position. A point is added at each telescope position for better visualization. Parameters ---------- hillas_dict: Dict[int, HillasParametersContainer] mapping of tel_id to Hillas parameters range: float half of the length of the segments to be plotted (in meters) """ coords = self.tel_coords c = self.tel_colors for tel_id, params in hillas_dict.items(): idx = self.subarray.tel_indices[tel_id] x_0 = coords[idx].x.value y_0 = coords[idx].y.value m = np.tan(Angle(params.psi)) x = x_0 + np.linspace(-range, range, 50) y = y_0 + m * (x - x_0) distance = np.sqrt((x - x_0) ** 2 + (y - y_0) ** 2) mask = np.ma.masked_where(distance < range, distance).mask self.axes.plot(x[mask], y[mask], color=c[idx], **kwargs) self.axes.scatter(x_0, y_0, color=c[idx]) def add_labels(self): px = self.tel_coords.x.value py = self.tel_coords.y.value for tel, x, y in zip(self.subarray.tels, px, py): name = str(tel) lab = self.axes.text(x, y, name, fontsize=8, clip_on=True) self._labels.append(lab) def remove_labels(self): for lab in self._labels: lab.remove() self._labels = [] def _update(self): """ signal a redraw if necessary """ if self.autoupdate: plt.draw() def background_contour(self, x, y, background, **kwargs): """ Draw image contours in background of the display, useful when likelihood fitting Parameters ---------- x: ndarray array of image X coordinates y: ndarray array of image Y coordinates background: ndarray Array of image to use in background kwargs: key=value any style keywords to pass to matplotlib """ # use zorder to ensure the contours appear under the telescopes. self.axes.contour(x, y, background, zorder=0, **kwargs)
def s_mu_tpcf_patches(tpcf, s_bins, mu_bins, cmap=cm.cool, vmin=None, vmax=None): """ Return a collection of patches that can be used to plot the tpcf in s and mu bins. Parameters ---------- tcpf : np.array numpy array with dimension len(s_bins) by len(mu_bins). This is the output of tpcf_s_mu() s_bins : np.array numpy array of shape (num_s_bin_edges, ) storing the :math:`s` boundaries defining the bins in which pairs are counted. mu_bins : np.array numpy array of shape (num_mu_bin_edges, ) storing the :math:`\cos(\theta_{\rm LOS})` boundaries defining the bins in which pairs are counted. All values must be between [0,1]. cmap : matplotlib.colors.LinearSegmentedColormap object color map to use for coloring the patches vmin : float minimum value of tpcf used to normalize luminance data. Default is min(tpcf). vmax : float maximum value of tpcf used to normalize luminance data. Default is max(tpcf). Returns ------- p : matplotlib.collections.PatchCollection object collection of patches Example ------- For demonstration purposes we create a randomly distributed set of points within a periodic cube of length 250 Mpc/h. >>> Npts = 100 >>> Lbox = 250. >>> x = np.random.uniform(0, Lbox, Npts) >>> y = np.random.uniform(0, Lbox, Npts) >>> z = np.random.uniform(0, Lbox, Npts) We transform our *x, y, z* points into the array shape used by the pair-counter by taking the transpose of the result of `numpy.vstack`. This boilerplate transformation is used throughout the `~halotools.mock_observables` sub-package: >>> sample1 = np.vstack((x,y,z)).T First, we calculate the correlation function using `~halotools.mock_observables.s_mu_tpcf`. >>> from halotools.mock_observables import s_mu_tpcf >>> s_bins = np.linspace(0.01, 25, 10) >>> mu_bins = np.linspace(0, 1, 15) >>> xi_s_mu = s_mu_tpcf(sample1, s_bins, mu_bins, period=Lbox) Get a collection of patches taht represent the tpcf in s and mu bins: >>> p = s_mu_tpcf_patches(xi_s_mu, s_bins, mu_bins) Now, you can plot the tpcf: >>> fig, ax = plt.subplots() >>> ax.add_collection(p) >>> ax.set_xlim([0,25]) >>> ax.set_ylim([0,25]) >>> plt.show() """ #normalize tpcf if vmin is None: min_tpcf = 1.0*np.min(tpcf) else: min_tpcf = vmin if vmax is None: max_tpcf = 1.0*np.max(tpcf) else: max_tpcf = vmax #set values over and under the vmin and vmax values mask = (tpcf>max_tpcf) tpcf[mask] = max_tpcf mask = (tpcf<min_tpcf) tpcf[mask] = min_tpcf #create lists to store wedges and color wedges = [] colors=[] #set center of wedges to be the origin center = (0.0,0.0) #convert to degrees theta_bins = np.degrees(np.arccos(mu_bins)) #change convention to start theta=0.0 on the positive x-axis #instead of the positive y-axis as is the theta_LOS convention theta_bins = 90.0 - theta_bins #loop over s bins for i, (s_low, s_high) in enumerate(zip(s_bins[:-1], s_bins[1:])): #loop over mu_bins for j, (theta_high, theta_low) in enumerate(zip(theta_bins[:-1], theta_bins[1:])): #set radial extent r = s_high dr = s_high-s_low #set angular extent theta1 = theta_high theta2 = theta_low #set color c = 1.0*(tpcf[i,j]-min_tpcf)/max_tpcf #store wedges colors.append(c) wedges.append(Wedge(center, r, theta1, theta2, width=dr)) #create a collection of patches p = PatchCollection(wedges, cmap=cmap) colors = np.array(colors) p.set_array(colors) p.set_linewidth(0.0) return p
class ArrayDisplay: """ Display a top-town view of a telescope array """ def __init__(self, telx, tely, tel_type=None, radius=20, axes=None, title="Array", autoupdate=True): if tel_type is None: tel_type = np.ones(len(telx)) patches = [Rectangle(xy=(x-radius/2, y-radius/2), width=radius, height=radius, fill=False) for x, y in zip(telx, tely)] self.autoupdate = autoupdate self.telescopes = PatchCollection(patches, match_original=True) self.telescopes.set_clim(1, 9) rgb = matplotlib.cm.Set1((tel_type-1)/9) self.telescopes.set_edgecolor(rgb) self.telescopes.set_linewidth(2.0) self.axes = axes if axes is not None else plt.gca() self.axes.add_collection(self.telescopes) self.axes.set_aspect(1.0) self.axes.set_title(title) self.axes.set_xlim(-1000, 1000) self.axes.set_ylim(-1000, 1000) self.axes_hillas = axes if axes is not None else plt.gca() @property def values(self): """An array containing a value per telescope""" return self.telescopes.get_array() @values.setter def values(self, values): """ set the telescope colors to display """ self.telescopes.set_array(values) self._update() def _update(self): """ signal a redraw if necessary """ if self.autoupdate: plt.draw() def add_ellipse(self, centroid, length, width, angle, **kwargs): """ plot an ellipse on top of the camera Parameters ---------- centroid: (float, float) position of centroid length: float major axis width: float minor axis angle: float rotation angle wrt x-axis about the centroid, anticlockwise, in radians asymmetry: float 3rd-order moment for directionality if known kwargs: any MatPlotLib style arguments to pass to the Ellipse patch """ ellipse = Ellipse(xy=centroid, width=length, height=width, angle=np.degrees(angle), fill=True, **kwargs) self.axes.add_patch(ellipse) return ellipse def add_polygon(self, centroid, radius, nsides=3, **kwargs): """ plot a polygon on top of the camera Parameters ---------- centroid: (float, float) position of centroid radius: float radius nsides: int Number of points on polygon kwargs: any MatPlotLib style arguments to pass to the RegularPolygon patch """ polygon = RegularPolygon(xy=centroid, radius=radius, numVertices=nsides, **kwargs) self.axes.add_patch(polygon) return polygon def overlay_moments(self, momparams, tel_position, scale_fac, **kwargs): """helper to overlay ellipse from a `reco.MomentParameters` structure Parameters ---------- momparams: `reco.MomentParameters` structuring containing Hillas-style parameterization tel_position: list (x, y) positions of each telescope scale_fac: float scaling factor to apply to width and length when overlaying moments kwargs: key=value any style keywords to pass to matplotlib (e.g. color='red' or linewidth=6) """ # strip off any units ellipse_list = list() size_list = list() i = 0 for h in momparams: length = u.Quantity(momparams[h].length).value * scale_fac width = u.Quantity(momparams[h].width).value * scale_fac size_list.append(u.Quantity(momparams[h].size).value) tel_x = u.Quantity(tel_position[0][i]).value tel_y = u.Quantity(tel_position[1][i]).value i += 1 ellipse = Ellipse(xy=(tel_x,tel_y), width=length, height=width, angle=np.degrees(momparams[h].psi.rad)) ellipse_list.append(ellipse) patches = PatchCollection(ellipse_list, **kwargs) patches.set_clim(0, 1000) # Set ellipse colour based on image size patches.set_array(np.asarray(size_list)) self.axes_hillas.add_collection(patches) def overlay_axis(self, momparams, tel_position, **kwargs): """helper to overlay ellipse from a `reco.MomentParameters` structure Parameters ---------- momparams: `reco.MomentParameters` structuring containing Hillas-style parameterization tel_position: list (x, y) positions of each telescope kwargs: key=value any style keywords to pass to matplotlib (e.g. color='red' or linewidth=6) """ # strip off any units i = 0 for h in momparams: tel_x = u.Quantity(tel_position[0][i]).value tel_y = u.Quantity(tel_position[1][i]).value psi = u.Quantity(momparams[h].psi).value x_sc = [tel_x - np.cos(psi) * 10000, tel_x + np.cos(psi) * 10000] y_sc = [tel_y - np.sin(psi) * 10000, tel_y + np.sin(psi) * 10000] i += 1 self.axes_hillas.add_line(Line2D(x_sc, y_sc, linestyle='dashed', color='black'))
import sys import numpy as np import matplotlib import matplotlib.pyplot as plt from matplotlib.patches import Polygon from matplotlib.collections import PatchCollection if __name__ == '__main__': data = np.genfromtxt("polygon.txt", delimiter=',') triangle_indices = np.genfromtxt("triangle_indices.txt", delimiter=',') triangle_indices = triangle_indices.astype(int) fig, ax = plt.subplots() patches = [] # Plot polygon convex_polygon = Polygon(data, closed=True) patches.append(convex_polygon) # Plot triangle vertices for i in range(np.size(triangle_indices, 0)): triangle = Polygon(data[triangle_indices[i, :]], closed=True) patches.append(triangle) polygons = PatchCollection(patches, alpha=0.4) polygons.set_facecolor('red') polygons.set_edgecolor('green') polygons.set_linewidth(2) ax.add_collection(polygons) ax.autoscale_view() plt.show()
class ArrayDisplay: """ Display a top-town view of a telescope array. This can be used in two ways: by default, you get a display of all telescopes in the subarray, colored by telescope type, however you can also color the telescopes by a value (like trigger pattern, or some other scalar per-telescope parameter). To set the color value, simply set the `value` attribute, and the fill color will be updated with the value. You might want to set the border color to zero to avoid confusion between the telescope type color and the value color ( `array_disp.telescope.set_linewidth(0)`) To display a vector field over the telescope positions, e.g. for reconstruction, call `set_uv()` to set cartesian vectors, or `set_r_phi()` to set polar coordinate vectors. These both take an array of length N_tels, or a single value. Parameters ---------- subarray: ctapipe.instrument.SubarrayDescription the array layout to display axes: matplotlib.axes.Axes matplotlib axes to plot on, or None to use current one title: str title of array plot tel_scale: float scaling between telescope mirror radius in m to displayed size autoupdate: bool redraw when the input changes radius: Union[float, list, None] set telescope radius to value, list/array of values. If None, radius is taken from the telescope's mirror size. """ def __init__(self, subarray, axes=None, autoupdate=True, tel_scale=2.0, alpha=0.7, title=None, radius=None, frame=GroundFrame()): self.frame = frame self.subarray = subarray # get the telescope positions. If a new frame is set, this will # transform to the new frame. self.tel_coords = subarray.tel_coords.transform_to(frame) # set up colors per telescope type tel_types = [str(tel) for tel in subarray.tels.values()] if radius is None: # set radius to the mirror radius (so big tels appear big) radius = [ np.sqrt(tel.optics.mirror_area.to("m2").value) * tel_scale for tel in subarray.tel.values() ] if title is None: title = subarray.name # get default matplotlib color cycle (depends on the current style) color_cycle = cycle(plt.rcParams['axes.prop_cycle'].by_key()['color']) # map a color to each telescope type: tel_type_to_color = {} for tel_type in list(set(tel_types)): tel_type_to_color[tel_type] = next(color_cycle) tel_color = [tel_type_to_color[ttype] for ttype in tel_types] patches = [] for x, y, r, c in zip(list(self.tel_coords.x.value), list(self.tel_coords.y.value), list(radius), tel_color): patches.append( Circle( xy=(x, y), radius=r, fill=True, color=c, alpha=alpha, )) # build the legend: legend_elements = [] for ttype in list(set(tel_types)): color = tel_type_to_color[ttype] legend_elements.append( Line2D([0], [0], marker='o', color=color, label=ttype, markersize=10, alpha=alpha, linewidth=0)) plt.legend(handles=legend_elements) self.tel_colors = tel_color self.autoupdate = autoupdate self.telescopes = PatchCollection(patches, match_original=True) self.telescopes.set_linewidth(2.0) self.axes = axes or plt.gca() self.axes.add_collection(self.telescopes) self.axes.set_aspect(1.0) self.axes.set_title(title) self._labels = [] self._quiver = None self.axes.autoscale_view() @property def values(self): """An array containing a value per telescope""" return self.telescopes.get_array() @values.setter def values(self, values): """ set the telescope colors to display """ self.telescopes.set_array(values) self._update() def set_vector_uv(self, u, v, c=None, **kwargs): """ sets the vector field U,V and color for all telescopes Parameters ---------- u: array[num_tels] x-component of direction vector v: array[num_tels] y-component of direction vector kwargs: extra args passed to plt.quiver(), ignored on subsequent updates """ if c is None: c = self.tel_colors if self._quiver is None: coords = self.tel_coords self._quiver = self.axes.quiver(coords.x, coords.y, u, v, color=c, **kwargs) else: self._quiver.set_UVC(u, v) def set_vector_rho_phi(self, rho, phi, c=None, **kwargs): """sets the vector field using R, Phi for each telescope Parameters ---------- rho: float or array[float] vector magnitude for each telescope phi: array[Angle] vector angle for each telescope c: color or list of colors vector color for each telescope (or one for all) """ phi = Angle(phi).rad u, v = polar_to_cart(rho, phi) self.set_vector_uv(u, v, c=c, **kwargs) def set_vector_hillas(self, hillas_dict, angle_offset=180 * u.deg): """ helper function to set the vector angle and length from a set of Hillas parameters. Parameters ---------- hillas_dict: Dict[int, HillasParametersContainer] mapping of tel_id to Hillas parameters """ rho = np.zeros(self.subarray.num_tels) * u.m phi = np.zeros(self.subarray.num_tels) * u.deg for tel_id, params in hillas_dict.items(): idx = self.subarray.tel_indices[tel_id] rho[idx] = 1.0 * u.m # params.length phi[idx] = Angle(params.phi) + Angle(angle_offset) self.set_vector_rho_phi(rho=rho, phi=phi) def add_labels(self): px = self.tel_coords.x.value py = self.tel_coords.y.value for tel, x, y in zip(self.subarray.tels, px, py): name = str(tel) lab = self.axes.text(x, y, name, fontsize=8) self._labels.append(lab) def remove_labels(self): for lab in self._labels: lab.remove() self._labels = [] def _update(self): """ signal a redraw if necessary """ if self.autoupdate: plt.draw() def background_contour(self, x, y, background, **kwargs): """ Draw image contours in background of the display, useful when likelihood fitting Parameters ---------- x: ndarray array of image X coordinates y: ndarray array of image Y coordinates background: ndarray Array of image to use in background kwargs: key=value any style keywords to pass to matplotlib """ # use zorder to ensure the contours appear under the telescopes. self.axes.contour(x, y, background, zorder=0, **kwargs)
class ArrayDisplay: """ Display a top-town view of a telescope array. This can be used in two ways: by default, you get a display of all telescopes in the subarray, colored by telescope type, however you can also color the telescopes by a value (like trigger pattern, or some other scalar per-telescope parameter). To set the color value, simply set the `value` attribute, and the fill color will be updated with the value. You might want to set the border color to zero to avoid confusion between the telescope type color and the value color ( `array_disp.telescope.set_linewidth(0)`) To display a vector field over the telescope positions, e.g. for reconstruction, call `set_uv()` to set cartesian vectors, or `set_r_phi()` to set polar coordinate vectors. These both take an array of length N_tels, or a single value. Parameters ---------- subarray: ctapipe.instrument.SubarrayDescription the array layout to display axes: matplotlib.axes.Axes matplotlib axes to plot on, or None to use current one title: str title of array plot tel_scale: float scaling between telescope mirror radius in m to displayed size autoupdate: bool redraw when the input changes radius: Union[float, list, None] set telescope radius to value, list/array of values. If None, radius is taken from the telescope's mirror size. """ def __init__(self, subarray, axes=None, autoupdate=True, tel_scale=2.0, alpha=0.7, title=None, radius=None, frame=GroundFrame()): self.frame = frame self.subarray = subarray # get the telescope positions. If a new frame is set, this will # transform to the new frame. self.tel_coords = subarray.tel_coords.transform_to(frame) # set up colors per telescope type tel_types = [str(tel) for tel in subarray.tels.values()] if radius is None: # set radius to the mirror radius (so big tels appear big) radius = [ np.sqrt(tel.optics.mirror_area.to("m2").value) * tel_scale for tel in subarray.tel.values() ] if title is None: title = subarray.name # get default matplotlib color cycle (depends on the current style) color_cycle = cycle(plt.rcParams['axes.prop_cycle'].by_key()['color']) # map a color to each telescope type: tel_type_to_color = {} for tel_type in list(set(tel_types)): tel_type_to_color[tel_type] = next(color_cycle) tel_color = [tel_type_to_color[ttype] for ttype in tel_types] patches = [] for x, y, r, c in zip(list(self.tel_coords.x.value), list(self.tel_coords.y.value), list(radius), tel_color): patches.append( Circle( xy=(x, y), radius=r, fill=True, color=c, alpha=alpha, )) # build the legend: legend_elements = [] for ttype in list(set(tel_types)): color = tel_type_to_color[ttype] legend_elements.append( Line2D([0], [0], marker='o', color=color, label=ttype, markersize=10, alpha=alpha, linewidth=0)) plt.legend(handles=legend_elements) self.tel_colors = tel_color self.autoupdate = autoupdate self.telescopes = PatchCollection(patches, match_original=True) self.telescopes.set_linewidth(2.0) self.axes = axes or plt.gca() self.axes.add_collection(self.telescopes) self.axes.set_aspect(1.0) self.axes.set_title(title) self._labels = [] self._quiver = None self.axes.autoscale_view() @property def values(self): """An array containing a value per telescope""" return self.telescopes.get_array() @values.setter def values(self, values): """ set the telescope colors to display """ self.telescopes.set_array(values) self._update() def set_vector_uv(self, u, v, c=None, **kwargs): """ sets the vector field U,V and color for all telescopes Parameters ---------- u: array[num_tels] x-component of direction vector v: array[num_tels] y-component of direction vector c: color or list of colors vector color for each telescope (or one for all) kwargs: extra args passed to plt.quiver(), ignored on subsequent updates """ if c is None: c = self.tel_colors if self._quiver is None: coords = self.tel_coords self._quiver = self.axes.quiver(coords.x, coords.y, u, v, color=c, scale_units='xy', angles='xy', scale=1, **kwargs) else: self._quiver.set_UVC(u, v) def set_vector_rho_phi(self, rho, phi, c=None, **kwargs): """sets the vector field using R, Phi for each telescope Parameters ---------- rho: float or array[float] vector magnitude for each telescope phi: array[Angle] vector angle for each telescope c: color or list of colors vector color for each telescope (or one for all) """ phi = Angle(phi).rad u, v = polar_to_cart(rho, phi) self.set_vector_uv(u, v, c=c, **kwargs) def set_vector_hillas(self, hillas_dict, length, time_gradient, angle_offset): """ Function to set the vector angle and length from a set of Hillas parameters. In order to proper use the arrow on the ground, also a dictionary with the time gradients for the different telescopes is needed. If the gradient is 0 the arrow is not plotted on the ground, whereas if the value of the gradient is negative, the arrow is rotated by 180 degrees (Angle(angle_offset) not added). This plotting behaviour has been tested with the timing_parameters function in ctapipe/image. Parameters ---------- hillas_dict: Dict[int, HillasParametersContainer] mapping of tel_id to Hillas parameters length: Float length of the arrow (in meters) time_gradient: Dict[int, value of time gradient (no units)] dictionary for value of the time gradient for each telescope angle_offset: Float This should be the event.mcheader.run_array_direction[0] parameter """ # rot_angle_ellipse is psi parameter in HillasParametersContainer rho = np.zeros(self.subarray.num_tels) * u.m rot_angle_ellipse = np.zeros(self.subarray.num_tels) * u.deg for tel_id, params in hillas_dict.items(): idx = self.subarray.tel_indices[tel_id] rho[idx] = length * u.m if time_gradient[tel_id] > 0.01: params.psi = Angle(params.psi) angle_offset = Angle(angle_offset) rot_angle_ellipse[ idx] = params.psi + angle_offset + 180 * u.deg elif time_gradient[tel_id] < -0.01: rot_angle_ellipse[idx] = params.psi + angle_offset else: rho[idx] = 0 * u.m self.set_vector_rho_phi(rho=rho, phi=rot_angle_ellipse) def set_line_hillas(self, hillas_dict, range, **kwargs): """ Function to plot a segment of length 2*range for each telescope from a set of Hillas parameters. The segment is centered on the telescope position. A point is added at each telescope position for better visualization. Parameters ---------- hillas_dict: Dict[int, HillasParametersContainer] mapping of tel_id to Hillas parameters range: float half of the length of the segments to be plotted (in meters) """ coords = self.tel_coords c = self.tel_colors for tel_id, params in hillas_dict.items(): idx = self.subarray.tel_indices[tel_id] x_0 = coords[idx].x.value y_0 = coords[idx].y.value m = np.tan(Angle(params.psi)) x = x_0 + np.linspace(-range, range, 50) y = y_0 + m * (x - x_0) distance = np.sqrt((x - x_0)**2 + (y - y_0)**2) mask = np.ma.masked_where(distance < range, distance).mask self.axes.plot(x[mask], y[mask], color=c[idx], **kwargs) self.axes.scatter(x_0, y_0, color=c[idx]) def add_labels(self): px = self.tel_coords.x.value py = self.tel_coords.y.value for tel, x, y in zip(self.subarray.tels, px, py): name = str(tel) lab = self.axes.text(x, y, name, fontsize=8, clip_on=True) self._labels.append(lab) def remove_labels(self): for lab in self._labels: lab.remove() self._labels = [] def _update(self): """ signal a redraw if necessary """ if self.autoupdate: plt.draw() def background_contour(self, x, y, background, **kwargs): """ Draw image contours in background of the display, useful when likelihood fitting Parameters ---------- x: ndarray array of image X coordinates y: ndarray array of image Y coordinates background: ndarray Array of image to use in background kwargs: key=value any style keywords to pass to matplotlib """ # use zorder to ensure the contours appear under the telescopes. self.axes.contour(x, y, background, zorder=0, **kwargs)