def map_lakepct(var, lon, lat, levels, title_str, clrmap, fig_name, alone=True, ax=False): # figure creation if alone: fig, ax = plt.subplots(1, 1, figsize=(13, 8), subplot_kw={'projection': ccrs.PlateCarree()}) ax.add_feature(ctp.feature.OCEAN, color='gainsboro') ax.coastlines(color='darkgrey') #ax.coastlines(color="grey") LON, LAT = mpu.infer_interval_breaks(lon, lat) # add the data to the map (more info on colormaps: https://matplotlib.org/users/colormaps.html) cmap, norm = mpu.from_levels_and_cmap(levels, clrmap) # do not show zeros var[var == 0] = np.nan cmap.set_over(cmap(0.99)) h = ax.pcolormesh(LON, LAT, var, cmap=cmap, norm=norm) # set the extent of the cartopy geoAxes to "global" ax.set_global() ax.set_title(title_str, pad=10, loc='right') # remove the frame ax.outline_patch.set_visible(False) # plot the colorbar cbar = mpu.colorbar(h, ax, orientation='horizontal', pad=0.1, extend='max') cbar.ax.set_xlabel('Natural lake area fraction [%]', size=16) cbar.set_ticks(np.arange(0, 110, 10)) # horizontal colorbar #cbar.ax.set_xticklabels(['Low', 'Medium', 'High']) # horizontal colorbar # if so, save the figure if fig_name != 0 and alone: plt.savefig(fig_name + '.jpeg', dpi=1000, bbox_inches='tight')
def plot_region_hc_map(var, region_props, lakes_path, indir_lakedata): # get region specific info from dictionary extent = region_props['extent'] continent_extent = region_props['continent_extent'] name = region_props['name'] name_str = region_props['name_str'] ax_location = region_props['ax_location'] levels = region_props['levels'] fig_size = region_props['fig_size'] cb_orientation = region_props['cb_orientation'] path_lakes = lakes_path + name + '.shp' # settings clb_label = 'Joule' title_str = name_str + ' heat content anomaly' fig_name = 'Heat_content_' + name cmap = 'YlOrBr' cmap, norm = mpu.from_levels_and_cmap(levels, cmap, extend='max') lon, lat = get_lonlat(indir_lakedata) LON, LAT = mpu.infer_interval_breaks(lon, lat) lakes = gpd.read_file(path_lakes) # plotting fig, ax = plt.subplots(1, 1, figsize=fig_size, subplot_kw={'projection': ccrs.PlateCarree()}) ax.add_feature(ctp.feature.OCEAN, color='gainsboro') ax.coastlines(color="grey") # add the data to the map (more info on colormaps: https://matplotlib.org/users/colormaps.html) h = ax.pcolormesh(LON, LAT, var, cmap=cmap, norm=norm) # load the lake shapefile lakes.plot(ax=ax, edgecolor='gray', facecolor='none') # set grid lines gl = ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=True, linewidth=0.5, color='gainsboro', alpha=0.5) gl.xlines = True gl.xformatter = LONGITUDE_FORMATTER gl.yformatter = LATITUDE_FORMATTER gl.xlabels_bottom = None gl.ylabels_right = None # set extent (in right way) extent[1], extent[2] = extent[2], extent[1] ax.set_extent(extent) # create effect for map borders: effect = Stroke(linewidth=1.5, foreground='darkgray') # set effect for main ax ax.outline_patch.set_path_effects([effect]) # Create an inset GeoAxes showing the location of the lakes region #x0 y0 width height sub_ax = fig.add_axes(ax_location, projection=ccrs.PlateCarree()) sub_ax.set_extent(continent_extent) #lakes.plot(ax=sub_ax) sub_ax.outline_patch.set_path_effects([effect]) extent_box = sgeom.box(extent[0], extent[2], extent[1], extent[3]) sub_ax.add_geometries([extent_box], ccrs.PlateCarree(), facecolor='none', edgecolor='red', linewidth=2) # Add the land, coastlines and the extent of the inset axis sub_ax.add_feature(cfeature.LAND, edgecolor='gray') sub_ax.coastlines(color='gray') extent_box = sgeom.box(extent[0], extent[2], extent[1], extent[3]) sub_ax.add_geometries([extent_box], ccrs.PlateCarree(), facecolor='none', edgecolor='black', linewidth=2) # plot the colorbar cbar = mpu.colorbar(h, ax, extend='max', orientation=cb_orientation, pad=0.05) if cb_orientation == 'vertical': cbar.ax.set_ylabel(clb_label, size=16) elif cb_orientation == 'horizontal': cbar.ax.set_xlabel(clb_label, size=16) #ax.set_title(title_str, pad=10) plotdir = '/home/inne/documents/phd/data/processed/isimip_lakeheat/plots/' plt.savefig(plotdir + fig_name + '.png', dpi=500)
def plot_global_hc_map(name_str, var, lakes_path, indir_lakedata): # get region specific info from dictionary if name_str == 'global_absolute': levels = np.arange(-1e17, 1.1e17, 0.1e17) elif name_str == 'global': levels = np.arange(-1e19, 1.1e19, 0.1e19) cb_orientation = 'horizontal' path_lakes = lakes_path + name_str + '.shp' # settings clb_label = 'Joule' title_str = name_str + ' heat content anomaly' fig_name = 'Heat_content_' + name_str cmap = 'RdBu_r' #, 'YlOrBr' cmap, norm = mpu.from_levels_and_cmap(levels, cmap, extend='max') lon, lat = get_lonlat(indir_lakedata) LON, LAT = mpu.infer_interval_breaks(lon, lat) # plotting fig, ax = plt.subplots(1, 1, figsize=(13, 8), subplot_kw={'projection': ccrs.PlateCarree()}) ax.add_feature(ctp.feature.OCEAN, color='gainsboro') ax.coastlines(color="grey") # add the data to the map (more info on colormaps: https://matplotlib.org/users/colormaps.html) h = ax.pcolormesh(LON, LAT, var, cmap=cmap, norm=norm) # set grid lines gl = ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=True, linewidth=0.5, color='gainsboro', alpha=0.5) gl.xlines = True gl.xformatter = LONGITUDE_FORMATTER gl.yformatter = LATITUDE_FORMATTER gl.xlabels_bottom = None gl.ylabels_right = None effect = Stroke(linewidth=1.5, foreground='darkgray') # set effect for main ax ax.outline_patch.set_path_effects([effect]) # plot the colorbar cbar = mpu.colorbar(h, ax, extend='max', orientation=cb_orientation, pad=0.05) if cb_orientation == 'vertical': cbar.ax.set_ylabel(clb_label, size=16) elif cb_orientation == 'horizontal': cbar.ax.set_xlabel(clb_label, size=16) #ax.set_title(title_str, pad=10) plotdir = '/home/inne/documents/phd/data/processed/isimip_lakeheat/plots/' plt.savefig(plotdir + fig_name + '.png')
def load_data_single_mod(gen,model,scenario,Tanglob_idx=False,Tref_all=True,Tref_start='1870-01-01',Tref_end='1900-01-01',usr_time_res="ann",var='tas'): """ Load the all initial-condition members of a single model in cmip5 or cmip6 for given scenario plus associated historical period. Keyword argument: - gen: generation (cmip5 = 5 and cmip6 = 6 are implemented) - model: model str - scenario: scenario str - Tanglob_idx: decides if wgt Tanglob is computed (and returned) or not, default is not returned - Tref_all: decides if the Tref at each grid point is dervied based on all available runs or not, default is yes - Tref_start: starting point for the reference period with default 1870 - Tref_end: first year to no longer be included in reference period with default 1900 Output: - y: the land grid points of the anomalies of the variable on grid centered over 0 longitude (like the srexgrid) - time: the time slots - srex: the gridded srex regions - df_srex: data frame containing the shape files of the srex regions - lon_pc: longitudes for pcolormesh (needs 1 more than on grid) - lat_pc: latitudes for pcolormesh (needs 1 more than on grid) - idx_l: array with 0 where sea, 1 where land (assumption: land if frac land > 0) - wgt_l: land grid point weights to derive area weighted mean vars - Tan_wgt_globmean = area weighted global mean temperature """ # the dictionaries are NOT ordered properly + some other adjustments -> will need to be careful with my old scripts # see e-mail from Verena on 20191112 for additional infos how could read in several files at once with xarr # additionally: she transforms dataset into dataarray to make indexing easier -> for consistency reason with earlier # version of emulator (& thus to be able to reuse my scripts), I do not do this (fow now). # right now I keep reloading constants fields for each run I add -> does not really make sense. # Maybe add boolean to decide instead. however they are small & I have to read them in at some point anyways # -> maybe path of least resistence is to not care about it print('start with model',model) # vars which used to be part of the inputs but did not really make sense as I employ the same ones all the time anyways (could be changed later if needed) #var='tas' temp_res = usr_time_res # if not, reading the var file needs to be changed as time var is not named in the same way anymore spatial_res = 'g05' # load in the constants files dir_data = '/net/so4/landclim/snath/data/' file_ls = 'interim_invariant_lsmask_regrid_g05.nc' # ERA-interim mask regridded by Richard from 73x144 to 72x144 file_srex = 'srex-region-masks_20120709.srex_mask_SREX_masks_all.50deg.time-invariant.nc' file_srex_shape = 'referenceRegions.shp' #df_all_regs = geopandas.read_file(dir_data+file_srex_shape) srex_names = ['ALA','CGI','WNA','CNA','ENA','CAM','AMZ','NEB','WSA','SSA','NEU','CEU','MED','SAH','WAF','EAF','SAF', 'NAS','WAS','CAS','TIB','EAS','SAS','SEA','NAU','SAU'] # SREX names ordered according to SREX mask I am # employing #df_srex = df_all_regs.loc[df_all_regs['LAB'].isin(srex_names)] # alternative indexing: search in column LAB for names srex_raw = xr.open_mfdataset(dir_data+file_srex, combine='by_coords',decode_times=False) # srex_raw nrs from 1-26 #df_srex=srex_raw #srex_raw["time"]=pd.to_datetime(srex_raw.time.values) frac_l = xr.open_mfdataset(dir_data+file_ls, combine='by_coords',decode_times=False) #land-sea mask of ERA-interim bilinearily interpolated lons, lats = np.meshgrid(frac_l.longitude.values,frac_l.latitude.values) # the lon, lat grid (just to derive weights) #frac_1["time"]=pd.to_datetime(frac_1.time.values) frac_l = frac_l.where(frac_l.latitude>-60,0) # remove Antarctica from frac_l field (ie set frac l to 0) idx_l=np.squeeze(frac_l.lsm.values)>0.0 # idex land #-> everything >0 I consider land wgt = norm_cos_wgt(lats) # area weights of each grid point wgt_l = wgt[idx_l] # area weights for land grid points lon_pc, lat_pc = mpu.infer_interval_breaks(frac_l.longitude, frac_l.latitude) # the lon / lat for the plotting with pcolormesh srex=(np.squeeze(srex_raw.srex_mask.values)-1)[idx_l] # srex indices on land y={} T_ref = np.zeros([36,72]) run_nrs={} if Tanglob_idx == True: Tan_wgt_globmean = {} if gen == 5: dir_var='/net/so4/landclim/snath/DA/data/%s/regridded/'%model run_names_list=sorted(glob.glob(dir_var+var+'_'+temp_res+'_'+model+'_'+scenario+'_'+'r*i1p1'+'_'+spatial_res+'.nc')) # ATTENTION: are ordered but does not work for models with runs above digit 9 #index_tr = [i for i, s in enumerate(run_names_list) if 'r1i1p1' in s][0] # find training run #print(run_names_list) #run_names_list.insert(0, run_names_list.pop(index_tr)) # move training run to begin of list # exception for cmip5 GISS-E2-H_rcp85_r2i1p1 ie the strange run I excluded from ESD paper if '/net/atmos/data/cmip5-ng/tas/tas_%s_GISS-E2-H_rcp85_r2i1p1_g025.nc'%usr_time_res in run_names_list: run_names_list.remove('/net/atmos/data/cmip5-ng/tas/tas_%s_GISS-E2-H_rcp85_r2i1p1_g025.nc'%usr_time_res ) # loop over all runs to obtain the absolute values print(run_names_list) for run_name in run_names_list: data = xr.open_mfdataset(run_name,decode_times=False) if usr_time_res=="ann": data=data.rename({'year':'time'}) data=data.rename({'longitude':'lon'}) data=data.rename({'latitude':'lat'}) data["time"]=cf_units.num2date(data.time.values, 'days since 1800-01-01 00:00:00', cf_units.CALENDAR_STANDARD) data=data.sel(time=slice('1870-01-01', '2101-01-01'))#.roll(lon=72) # rename so it is consisten with cmip6 # roll so that it is on same grid as others (no longer Pacific centered) #print(data.time.values) data = data.assign_coords(lon= (((data.lon + 180) % 360) - 180)) # assign_coords so same labels as others run=int(data.attrs['source_ensemble'].split('r')[1].split('i')[0]) # extract ens member run_nrs[run_name]=run y[run] = data.tas.values # still absolute values + still contains sea pixels T_ref += data.tas.sel(time=slice(Tref_start, Tref_end)).mean(dim='time').values*1.0/len(run_names_list) # sum up all ref climates if run==1 and Tref_all != True: T_ref_1=data.tas.sel(time=slice(Tref_start, Tref_end)).mean(dim='time').values print('create ref for ',run_name) if Tanglob_idx == True: Tan_wgt_globmean[run] = np.asarray([np.average(y[run][t],weights=wgt) for t in np.arange(y[run].shape[0])]) #area weighted but abs values if gen == 6: dir_var = '/net/so4/landclim/snath/DA/data/%s/regridded/'%model run_names_list=sorted(glob.glob(dir_var+var+'_'+temp_res+'_'+model+'_'+scenario+'_'+'r*i1p1f*'+'_'+spatial_res+'.nc')) # ATTENTION: are ordered but does not work for models with runs above digit 9 # idea is: every ssp one needs a corresponding hist one (vice versa not the case) #index_tr = [i for i, s in enumerate(run_names_list) if 'r1i1p1' in s][0] # find training run #run_names_list.insert(0, run_names_list.pop(index_tr)) # move training run to begin of list if model == 'EC-Earth3': # temporary fix added on 20191118 because these runs are not available as historical ones run_names_list.remove('/net/cfc/cmip6/Next_Generation/tas/%s/g025/tas_%s_EC-Earth3_ssp585_r1i1p1f1_g025.nc'%(usr_time_res,usr_time_res)) #run_names_list.remove('/net/cfc/cmip6/Next_Generation/tas/ann/g025/tas_ann_EC-Earth3_ssp585_r6i1p1f1_g025.nc') #6 removed because historical seems faulty (ie only ghg driven) on 20191119 #run_names_list.remove('/net/cfc/cmip6/Next_Generation/tas/ann/g025/tas_ann_EC-Earth3_ssp585_r11i1p1f1_g025.nc') #run_names_list.remove('/net/cfc/cmip6/Next_Generation/tas/ann/g025/tas_ann_EC-Earth3_ssp585_r13i1p1f1_g025.nc') #run_names_list.remove('/net/cfc/cmip6/Next_Generation/tas/ann/g025/tas_ann_EC-Earth3_ssp585_r15i1p1f1_g025.nc') print('ATTENTION: ssp realizations 1 because no historical available on 20191122 (open issue on ESGF).') print(run_names_list) for run_name in run_names_list: #run_name_ssp = run_name #run_name_hist = run_name.replace(scenario,'historical') run_name_hist = run_name run_name_ssp = dir_var+var+'_%s_'%(usr_time_res)+model+'_ssp370_r1i1p1f1_g05.nc' if model=='HadGEM3-GC31-LL': run_name_ssp = dir_var+var+'_%s_'%(usr_time_res)+model+'_ssp245_r1i1p1f3_g05.nc' if model=='CNRM-CM6-1': run_name_ssp = dir_var+var+'_%s_'%(usr_time_res) +model+'_ssp370_r1i1p1f2_g05.nc' if model=='GISS-E2-1-G': run_name_ssp = dir_var+var+'_%s_'%(usr_time_res) +model+'_ssp370_r6i1p1f2_g05.nc' data = xr.open_mfdataset([run_name_hist,run_name_ssp],concat_dim='time').sel(time=slice('1944-01-01', '2019-01-01')) #data = data.assign_coords(lon= (((data.lon + 180) % 360) - 180)) # assign_coords so same labels as others run = int(run_name_hist.split('_')[4].split('r')[1].split('i')[0])#data.attrs['realization_index'] run_nrs[run_name]=run y[run] = data[var].values # still absolute values + still contains sea pixels T_ref += data[var].sel(time=slice(Tref_start, Tref_end)).mean(dim='time').values*1.0/len(run_names_list) # sum up all ref climates if run==1 and Tref_all != True: T_ref_1=data[var].sel(time=slice(Tref_start, Tref_end)).mean(dim='time').values print('create ref for ',run_name) if model=='CAMS-CSM1-0': # temporary (?) fix added on 20191119 because CAMS-CSM1-0 data are currently only available till 2099 instead of 2100 y[run]=y[run][:-1] if Tanglob_idx == True: Tan_wgt_globmean[run] = np.asarray([np.average(y[run][t],weights=wgt) for t in np.arange(y[run].shape[0])]) #area weighted but abs values # obtain the anomalies for run_name in run_names_list: run = run_nrs[run_name] if Tref_all == True: y[run]=(y[run]-T_ref) if Tanglob_idx == True: Tan_wgt_globmean[run]=Tan_wgt_globmean[run]-np.average(T_ref,weights=wgt) else: y[run]=y[run] if Tanglob_idx == True: Tan_wgt_globmean[run]=Tan_wgt_globmean[run]-np.average(T_ref_1,weights=wgt) time=data["time"] if Tanglob_idx == False: return y,time,srex,srex_names,lon_pc,lat_pc,idx_l,wgt_l else: return y,time,srex,srex_names,lon_pc,lat_pc,idx_l,wgt_l,Tan_wgt_globmean