def plotEllipse(self,barotropic=False,k=0,con='M2',scale=1e4,subsample=4,\ xlims=None,ylims=None,cbarpos=[0.15, 0.15, 0.03, 0.3],**kwargs): """ Plots tidal ellipses on a map """ from matplotlib.collections import EllipseCollection plt.ioff() fig = plt.gcf() ax = fig.gca() iicon = findCon(con,self.frqnames) if self.clim==None: self.clim=[] self.clim.append(np.min(self.Amp)) self.clim.append(np.max(self.Amp)) if xlims==None or ylims==None: xlims=self.xlims ylims=self.ylims ell = self.getEllipse(barotropic=barotropic,k=k,con=con) # Create the ellipse collection indices = range(0,self.Nc,subsample) widths = [ell[0][ii]*scale for ii in indices] heights = [ell[1][ii]*scale for ii in indices] angles = [ell[2][ii]*180.0/np.pi for ii in indices] #angles = [ell[2][ii] for ii in indices] offsets = [(self.xv[ii],self.yv[ii]) for ii in indices] collection = EllipseCollection(widths,heights,angles,units='xy',\ offsets=offsets, transOffset=ax.transData,**kwargs) z=ell[0][indices] collection.set_array(np.array(z)) collection.set_clim(vmin=self.clim[0],vmax=self.clim[1]) collection.set_edgecolors(collection.to_rgba(np.array(z))) ax.set_aspect('equal') ax.set_xlim(xlims) ax.set_ylim(ylims) titlestr='%s - Semi-major Ellipse Amplitude'%(self.frqnames[iicon]) plt.title(titlestr) ax.add_collection(collection) # Add a decent looking colorbar if not cbarpos==None: cbaxes = fig.add_axes(cbarpos) cb = fig.colorbar(collection,cax = cbaxes,orientation='vertical') cb.ax.set_title('[m s$^{-1}$]') plt.sca(ax) #axcb = fig.colorbar(collection) return collection
def display_matrices(ax, grid, texture, scale=None, col=None): """Display on a matplotlib axis an ellipse representing a symmetric matrix at each grid element. Each axis of the ellipse corresponds to an eigenvalue and is oriented along its eigenvector. An axis corresponding to a positive eigenvalue is drawn. A 'coffee bean' has a negative eigenvalue smaller in absolute value than its positive eigenvalue. A 'capsule' has a negative eigenvalue larger in absolute value than its positive eigenvalue. A circle is when the two eigenvalues are equal in absolute value.""" XY = grid.mesh() mask = grid.mask() #convert the texture back to an array of matrices mat = tri2square(texture) #compute egenvalues and eigenvectors of texture for each cell of the grid evalues, evectors = np.linalg.eigh(mat) #width and height are the larger and smaller eigenvalues respectively ww = evalues[..., 1][mask] hh = evalues[..., 0][mask] #angle is given by the angle of the larger eigenvector aa = np.rad2deg(np.arctan2(evectors[..., 1, 1], evectors[..., 0, 1]))[mask] #sum of the eigenvalues (trace of the matrix) trace = ww + hh #np.where(np.abs(ww)>np.abs(hh), ww, hh)#ww*hh #color #if col is None: # if trace.ptp()>0: # col = plt.cm.viridis((trace.ravel() - trace.min())/trace.ptp()) # else: # col = plt.cm.viridis(np.ones_like(trace)) if scale is None: #scale = 1 ellipse_areas = np.pi * np.abs(np.prod(evalues, axis=-1)) rarea = ellipse_areas / grid.areas() scale = np.nanpercentile(np.sqrt(rarea[mask]), 90) if scale == 0: scale = np.nanmax(np.sqrt(rarea[mask])) if scale == 0: raise ValueError("All matrices are null") scale = 1 / scale #show ellipses ec = EllipseCollection( ww * scale, hh * scale, aa, units='xy', offsets=XY, transOffset=ax.transData, edgecolors=col, facecolors='none', ) #major and minor axes (only for positive eigenvalues) xyps = scale * np.transpose( evectors * np.maximum(0, evalues)[..., None, :], (0, 1, 3, 2))[mask].reshape(2 * len(ww), 2) * 0.5 ma = LineCollection([[-xyp, xyp] for xyp in xyps], offsets=np.repeat(XY, 2, axis=0), color=(0.5, 0.5, 0.5)) if col is None: if trace.ptp() > 0: ec.set_array(trace) ma.set_array(trace[mask.ravel()]) else: ec.set_edgecolors(col) ma.set_edgecolors(col) ax.add_collection(ec) ax.add_collection(ma) return ec