def load_files(self, path_hashfile=str, hash_str: str = None): #%% if hash_str is None: hash_str = '{}_a{}_{}_{}'.format(self._name, self.alpha, self.distance_eps, self.min_area_in_degrees2) if path_hashfile is None: path_hashfile = functions_pp.get_download_path() f_name = None for root, dirs, files in os.walk(path_hashfile): for file in files: if re.findall(f'{hash_str}', file): print(f'Found file {file}') f_name = file if f_name is not None: filepath = os.path.join(path_hashfile, f_name) self.ds = core_pp.import_ds_lazy(filepath) self.corr_xr = self.ds['corr_xr'] self.alpha = self.corr_xr.attrs['alpha'] self.FDR_control = bool(self.corr_xr.attrs['FDR_control']) self.precur_arr = self.ds['precur_arr'] # self._tfreq = self.precur_arr.attrs['_tfreq'] if 'prec_labels' in self.ds.variables.keys(): self.prec_labels = self.ds['prec_labels'] self.distance_eps = self.prec_labels.attrs['distance_eps'] self.min_area_in_degrees2 = self.prec_labels.attrs[ 'min_area_in_degrees2'] self.group_lag = bool(self.prec_labels.attrs['group_lag']) self.group_split = bool(self.prec_labels.attrs['group_split']) loaded = True else: print('No file that matches the hash_str or instance settings in ' f'folder {path_hashfile}') loaded = False return loaded
def store_netcdf(self, path: str=None, f_name: str=None, add_hash=True): assert hasattr(self, 'corr_xr'), 'No MI map calculated' if path is None: path = functions_pp.get_download_path() hash_str = uuid.uuid4().hex[:6] if f_name is None: f_name = '{}_a{}'.format(self._name, self.alpha) self.corr_xr.attrs['alpha'] = self.alpha self.corr_xr.attrs['FDR_control'] = int(self.FDR_control) self.corr_xr['lag'] = ('lag', range(self.lags.shape[0])) if 'mask' in self.precur_arr.coords: self.precur_arr = self.precur_arr.drop('mask') # self.precur_arr.attrs['_tfreq'] = int(self._tfreq) if hasattr(self, 'prec_labels'): self.prec_labels['lag'] = self.corr_xr['lag'] # must be same self.prec_labels.attrs['distance_eps'] = self.distance_eps self.prec_labels.attrs['min_area_in_degrees2'] = self.min_area_in_degrees2 self.prec_labels.attrs['group_lag'] = int(self.group_lag) self.prec_labels.attrs['group_split'] = int(self.group_split) if f_name is None: f_name += '_{}_{}'.format(self.distance_eps, self.min_area_in_degrees2) ds = xr.Dataset({'corr_xr':self.corr_xr, 'prec_labels':self.prec_labels, 'precur_arr':self.precur_arr}) else: ds = xr.Dataset({'corr_xr':self.corr_xr, 'precur_arr':self.precur_arr}) if add_hash: f_name += f'_{hash_str}' self.filepath_experiment = os.path.join(path, f_name+ '.nc') ds.to_netcdf(self.filepath_experiment) print(f'Dataset stored with hash: {hash_str}')
verticalalignment='top', bbox=props) ax1.tick_params(which='y', labelsize=18) fig.suptitle('Probabilistic forecast of temperature events', y=0.96, fontsize=20, fontweight='bold') png1 = BytesIO() dpi = 300 fig.savefig(png1, format='png', dpi=dpi, bbox_inches='tight') fig.savefig(png1, format='png', dpi=dpi, bbox_inches='tight') png2 = Image.open(png1) png2.save( os.path.join(functions_pp.get_download_path(), f'BSS_vs_AUC_{dpi}dpi.tif')) png1.close() #%% # # skill versus threshold # metrics_cols = ['BSS', 'AUC_SS'] # colors = ['blue', 'green'] ; lstyles = ['solid', 'dashed'] # rename_m = {'roc_auc_score': 'AUC', 'BSS':'BSS', 'AUC_SS':'AUC-ROC-SS'} # for i, m in enumerate(metrics_cols): # ss = [d[q].reorder_levels((1,0), axis=1).loc[0][m].loc[plotlag] for q in qrange] # ax2.plot(qrange, ss, label=rename_m[m], c=colors[i], ls=lstyles[i]) # ax2.legend(loc='upper center') # for i, m in enumerate(metrics_cols): # c_sc = [c1 if q in [.90] else colors[i] for q in qrange] # c_sc[np.argwhere(np.array(qrange)==.66)[0][0]] = c2
def plot_HM(self, main_title_right: str=None, ytickstep=5, lattickstep: int=3, clevels: np.ndarray=None, clim: Union[str, tuple]='relaxed', cmap=None, drawbox: list=None, save: bool=False, height_ratios: list=[1,6], fontsize: int=14, alpha: float=.05, lag_composite: int=0, fig_path: str=None): #%% # main_title_right=None; ytickstep=5; lattickstep=3; height_ratios=[1,6] # clevels=None; clim='relaxed' ; cmap=None; drawbox=None; fontsize=14; # alpha=.05; lag_composite=0 # Get times and make array of datetime objects if self.event_dates is not None: vtimes = self.xr_HM.lag.values else: vtimes = self.xr_HM.time.values.astype('datetime64[ms]').astype('O') if cmap is None: cmap = plt.cm.RdBu_r # Start figure fig = plt.figure(figsize=(10, 13)) # Use gridspec to help size elements of plot; small top plot and big bottom plot gs = gridspec.GridSpec(nrows=2, ncols=1, height_ratios=height_ratios, hspace=0.03) # Tick labels dim = [d for d in self.xr_HM.dims if d != 'lag'][0] if dim == 'longitude': x_tick_labels = [u'0\N{DEGREE SIGN}E', u'90\N{DEGREE SIGN}E', u'180\N{DEGREE SIGN}E', u'90\N{DEGREE SIGN}W', u'0\N{DEGREE SIGN}E'] elif dim == 'latitude': x_ticks = np.unique(np.round(self.xarray.latitude.values.astype(int), -1)) x_tick_labels = [u'{}\N{DEGREE SIGN}N'.format(coord) for coord in x_ticks] # Plot of chosen variable averaged over latitude and slightly smoothed if clevels is None: class MidpointNormalize(mcolors.Normalize): def __init__(self, vmin=None, vmax=None, midpoint=None, clip=False): self.midpoint = midpoint mcolors.Normalize.__init__(self, vmin, vmax, clip) def __call__(self, value, clip=None): # I'm ignoring masked values and all kinds of edge cases to make a # simple example... x, y = [self.vmin, self.midpoint, self.vmax], [0, 0.5, 1] return np.ma.masked_array(np.interp(value, x, y)) if clim == 'relaxed': vmin_ = np.nanpercentile(self.xr_HM, 1) ; vmax_ = np.nanpercentile(self.xr_HM, 99) elif type(clim) == tuple: vmin_, vmax_ = clim else: vmin_ = self.xr_HM.min()-0.01 ; vmax_ = self.xr_HM.max()+0.01 vmin = np.round(float(vmin_),decimals=2) ; vmax = np.round(float(vmax_),decimals=2) clevels = np.linspace(-max(abs(vmin),vmax),max(abs(vmin),vmax),17) # choose uneven number for # steps norm = MidpointNormalize(midpoint=0, vmin=clevels[0],vmax=clevels[-1]) ticksteps = 4 else: vmin_ = np.nanpercentile(self.xr_HM, 1) ; vmax_ = np.nanpercentile(self.xr_HM, 99) vmin = np.round(float(vmin_),decimals=2) ; vmax = np.round(float(vmax_),decimals=2) clevels=clevels norm=None ticksteps = 1 # Top plot for geographic reference (makes small map) ax1 = fig.add_subplot(gs[0, 0], projection=ccrs.PlateCarree(central_longitude=180)) selbox = list(self.kwrgs_load['selbox']) ; selbox[1] = selbox[1]-.1 # Add geopolitical boundaries for map reference ax1.add_feature(cfeature.COASTLINE.with_scale('50m')) ax1.add_feature(cfeature.LAKES.with_scale('50m'), color='black', linewidths=0.5) xr_events = self.xarray.sel(lag=lag_composite).mean(dim='lag') lon = xr_events.longitude if abs(lon[-1] - 360) <= (lon[1] - lon[0]): xr_events = plot_maps.extend_longitude(xr_events) # xr_events = core_pp.convert_longitude(xr_events, to_format='west_east') xr_events.plot.contourf(levels=clevels, cmap=cmap, transform=ccrs.PlateCarree(), ax=ax1, add_colorbar=False) ax1.set_extent(selbox, ccrs.PlateCarree(central_longitude=180)) y_ticks = np.unique(np.round(xr_events.latitude, decimals=-1))[::lattickstep] ax1.set_yticks(y_ticks.astype(int)) ax1.set_yticklabels([u'{:.0f}\N{DEGREE SIGN}N'.format(l) for l in y_ticks], fontdict={'fontsize':fontsize-2}) ax1.set_ylabel('Latitude', fontdict={'fontsize':fontsize}) # ax1.set_xticks([-180, -90, 0, 90, 180]) # ax1.set_xticklabels(x_tick_labels) ax1.grid(linestyle='dotted', linewidth=2) if self.zoomdim is not None: xmin = float(min(self.xr_HM[dim])) xmax = float(max(self.xr_HM[dim])) ax1.hlines(self.zoomdim[0], xmin, xmax, transform=ccrs.PlateCarree()) ax1.hlines(self.zoomdim[1], xmin, xmax, transform=ccrs.PlateCarree()) # ============================================================================= # Draw (rectangular) box # ============================================================================= if drawbox is not None: def get_ring(coords): '''tuple in format: west_lon, east_lon, south_lat, north_lat ''' west_lon, east_lon, south_lat, north_lat = coords lons_sq = [west_lon, west_lon, east_lon, east_lon] lats_sq = [north_lat, south_lat, south_lat, north_lat] ring = [LinearRing(list(zip(lons_sq , lats_sq )))] return ring ring = get_ring(drawbox) ax1.add_geometries(ring, ccrs.PlateCarree(), facecolor='none', edgecolor='green', linewidth=2, linestyle='dashed') # Set some titles title = f'Composite mean of {self.event_dates.size} events at lag={lag_composite}' plt.title(title, loc='left') if main_title_right is not None: plt.title(main_title_right, loc='right', fontdict={'fontsize':fontsize}) # Bottom plot for Hovmoller diagram ax2 = fig.add_subplot(gs[1, 0]) ax2.invert_yaxis() # Reverse the time order to do oldest first ax2.hlines(y=0, xmin=0, xmax=357.5, linewidth=1) cf = self.xr_HM.plot.contourf(levels=clevels, cmap=cmap, ax=ax2, add_colorbar=False) self.xr_HM.plot.contour(clevels=clevels, colors='k', linewidths=1, ax=ax2) # stippling significance if self.t_test: self.xr_mask.plot.contourf(ax=ax2, levels=[0, alpha, 1], hatches=['...', ''], colors='none', add_colorbar=False) cbar = plt.colorbar(cf, orientation='horizontal', pad=0.04, aspect=50, extendrect=True, norm=norm, ticks=clevels[::ticksteps]) cbar.ax.tick_params(labelsize=fontsize) if hasattr(self, 'units'): cbar.set_label(self.units) # Make some ticks and tick labels ax2.set_xticks([0, 90, 180, 270, 357.5]) ax2.set_xticklabels(x_tick_labels, fontdict={'fontsize':fontsize - 2}) ax2.set_xlabel('') if self.event_dates is not None: y_ticks = list(vtimes[::ytickstep]) ; #y_ticks.append(vtimes[-1]) ax2.set_yticks(y_ticks) ax2.set_yticklabels(y_ticks, fontdict={'fontsize':fontsize}) ax2.set_ylabel('lag [in days]', fontdict={'fontsize':fontsize}) ax2.grid(linestyle='dotted', linewidth=2) # Set some titles if self.name is not None: plt.title(self.name, loc='left', fontsize=fontsize) if self.slice_dates != None: plt.title('Time Range: {0:%Y%m%d %HZ} - {1:%Y%m%d %HZ}'.format(vtimes[0], vtimes[-1]), loc='right', fontsize=fontsize) if save or fig_path is not None: fname = '_'.join(np.array(self.kwrgs_load['selbox']).astype(str)) + \ f'_w{self.rollingmeanwindow}_std{self.standardize}' fname = self.name + '_' + fname if fig_path is None: fig_path = os.path.join(functions_pp.get_download_path(), fname) plt.savefig(fig_path, bbox_inches='tight')