예제 #1
0
 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
예제 #2
0
    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}')
예제 #3
0
         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
예제 #4
0
    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')