def get_PDO(sst_Pacific): #%% from eofs.xarray import Eof # PDO = functions_pp.find_region(sst, region='PDO')[0] coslat = np.cos(np.deg2rad(sst_Pacific.coords['latitude'].values)).clip( 0., 1.) area_weights = np.tile(coslat[..., np.newaxis], (1, sst_Pacific.longitude.size)) area_weights = area_weights / area_weights.mean() solver = Eof(sst_Pacific, area_weights) # Retrieve the leading EOF, expressed as the correlation between the leading # PC time series and the input SST anomalies at each grid point, and the # leading PC time series itself. eof1 = solver.eofsAsCovariance(neofs=1).squeeze() PDO_warmblob = eof1.sel(latitude=slice(30, 40)).sel( longitude=slice(180, 200)).mean() # flip sign oef pattern and ts assert ~np.isnan( PDO_warmblob), 'Could not verify sign of PDO, check lat lon axis' init_sign = np.sign(PDO_warmblob) if init_sign != -1.: adjust_sign = -1 else: adjust_sign = 1 eof1 *= adjust_sign return eof1, solver, adjust_sign
def _get_EOF_xarray(ds_EOF, neofs): from eofs.xarray import Eof coslat = np.cos(np.deg2rad(ds_EOF.coords['latitude'].values)).clip(0., 1.) area_weights = np.tile(coslat[..., np.newaxis],(1,ds_EOF.longitude.size)) area_weights = area_weights / area_weights.mean() solver = Eof(ds_EOF, area_weights) eofs = solver.eofsAsCovariance(neofs=neofs).squeeze() return eofs, solver
def EOF_SST_analysis(xa, weights, neofs=1, npcs=1, fn=None): """ Empirical Orthogonal Function of SST(t,x,y) field """ assert type(xa) == xr.core.dataarray.DataArray assert type(weights) == xr.core.dataarray.DataArray assert 'time' in xa.dims assert np.shape(xa[0, :, :]) == np.shape(weights) # anomalies by removing time mean xa = xa - xa.mean(dim='time') # Retrieve the leading EOF, expressed as the covariance between the leading PC # time series and the input xa anomalies at each grid point. solver = Eof(xa, weights=weights) eofs = solver.eofsAsCovariance(neofs=neofs) pcs = solver.pcs(npcs=npcs, pcscaling=1) if fn != None: xr.merge([eofs, pcs]).to_netcdf(fn) return eofs, pcs
def EOF_SST_analysis(self, xa, weights, n=1, fn=None): """ Empirical Orthogonal Function analysis of SST(t,x,y) field; from `SST.py` """ assert type(xa)==xr.core.dataarray.DataArray assert type(weights)==xr.core.dataarray.DataArray assert 'time' in xa.dims assert np.shape(xa[0,:,:])==np.shape(weights) # anomalies by removing time mean xa = xa - xa.mean(dim='time') # Retrieve the leading EOF, expressed as the covariance between the leading PC # time series and the input xa anomalies at each grid point. solver = Eof(xa, weights=weights) eofs = solver.eofsAsCovariance(neofs=n) pcs = solver.pcs(npcs=n, pcscaling=1) eigs = solver.eigenvalues(neigs=n) varF = solver.varianceFraction(neigs=n) ds = xr.merge([eofs, pcs, eigs, varF]) if fn!=None: ds.to_netcdf(fn) return ds
def operate(self, vid: str, variable: xa.DataArray) -> Dict[str, xa.DataArray]: """ Convenience method defined for this particular operation """ opSpecs = self.request['operation'] result_arrays: Dict[str, xa.DataArray] = {} for opSpec in opSpecs: opId = opSpec['name'].split(':')[1] opAxis = opSpec['axis'] coslat = np.cos(np.deg2rad(variable.coords['latitude'].values)) wgts = np.sqrt(coslat)[..., np.newaxis] solver = Eof(variable, weights=wgts) if opId == "correlation": result_arrays = solver.eofsAsCorrelation(neofs=1) elif opId == "covariance": result_arrays = solver.eofsAsCovariance(neofs=1) else: raise Exception(f"Unknown operation for EOF: '{opId}'") return result_arrays
# Read geopotential height data using the xarray module. The file contains # December-February averages of geopotential height at 500 hPa for the # European/Atlantic domain (80W-40E, 20-90N). filename = example_data_path('hgt_djf.nc') z_djf = xr.open_dataset(filename)['z'] # Compute anomalies by removing the time-mean. z_djf = z_djf - z_djf.mean(dim='time') # Create an EOF solver to do the EOF analysis. Square-root of cosine of # latitude weights are applied before the computation of EOFs. coslat = np.cos(np.deg2rad(z_djf.coords['latitude'].values)).clip(0., 1.) wgts = np.sqrt(coslat)[..., np.newaxis] solver = Eof(z_djf, weights=wgts) # Retrieve the leading EOF, expressed as the covariance between the leading PC # time series and the input SLP anomalies at each grid point. eof1 = solver.eofsAsCovariance(neofs=1) # Plot the leading EOF expressed as covariance in the European/Atlantic domain. clevs = np.linspace(-75, 75, 11) proj = ccrs.Orthographic(central_longitude=-20, central_latitude=60) ax = plt.axes(projection=proj) ax.coastlines() ax.set_global() eof1[0, 0].plot.contourf(ax=ax, levels=clevs, cmap=plt.cm.RdBu_r, transform=ccrs.PlateCarree(), add_colorbar=False) ax.set_title('EOF1 expressed as covariance', fontsize=16) plt.show()
time-mean) will be removed prior to analysis. If *False*, the mean along the first axis will not be removed. Defaults to *True* (mean is removed). The covariance interpretation relies on the input data being anomaly data with a time-mean of 0. Therefore this option should usually be set to *True*. Setting this option to *True* has the useful side effect of propagating missing values along the time dimension, ensuring that a solution can be found even if missing values occur in different locations at different times. ''' lambdas = solver.eigenvalues() vf = solver.varianceFraction() Nerror = solver.northTest(vfscaled=True) pcs = solver.pcs() #(time, mode) eofs = solver.eofsAsCovariance() ''' plt.figure() plt.subplot(3,2,1) pcs[:, 0].plot()#color='b', linewidth=2) ax = plt.gca() ax.axhline(0, color='k') ax.set_xlabel('Year') ax.set_ylabel('PC1 amplitude') plt.grid() plt.subplot(3,2,2) pcs[:, 1].plot() ax = plt.gca() ax.axhline(0, color='k') ax.set_xlabel('Year') ax.set_ylabel('PC2 amplitude')
def calcEOF(xrdata, data_var, w, wei=True): """ input: xrdata: xarray Dataset data_var: string. Variable name to use on EOF. w: string. variable for using weights. E.g. latitude use as: solver, eof1, var1 = calcEOF(xrdata, 'data_var') """ xrdata = xrdata - xrdata[data_var].mean(dim="time") # Testing if we can select data from level, lat and time try: xrdata = xrdata.sel(level=1000, latitude=slice(90, 20), time=slice("1979-01-01", "2000-12-31")) print( 'Data selection OK on first try. Level, lat and time slice done.') except ValueError: try: print('valueError: Trying next') xrdata = xrdata.sel(level=1000, lat=slice(90, 20), time=slice("1979-01-01", "2000-12-31")) print( 'Data selection OK on second try. Level, lat and time slice done.' ) except ValueError: try: print('valueError: Trying next') xrdata = xrdata.sel(latitude=slice(90, 20), time=slice("1979-01-01", "2000-12-31")) print('Data selection OK on third try. No level cut') except ValueError: try: print('valueError: Trying next') xrdata = xrdata.sel(time=slice("1979-01-01", "2000-12-31")) print('Data selection OK on fourth try. Only time slice.') except: raise TypeError(' Data out of limits') xrdata = (xrdata.groupby('time.month') - xrdata[data_var].groupby('time.month').mean()) # To ensure equal area weighting for the covariance matrix, # the gridded data is weighted by the square root of the cosine of # latitude. - NOAA if wei == True: coslat = np.cos(np.deg2rad(xrdata.coords[w].values)).clip(0., 1.) # np.newaxis add a dimention to wgts. dont know what ... does # i think its like a transposed. It took all the objects on a list and # make a new list with lists inside (each list with only one object) # just an adjustment of format wgts = np.sqrt(coslat)[..., np.newaxis] # The EOF analysis is handled by a solver class, and the EOF solution # is computed when the solver class is created. Method calls are then used # to retrieve the quantities of interest from the solver class. # center = False do not remove mean from data # solver = Eof(m_anomalie.hgt, weights=wgts, center=False) """ # solver.eofAsCovariance Returns the EOFs expressed as the covariance between each PC and the input # data set at each point in space. they are not actually the EOFs. They tell you how each point in space # varies like the given mode. The eofs method provides the raw EOFs (eigenvectors of the covariance # matrix) which are the spatial patterns the PCs are the coefficeints of. # “The covariance matrix is used for the EOF analysis.” - NOAA """ solver = Eof(xrdata[data_var], weights=wgts) else: solver = Eof(xrdata[data_var]) # solver = Eof(s_anomalie.hgt, weights=wgts, center=False) # Retrieve the leading EOF, expressed as the covariance between the leading PC # time series and the input SLP anomalies at each grid point. eof1 = solver.eofsAsCovariance(pcscaling=1) var1 = solver.varianceFraction().sel(mode=0) return solver, eof1, var1
def eof_orca_latlon_box(run, var, modes, lon_bnds, lat_bnds, pathfile, plot, time, eoftype): if (var == 'temp'): key = 'votemper' key1 = "votemper" elif (var == 'sal'): key = 'vosaline' key1 = "vosaline" elif (var == 'MLD'): key = 'somxl010' key1 = "somxl010" # read data ds = xr.open_dataset(pathfile) #ds["time_counter"] = ds['time_counter']+(np.datetime64('0002-01-01')-np.datetime64('0001-01-01')) if time == 'comparison': ds = ds.sel(time_counter=slice('1958-01-01', '2006-12-31')) # cut box for EOF at surface if var == 'MLD': data = ds[key].sel(lon=slice(lon_bnds[0], lon_bnds[1]), lat=slice(lat_bnds[0], lat_bnds[1])) #data = cut_latlon_box(ds[key][:,:,:],ds.lon,ds.lat, # lon_bnds,lat_bnds) else: data = ds[key][:, 0, :, :].sel(lon=slice(lon_bnds[0], lon_bnds[1]), lat=slice(lat_bnds[0], lat_bnds[1])) #data = cut_latlon_box(ds[key][:,0,:,:],ds.lon,ds.lat, # lon_bnds,lat_bnds) data = data.to_dataset() # detrend data data[key1] = (['time_counter', 'lat', 'lon'], signal.detrend(data[key].fillna(0), axis=0, type='linear')) #data=data.where(data!=0) # remove seasonal cycle and drop unnecessary coordinates if 'time_centered' in list(data.coords): data = deseason_month(data).drop('month').drop( 'time_centered') # somehow pca doesn't work otherwise else: data = deseason_month(data).drop( 'month') # somehow pca doesn't work otherwise # set 0 values back to nan data = data.where(data != 0) # EOF analysis #Square-root of cosine of latitude weights are applied before the computation of EOFs. coslat = np.cos(np.deg2rad(data['lat'].values)) coslat, _ = np.meshgrid(coslat, np.arange(0, len(data['lon']))) wgts = np.sqrt(coslat) solver = Eof(data[key], weights=wgts.transpose()) pcs = solver.pcs(npcs=modes, pcscaling=1) if eoftype == 'correlation': eof = solver.eofsAsCorrelation(neofs=modes) elif eoftype == 'covariance': eof = solver.eofsAsCovariance(neofs=modes) else: eof = solver.eofs(neofs=modes) varfr = solver.varianceFraction(neigs=4) print(varfr) #----------- Plotting -------------------- plt.close("all") if plot == 1: for i in np.arange(0, modes): fig = plt.figure(figsize=(8, 2)) ax1 = fig.add_axes([0.1, 0.1, 0.3, 0.9], projection=ccrs.PlateCarree()) # main axes ax1.set_extent( (lon_bnds[0], lon_bnds[1], lat_bnds[0], lat_bnds[1])) # discrete colormap cmap = plt.get_cmap('RdYlBu', len(np.arange(10, 30)) - 1) #inferno similar to cmo thermal eof[i, :, :].plot(ax=ax1, cbar_kwargs={'label': 'Correlation'}, transform=ccrs.PlateCarree(), x='lon', y='lat', add_colorbar=True, cmap=cmap) gl = map_stuff(ax1) gl.xlocator = mticker.FixedLocator([100, 110, 120]) gl.ylocator = mticker.FixedLocator(np.arange(-35, -10, 5)) plt.text(116, -24, str(np.round(varfr[i].values, decimals=2)), horizontalalignment='center', verticalalignment='center', transform=ccrs.PlateCarree(), fontsize=8) ax2 = fig.add_axes([0.5, 0.1, 0.55, 0.9]) # main axes plt.plot(pcs.time_counter, pcs[:, i].values, linewidth=0.1, color='k') anomaly(ax2, pcs.time_counter.values, pcs.values[:, i], [0, 0]) ax2.set_xlim( [pcs.time_counter[0].values, pcs.time_counter[-1].values]) plt.savefig(pathplots + 'eof_as' + eoftype + '_mode' + str(i) + '_' + time + '_' + run + '_' + var + '.png', dpi=300, bbox_inches='tight', pad_inches=0.1) plt.show() #---------------------------------------------- return pcs, eof, varfr