def make_timeseries_plot_2sided(time, data1, data2, title, units1, units2, monthly=True, fig_name=None, dpi=None): fig, ax1 = plt.subplots(figsize=(9, 6)) ax1.plot_date(time, data1, '-', linewidth=1.5, color='blue') ax1.grid(True) if not monthly: monthly_ticks(ax1) ax1.set_ylabel(units1, color='blue', fontsize=16) ax1.tick_params(axis='y', labelcolor='blue') ax2 = ax1.twinx() ax2.plot_date(time, data2, '-', linewidth=1.5, color='red') ax2.get_yaxis().get_major_formatter().set_useOffset(False) ax2.set_ylabel(units2, color='red', fontsize=16) ax2.tick_params(axis='y', labelcolor='red') if np.amin(data1) < 0 and np.amax(data1) > 0 and np.amin( data2) < 0 and np.amax(data2) > 0: # Both timeseries cross 0. Line them up there. val1 = max(-np.amin(data1), np.amax(data1)) val2 = max(-np.amin(data2), np.amax(data2)) ax1.set_ylim([-val1, val1]) ax2.set_ylim([-val2, val2]) ax1.axhline(color='black') plt.title(title, fontsize=18) finished_plot(fig, fig_name=fig_name, dpi=dpi)
def plot_timeseries_max(file_path, var_name, grid, xmin=None, xmax=None, ymin=None, ymax=None, title='', units='', fig_name=None, monthly=True): if not isinstance(grid, Grid): # This is the path to the NetCDF grid file, not a Grid object # Make a grid object from it grid = Grid(grid) if isinstance(file_path, str): # Just one file first_file = file_path elif isinstance(file_path, list): # More than one first_file = file_path[0] else: print 'Error (plot_timeseries_max): file_path must be a string or a list' sys.exit() # Calculate timeseries on the first file values = timeseries_max(first_file, var_name, grid, xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax) # Read time axis time = netcdf_time(first_file, monthly=monthly) if isinstance(file_path, list): # More files to read for file in file_path[1:]: values_tmp = timeseries_max(file, var_name, grid, xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax) time_tmp = netcdf_time(file, monthly=monthly) # Concatenate the arrays values = np.concatenate((values, values_tmp)) time = np.concatenate((time, time_tmp)) # Plot fig, ax = plt.subplots() ax.plot_date(time, values, '-', linewidth=1.5) ax.grid(True) yearly_ticks(ax) plt.title(title, fontsize=18) plt.ylabel(units, fontsize=16) finished_plot(fig, fig_name=fig_name)
def plot_vel(u, v, grid, vel_option='avg', vmin=None, vmax=None, zoom_fris=False, xmin=None, xmax=None, ymin=None, ymax=None, date_string=None, fig_name=None): # Do the correct vertical transformation, and interpolate to the tracer grid speed, u_plot, v_plot = prepare_vel(u, v, grid, vel_option=vel_option) include_shelf = True if vel_option == 'avg': title_beg = 'Vertically averaged ' elif vel_option == 'sfc': title_beg = 'Surface ' elif vel_option == 'bottom': title_beg = 'Bottom ' elif vel_option == 'ice': title_beg = 'Sea ice ' include_shelf = False # Make the plot but don't finish it yet fig, ax = latlon_plot(speed, grid, ctype='vel', include_shelf=include_shelf, vmin=vmin, vmax=vmax, zoom_fris=zoom_fris, xmin=xmin, xmax=xmax, date_string=date_string, title=title_beg + 'velocity (m/s)', return_fig=True) # Overlay circulation if zoom_fris: chunk = 6 else: chunk = 10 if vel_option == 'avg': scale = 0.8 elif vel_option == 'sfc': scale = 1.5 elif vel_option == 'bottom': scale = 1 elif vel_option == 'ice': scale = 4 overlay_vectors(ax, u_plot, v_plot, grid, chunk=chunk, scale=scale) finished_plot(fig, fig_name=fig_name)
def ts_slice_plot (temp, salt, grid, lon0=None, lat0=None, hmin=None, hmax=None, zmin=None, zmax=None, tmin=None, tmax=None, smin=None, smax=None, date_string=None, fig_name=None): # Choose what the endpoints of the colourbars should do extend = [get_extend(vmin=tmin, vmax=tmax), get_extend(vmin=smin, vmax=smax)] # Build the temperature patches and get the bounds patches, temp_values, loc0, hmin, hmax, zmin, zmax, tmin_tmp, tmax_tmp, left, right, below, above = slice_patches(temp, grid, lon0=lon0, lat0=lat0, hmin=hmin, hmax=hmax, zmin=zmin, zmax=zmax, return_bdry=True) # Get the salinity values on the same patches, and their colour bounds salt_values, smin_tmp, smax_tmp = slice_values(salt, grid, left, right, below, above, hmin, hmax, zmin, zmax, lon0=lon0, lat0=lat0) # Update any colour bounds which aren't already set if tmin is None: tmin = tmin_tmp if tmax is None: tmax = tmax_tmp if smin is None: smin = smin_tmp if smax is None: smax = smax_tmp # Figure out orientation and format slice location if lon0 is not None: h_axis = 'lat' loc_string = lon_label(loc0, 3) elif lat0 is not None: h_axis = 'lon' loc_string = lat_label(loc0, 3) # Set panels fig, gs, cax_t, cax_s = set_panels('1x2C2') # Wrap some things up in lists for easier iteration values = [temp_values, salt_values] vmin = [tmin, smin] vmax = [tmax, smax] cax = [cax_t, cax_s] title = [r'Temperature ($^{\circ}$C)', 'Salinity (psu)'] for i in range(2): ax = plt.subplot(gs[0,i]) # Plot patches img = plot_slice_patches(ax, patches, values[i], hmin, hmax, zmin, zmax, vmin[i], vmax[i]) # Nice axes slice_axes(ax, h_axis=h_axis) if i == 1: # Don't need depth labels a second time ax.set_yticklabels([]) ax.set_ylabel('') # Add a colourbar and hide every second label so they're not squished cbar = plt.colorbar(img, cax=cax[i], extend=extend[i], orientation='horizontal') for label in cbar.ax.xaxis.get_ticklabels()[1::2]: label.set_visible(False) # Variable title plt.title(title[i], fontsize=18) if date_string is not None: # Add date to main title loc_string += ', ' + date_string # Main title plt.suptitle(loc_string, fontsize=20) finished_plot(fig, fig_name=fig_name)
def plot_fris_massbalance(file_path, grid, fig_name=None, monthly=True): if not isinstance(grid, Grid): # This is the path to the NetCDF grid file, not a Grid object # Make a grid object from it grid = Grid(grid) if isinstance(file_path, str): # Just one file first_file = file_path elif isinstance(file_path, list): # More than one first_file = file_path[0] else: print 'Error (plot_fris_massbalance): file_path must be a string or a list' sys.exit() # Calculate timeseries on the first file melt, freeze = fris_melt(first_file, grid, mass_balance=True) # Read time axis time = netcdf_time(first_file, monthly=monthly) if isinstance(file_path, list): # More files to read for file in file_path[1:]: melt_tmp, freeze_tmp = fris_melt(file, grid, mass_balance=True) time_tmp = netcdf_time(file, monthly=monthly) # Concatenate the arrays melt = np.concatenate((melt, melt_tmp)) freeze = np.concatenate((freeze, freeze_tmp)) time = np.concatenate((time, time_tmp)) # Plot fig, ax = plt.subplots() ax.plot_date(time, melt, '-', color='red', linewidth=1.5, label='Melting') ax.plot_date(time, freeze, '-', color='blue', linewidth=1.5, label='Freezing') ax.plot_date(time, melt + freeze, '-', color='black', linewidth=1.5, label='Total') ax.axhline(color='black') ax.grid(True) yearly_ticks(ax) plt.title('Basal mass balance of FRIS', fontsize=18) plt.ylabel('Gt/y', fontsize=16) ax.legend() finished_plot(fig, fig_name=fig_name)
def timeseries_multi_plot(times, datas, labels, colours, title='', units='', monthly=True, fig_name=None): # Figure out if time is a list or a single array that applies to all timeseries multi_time = isinstance(times, list) # Boolean which will tell us whether we need a line at 0 crosses_zero = False fig, ax = plt.subplots(figsize=(11, 6)) # Plot each line for i in range(len(datas)): if multi_time: time = times[i] else: time = times ax.plot_date(time, datas[i], '-', color=colours[i], label=labels[i], linewidth=1.5) if (not crosses_zero) and (np.amin(datas[i]) < 0) and (np.amax( datas[i]) > 0): crosses_zero = True ax.grid(True) if crosses_zero: # Add a line at 0 ax.axhline(color='black') if not monthly: monthly_ticks(ax) plt.title(title, fontsize=18) plt.ylabel(units, fontsize=16) # Move plot over to make room for legend box = ax.get_position() ax.set_position([box.x0, box.y0, box.width * 0.8, box.height]) # Make legend ax.legend(loc='center left', bbox_to_anchor=(1, 0.5)) finished_plot(fig, fig_name=fig_name)
def make_timeseries_plot(time, data, title='', units='', monthly=True, fig_name=None): fig, ax = plt.subplots() ax.plot_date(time, data, '-', linewidth=1.5) if np.amin(data) < 0 and np.amax(data) > 0: # Add a line at 0 ax.axhline(color='black') ax.grid(True) if not monthly: monthly_ticks(ax) plt.title(title, fontsize=18) plt.ylabel(units, fontsize=16) finished_plot(fig, fig_name=fig_name)
def slice_plot (data, grid, gtype='t', lon0=None, lat0=None, hmin=None, hmax=None, zmin=None, zmax=None, vmin=None, vmax=None, ctype='basic', title=None, date_string=None, fig_name=None): # Choose what the endpoints of the colourbar should do extend = get_extend(vmin=vmin, vmax=vmax) # Build the patches and get the bounds patches, values, loc0, hmin, hmax, zmin, zmax, vmin_tmp, vmax_tmp = slice_patches(data, grid, gtype=gtype, lon0=lon0, lat0=lat0, hmin=hmin, hmax=hmax, zmin=zmin, zmax=zmax) # Update any colour bounds which aren't already set if vmin is None: vmin = vmin_tmp if vmax is None: vmax = vmax_tmp # Set colour map cmap, vmin, vmax = set_colours(values, ctype=ctype, vmin=vmin, vmax=vmax) # Figure out orientation and format slice location if lon0 is not None: h_axis = 'lat' loc_string = lon_label(loc0, 3) elif lat0 is not None: h_axis = 'lon' loc_string = lat_label(loc0, 3) # Set up the title if title is None: title = '' title += ' at ' + loc_string # Plot fig, ax = plt.subplots() # Add patches img = plot_slice_patches(ax, patches, values, hmin, hmax, zmin, zmax, vmin, vmax, cmap=cmap) # Make nice axis labels slice_axes(ax, h_axis=h_axis) # Add a colourbar plt.colorbar(img, extend=extend) # Add a title plt.title(title, fontsize=18) if date_string is not None: # Add the date in the bottom right corner plt.text(.99, .01, date_string, fontsize=14, ha='right', va='bottom', transform=fig.transFigure) finished_plot(fig, fig_name=fig_name)
def plot_aice_minmax(file_path, grid, year, fig_name=None, monthly=True): if not isinstance(grid, Grid): # This is the path to the NetCDF grid file, not a Grid object # Make a grid object from it grid = Grid(grid) # Read sea ice area and the corresponding dates aice = mask_land_zice(read_netcdf(file_path, 'SIarea'), grid, time_dependent=True) time = netcdf_time(file_path, monthly=monthly) # Find the range of dates we care about t_start, t_end = select_year(time, year) # Trim the arrays to these dates aice = aice[t_start:t_end, :] time = time[t_start:t_end] # Find the indices of min and max sea ice area t_min, t_max = find_aice_min_max(aice, grid) # Wrap up in lists for easy iteration aice_minmax = [aice[t_min, :], aice[t_max, :]] time_minmax = [time[t_min], time[t_max]] # Plot fig, gs, cax = set_panels('1x2C1') for t in range(2): lon, lat, aice_plot = cell_boundaries(aice_minmax[t], grid) ax = plt.subplot(gs[0, t]) shade_land_zice(ax, grid) img = ax.pcolormesh(lon, lat, aice_plot, vmin=0, vmax=1) latlon_axes(ax, lon, lat) if t == 1: # Don't need latitude labels a second time ax.set_yticklabels([]) plt.title(parse_date(date=time_minmax[t]), fontsize=18) # Colourbar plt.colorbar(img, cax=cax, orientation='horizontal') # Main title above plt.suptitle('Min and max sea ice area', fontsize=22) finished_plot(fig, fig_name=fig_name)
def make_timeseries_plot_2sided(time, data1, data2, title, units1, units2, monthly=True, fig_name=None, dpi=None): fig, ax1 = plt.subplots(figsize=(9, 6)) ax1.plot_date(time, data1, '-', linewidth=1.5, color='blue') ax1.grid(True) if not monthly: monthly_ticks(ax1) ax1.set_ylabel(units1, color='blue', fontsize=16) ax1.tick_params(axis='y', labelcolor='blue') ax2 = ax1.twinx() ax2.plot_date(time, data2, '-', linewidth=1.5, color='red') ax2.get_yaxis().get_major_formatter().set_useOffset(False) ax2.set_ylabel(units2, color='red', fontsize=16) ax2.tick_params(axis='y', labelcolor='red') plt.title(title, fontsize=18) finished_plot(fig, fig_name=fig_name, dpi=dpi)
def amundsen_rignot_comparison(file_path, precomputed=False, option='melting', file_path_2=None, sim_names=None, fig_name=None): shelf_names = [ 'getz', 'dotson_crosson', 'thwaites', 'pig', 'cosgrove', 'abbot', 'venable' ] shelf_titles = [ 'Getz', 'Dotson &\nCrosson', 'Thwaites', 'Pine Island', 'Cosgrove', 'Abbot', 'Venable' ] num_shelves = len(shelf_names) if not precomputed: grid = Grid(file_path) second = file_path_2 is not None ensemble = second and isinstance(file_path_2, list) if ensemble: num_ens = len(file_path_2) if second and (sim_names is None or not isinstance(sim_names, list) or len(sim_names) != 2): print 'Error (amundsen_rignot_comparison): must set sim_names as list of 2 simulation names if file_path_2 is set.' sys.exit() model_melt = [] if second: model2_melt = [] obs_melt = [] obs_std = [] for shelf in shelf_names: var_name = shelf + '_' + option if precomputed: model_melt.append( read_netcdf(file_path, var_name, time_average=True)) if second: if ensemble: for n in range(num_ens): melt_tmp = read_netcdf(file_path_2[n], var_name, time_average=True) if n == 0: min_melt = melt_tmp max_melt = melt_tmp else: min_melt = min(min_melt, melt_tmp) max_melt = max(max_melt, melt_tmp) model2_melt.append([min_melt, max_melt]) else: model2_melt.append( read_netcdf(file_path_2, var_name, time_average=True)) else: model_melt.append( timeseries_ismr(file_path, grid, shelf=shelf, result=option, time_average=True)) if second: if ensemble: for n in range(num_ens): melt_tmp = timeseries_ismr(file_path_2[n], grid, shelf=shelf, result=option, time_average=True) if n == 0: min_melt = melt_tmp max_melt = melt_tmp else: min_melt = min(min_melt, melt_tmp) max_melt = max(max_melt, melt_tmp) model2_melt.append([min_melt, max_melt]) else: model2_melt.append( timeseries_ismr(file_path_2, grid, shelf=shelf, result=option, time_average=True)) obs = rignot_melt[shelf] if option == 'massloss': obs_melt.append(obs[0]) obs_std.append(obs[1]) elif option == 'melting': obs_melt.append(obs[2]) obs_std.append(obs[3]) else: print 'Error (amundsen_rignot_comparison): invalid option ' + option sys.exit() if second and ensemble: # Convert from min/max to central value and difference, for plotting model2_melt0 = [] model2_melt_diff = [] for n in range(num_shelves): model2_melt0.append(0.5 * (model2_melt[n][0] + model2_melt[n][1])) model2_melt_diff.append(model2_melt0[n] - model2_melt[n][0]) fig, ax = plt.subplots() if second: ax.plot(range(num_shelves), model_melt, 'o', color='blue', label=sim_names[0]) if ensemble: ax.errorbar(range(num_shelves), model2_melt0, yerr=model2_melt_diff, fmt='none', color='green', capsize=4, label=sim_names[1]) else: ax.plot(range(num_shelves), model2_melt, 'o', color='green', label=sim_names[1]) else: if isinstance(sim_names, list): label = sim_names[0] elif isinstance(sim_names, str): label = sim_names else: label = 'MITgcm' ax.plot(range(num_shelves), model_melt, 'o', color='blue', label=label) ax.errorbar(range(num_shelves), obs_melt, yerr=obs_std, fmt='none', color='black', capsize=4, label='Observations') ax.legend() ax.grid(True) plt.xticks(range(num_shelves), shelf_titles, rotation='vertical') plt.subplots_adjust(bottom=0.2) if option == 'massloss': title = 'Basal mass loss' units = 'Gt/y' elif option == 'melting': title = 'Average melt rate' units = 'm/y' plt.title(title, fontsize=16) plt.ylabel(units, fontsize=12) finished_plot(fig, fig_name=fig_name)
def ctd_cast_compare(loc, hovmoller_file, obs_file, grid, std=False, ens_hovmoller_files=None, month=2, fig_name=None): from scipy.io import loadmat ensemble = ens_hovmoller_files is not None grid = choose_grid(grid, None) # Get bounds on region [xmin, xmax, ymin, ymax] = region_bounds[loc] # Read obs f = loadmat(obs_file) obs_lat = np.squeeze(f['Lat']) obs_lon = np.squeeze(f['Lon']) obs_depth = -1 * np.squeeze(f['P']) obs_temp = np.transpose(f['PT']) obs_salt = np.transpose(f['S']) # Convert NaNs into mask obs_temp = np.ma.masked_where(np.isnan(obs_temp), obs_temp) obs_salt = np.ma.masked_where(np.isnan(obs_salt), obs_salt) # Find casts within given region index = (obs_lon >= xmin) * (obs_lon <= xmax) * (obs_lat >= ymin) * (obs_lat <= ymax) obs_temp = obs_temp[index, :] obs_salt = obs_salt[index, :] num_obs = obs_temp.shape[0] # Read model output model_temp = read_netcdf(hovmoller_file, loc + '_temp') model_salt = read_netcdf(hovmoller_file, loc + '_salt') if month != 0: # Select the month we want time = netcdf_time(hovmoller_file, monthly=False) index = [t.month == month for t in time] model_temp = model_temp[index, :] model_salt = model_salt[index, :] num_model = model_temp.shape[0] if ensemble: # Read model ensemble output, all in one ens_temp = None ens_salt = None ens_time = None for file_path in ens_hovmoller_files: temp_tmp = read_netcdf(file_path, loc + '_temp') salt_tmp = read_netcdf(file_path, loc + '_salt') time_tmp = netcdf_time(file_path, monthly=False) if ens_temp is None: ens_temp = temp_tmp ens_salt = salt_tmp ens_time = time_tmp else: ens_temp = np.concatenate((ens_temp, temp_tmp)) ens_salt = np.concatenate((ens_salt, salt_tmp)) ens_time = np.concatenate((ens_time, time_tmp)) if month != 0: index = [t.month == month for t in ens_time] ens_temp = ens_temp[index, :] ens_salt = ens_salt[index, :] # Set panels fig, gs = set_panels('1x2C0') # Wrap things up in lists for easier iteration obs_data = [obs_temp, obs_salt] model_data = [model_temp, model_salt] if ensemble: ens_data = [ens_temp, ens_salt] all_data = [obs_data, model_data, ens_data] depths = [obs_depth, grid.z, grid.z] colours = ['black', 'red', 'blue'] num_ranges = len(colours) titles = ['Temperature', 'Salinity'] if std: titles = [t + ' std' for t in titles] units = [deg_string + 'C', 'psu'] if std: vmin = [None, None] vmax = [None, None] else: vmin = [-2, 33] vmax = [2, 34.75] for i in range(2): ax = plt.subplot(gs[0, i]) if ensemble: # Plot transparent ranges, with means on top # OR just plot standard deviation for n in range(num_ranges): if std: ax.plot(np.std(all_data[n][i], axis=0), depths[n], color=colours[n], linewidth=2) else: ax.fill_betweenx(depths[n], np.amin(all_data[n][i], axis=0), x2=np.amax(all_data[n][i], axis=0), color=colours[n], alpha=0.3) ax.plot(np.mean(all_data[n][i], axis=0), depths[n], color=colours[n], linewidth=2) else: # Plot obs if std: ax.plot(np.std(obs_data[i], axis=0), obs_depth, color='black', linewidth=2) else: # Plot individual lines for n in range(num_obs): ax.plot(obs_data[i][n, :], obs_depth, color=(0.6, 0.6, 0.6), linewidth=1) # Plot obs mean in thicker dashedblack ax.plot(np.mean(obs_data[i], axis=0), obs_depth, color='black', linewidth=2, linestyle='dashed') # Plot model years if std: ax.plot(np.std(model_data[i], axis=0), grid.z, color='blue', linewidth=2) else: # Different colours for each year for n in range(num_model): ax.plot(model_data[i][n, :], grid.z, linewidth=1) # Plot model mean in thicker black ax.plot(np.mean(model_data[i], axis=0), grid.z, color='black', linewidth=2) ax.set_xlim([vmin[i], vmax[i]]) ax.grid(True) plt.title(titles[i], fontsize=16) plt.xlabel(units[i], fontsize=14) if i == 0: plt.ylabel('Depth (m)', fontsize=14) else: ax.set_yticklabels([]) if ensemble: plt.suptitle(loc + ': CTDs (black), ERA5 (red), PACE ensemble (blue)', fontsize=20) else: if std: plt.suptitle(loc + ': model (blue) vs CTDs (black)', fontsize=20) else: plt.suptitle(loc + ': model (colours) vs CTDs (grey)', fontsize=20) finished_plot(fig, fig_name=fig_name)
def hovmoller_ts_plot(temp, salt, time, grid, smooth=0, split_year=None, tmin=None, tmax=None, smin=None, smax=None, zmin=None, zmax=None, monthly=True, t_contours=None, s_contours=None, title=None, date_since_start=False, start=0, t0=None, s0=None, ctype='basic', loc_string='', fig_name=None, figsize=(12, 7), dpi=None, return_fig=False, ab_inside=False, rasterized=False): # Set panels fig, gs, cax_t, cax_s = set_panels('2x1C2', figsize=figsize) if split_year is not None: if date_since_start: first_year = time[0].year - time[start].year last_year = time[-1].year - time[start].year else: first_year = time[0].year last_year = time[-1].year width1 = (split_year - first_year) width2 = (last_year + 1 - split_year) gs = plt.GridSpec(2, 2, width_ratios=[width1, width2]) gs.update(left=0.08, right=0.9, bottom=0.1, top=0.88, hspace=0.2, wspace=0.01) # Need to choose the correct colour bounds if any([zmin, zmax]): tmin_tmp, tmax_tmp = var_min_max_zt(temp, grid, zmin=zmin, zmax=zmax) smin_tmp, smax_tmp = var_min_max_zt(salt, grid, zmin=zmin, zmax=zmax) if tmin is None: tmin = tmin_tmp if tmax is None: tmax = tmax_tmp if smin is None: smin = smin_tmp if smax is None: smax = smax_tmp # Wrap things up in lists for easier iteration data = [temp, salt] vmin = [tmin, smin] vmax = [tmax, smax] val0 = [t0, s0] contours = [t_contours, s_contours] if ab_inside: titles = ['Temperature (' + deg_string + 'C)', 'Salinity (psu)'] ab = ['a', 'b'] else: titles = ['a) Temperature (' + deg_string + 'C)', 'b) Salinity (psu)'] cax = [cax_t, cax_s] axs = [] for i in range(2): ax = plt.subplot(gs[i, 0]) # Make the plot img = hovmoller_plot(data[i], time, grid, smooth=smooth, ax=ax, make_cbar=False, vmin=vmin[i], vmax=vmax[i], zmin=zmin, zmax=zmax, monthly=monthly, contours=contours[i], ctype=ctype, title=titles[i], date_since_start=date_since_start, start=start, val0=val0[i], end_t=split_year, rasterized=rasterized) if ab_inside: plt.text(0.01, 0.98, ab[i], weight='bold', ha='left', va='top', fontsize=16, transform=ax.transAxes) # Add a colourbar extend = get_extend(vmin=vmin[i], vmax=vmax[i]) cbar = plt.colorbar(img, cax=cax[i], extend=extend) reduce_cbar_labels(cbar) if i == 0: # Remove x-tick labels from top plot ax.set_xticklabels([]) else: ax.set_xlabel('Year', fontsize=14) ax.set_ylabel('') axs.append(ax) if split_year is not None: # Now make another plot beside ax2 = plt.subplot(gs[i, 1]) img = hovmoller_plot(data[i], time, grid, smooth=smooth, ax=ax2, make_cbar=False, vmin=vmin[i], vmax=vmax[i], zmin=zmin, zmax=zmax, monthly=monthly, contours=contours[i], ctype=ctype, title='', date_since_start=date_since_start, start=start, val0=val0[i], start_t=split_year, rasterized=rasterized) ax2.set_yticklabels([]) ax2.set_ylabel('') if i == 0: ax2.set_xticklabels([]) axs.append(ax2) if title is None: title = loc_string plt.suptitle(title, fontsize=22) if return_fig: return fig, axs else: finished_plot(fig, fig_name=fig_name, dpi=dpi)
def ts_distribution_plot(file_path, region='all', grid=None, time_index=None, t_start=None, t_end=None, time_average=False, second_file_path=None, tmin=None, tmax=None, smin=None, smax=None, num_bins=1000, date_string=None, figsize=(8, 6), fig_name=None): # Build the grid if needed grid = choose_grid(grid, file_path) # Make sure we'll end up with a single record in time check_single_time(time_index, time_average) # Determine what to write about the date date_string = check_date_string(date_string, file_path, time_index) # Quick inner function to read data (THETA or SALT) def read_data(var_name): # First choose the right file if second_file_path is not None: file_path_use = find_variable(file_path, second_file_path) else: file_path_use = file_path data = read_netcdf(file_path_use, var_name, time_index=time_index, t_start=t_start, t_end=t_end, time_average=time_average) return data # Call this function for each variable temp = read_data('THETA') salt = read_data('SALT') if region == 'all': mask = grid.hfac > 0 elif region == 'cavities': mask = grid.ice_mask else: mask = grid.get_region_mask(region) # Make the bins volume, temp_centres, salt_centres, temp_edges, salt_edges = ts_binning( temp, salt, grid, mask, num_bins=num_bins) # Find the volume bounds for plotting min_vol = np.log(np.amin(volume)) max_vol = np.log(np.amax(volume)) # Calculate the surface freezing point for plotting tfreeze_sfc = tfreeze(salt_centres, 0) # Choose the plotting bounds if not set if tmin is None: tmin = temp_bins[0] if tmax is None: tmax = temp_bins[-1] if smin is None: smin = salt_bins[0] if smax is None: smax = salt_bins[-1] # Construct the title title = 'Water masses' if region == 'all': pass elif region == 'cavities': title += ' in ice shelf cavities' elif region.endswith('cavity'): title += ' in ' + region_names[region[:region.index('_cavity')]] else: title += ' in ' + region_names[region] if date_string != '': title += ', ' + date_string # Plot fig, ax = plt.subplots(figsize=figsize) # Use a log scale for visibility img = plt.pcolor(salt_centres, temp_centres, np.log(volume), vmin=min_vol, vmax=max_vol) # Add the surface freezing point plt.plot(salt_centres, tfreeze_sfc, color='black', linestyle='dashed', linewidth=2) ax.grid(True) ax.set_xlim([smin, smax]) ax.set_ylim([tmin, tmax]) plt.xlabel('Salinity (psu)') plt.ylabel('Temperature (' + deg_string + 'C)') plt.colorbar(img) plt.text(.9, .6, 'log of volume', ha='center', rotation=-90, transform=fig.transFigure) plt.title(title) finished_plot(fig, fig_name=fig_name)
def timeseries_multi_plot(times, datas, labels, colours, linestyles=None, alphas=None, title='', units='', monthly=True, fig_name=None, dpi=None, legend_in_centre=False, legend_outside=True, dates=True, thick_last=False, thick_first=False, first_on_top=False, vline=None, return_fig=False, year_ticks=None): # Figure out if time is a list or a single array that applies to all timeseries multi_time = isinstance(times, list) # Booleans which will tell us whether we need a line at 0 or 100 negative = False positive = False lt_100 = False gt_100 = False for data in datas: if np.amin(data) < 0: negative = True if np.amax(data) > 0: positive = True if np.amin(data) < 100: lt_100 = True if np.amax(data) > 100: gt_100 = True crosses_zero = negative and positive crosses_100 = lt_100 and gt_100 and units[0] == '%' if multi_time: start_time = times[0][0] end_time = start_time for time in times: if time[-1] > end_time: end_time = time[-1] else: start_time = times[0] end_time = times[-1] plot_legend = labels is not None if labels is None: labels = [None for i in range(len(datas))] if linestyles is None: linestyles = ['solid' for n in range(len(labels))] if alphas is None: alphas = [1 for n in range(len(labels))] if legend_outside: figsize = (11, 6) else: figsize = (8, 6) fig, ax = plt.subplots(figsize=figsize) # Plot each line for i in range(len(datas)): if multi_time: time = times[i] else: time = times if (thick_first and i == 0) or (thick_last and i == len(datas) - 1): linewidth = 2 else: linewidth = 1 if first_on_top and i == 0: if dates: ax.plot_date(time, datas[i], '-', color=colours[i], label=labels[i], linewidth=linewidth, linestyle=linestyles[i], alpha=alphas[i], zorder=len(datas)) else: ax.plot(time, datas[i], '-', color=colours[i], label=labels[i], linewidth=linewidth, linestyle=linestyles[i], alpha=alphas[i], zorder=len(datas)) else: if dates: ax.plot_date(time, datas[i], '-', color=colours[i], label=labels[i], linewidth=linewidth, linestyle=linestyles[i], alpha=alphas[i]) else: ax.plot(time, datas[i], '-', color=colours[i], label=labels[i], linewidth=linewidth, linestyle=linestyles[i], alpha=alphas[i]) ax.set_xlim(start_time, end_time) ax.grid(linestyle='dotted') if crosses_zero: # Add a line at 0 ax.axhline(color='black', linestyle='dashed') if crosses_100: # Add a line at 100% ax.axhline(100, color='black', linestyle='dashed') if vline is not None: if dates: vline = datetime.date(vline, 1, 1) ax.axvline(vline, color='black', linestyle='dashed') if not monthly: monthly_ticks(ax) if year_ticks is not None: if dates: year_ticks = [datetime.date(y, 1, 1) for y in year_ticks] ax.set_xticks(year_ticks) plt.title(title, fontsize=18) plt.ylabel(units, fontsize=16) if not dates: plt.xlabel('Years', fontsize=16) if plot_legend: if legend_outside: # Move plot over to make room for legend box = ax.get_position() ax.set_position([box.x0, box.y0, box.width * 0.8, box.height]) # Make legend ax.legend(loc='center left', bbox_to_anchor=(1, 0.5)) elif legend_in_centre: ax.legend(loc='center') else: ax.legend(loc='best') if return_fig: return fig, ax else: finished_plot(fig, fig_name=fig_name, dpi=dpi)
def latlon_plot(data, grid, gtype='t', include_shelf=True, ctype='basic', vmin=None, vmax=None, zoom_fris=False, xmin=None, xmax=None, ymin=None, ymax=None, date_string=None, title=None, return_fig=False, fig_name=None, change_points=None): # Choose what the endpoints of the colourbar should do extend = get_extend(vmin=vmin, vmax=vmax) # If we're zooming, we need to choose the correct colour bounds if zoom_fris or any([xmin, xmax, ymin, ymax]): vmin_tmp, vmax_tmp = var_min_max(data, grid, zoom_fris=zoom_fris, xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax, gtype=gtype) # Don't override manually set bounds if vmin is None: vmin = vmin_tmp if vmax is None: vmax = vmax_tmp # Get colourmap cmap, vmin, vmax = set_colours(data, ctype=ctype, vmin=vmin, vmax=vmax, change_points=change_points) # Prepare quadrilateral patches lon, lat, data_plot = cell_boundaries(data, grid, gtype=gtype) fig, ax = plt.subplots() if include_shelf: # Shade land in grey shade_land(ax, grid, gtype=gtype) else: # Shade land and ice shelves in grey shade_land_zice(ax, grid, gtype=gtype) # Plot the data img = ax.pcolormesh(lon, lat, data_plot, cmap=cmap, vmin=vmin, vmax=vmax) if include_shelf: # Contour ice shelf front contour_iceshelf_front(ax, grid) # Add a colourbar plt.colorbar(img, extend=extend) # Make nice axes latlon_axes(ax, lon, lat, zoom_fris=zoom_fris, xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax) if date_string is not None: # Add the date in the bottom right corner plt.text(.99, .01, date_string, fontsize=14, ha='right', va='bottom', transform=fig.transFigure) if title is not None: # Add a title plt.title(title, fontsize=18) if return_fig: return fig, ax else: finished_plot(fig, fig_name=fig_name)
def timeseries_multi_plot(times, datas, labels, colours, title='', units='', monthly=True, fig_name=None, dpi=None, legend_in_centre=False, dates=True): # Figure out if time is a list or a single array that applies to all timeseries multi_time = isinstance(times, list) # Boolean which will tell us whether we need a line at 0 negative = False positive = False for data in datas: if np.amin(data) < 0: negative = True if np.amax(data) > 0: positive = True crosses_zero = negative and positive if not dates: if multi_time: start_time = times[0][0] end_time = start_time for time in times: end_time = max(end_time, time[-1]) else: start_time = times[0] end_time = times[-1] if legend_in_centre: figsize = (8, 6) else: figsize = (11, 6) fig, ax = plt.subplots(figsize=figsize) # Plot each line for i in range(len(datas)): if multi_time: time = times[i] else: time = times if dates: ax.plot_date(time, datas[i], '-', color=colours[i], label=labels[i], linewidth=1.5) else: ax.plot(time, datas[i], '-', color=colours[i], label=labels[i], linewidth=1.5) ax.set_xlim(start_time, end_time) ax.grid(True) if crosses_zero: # Add a line at 0 ax.axhline(color='black') if not monthly: monthly_ticks(ax) plt.title(title, fontsize=18) plt.ylabel(units, fontsize=16) if legend_in_centre: # Make legend ax.legend(loc='center') else: # Move plot over to make room for legend box = ax.get_position() ax.set_position([box.x0, box.y0, box.width * 0.8, box.height]) # Make legend ax.legend(loc='center left', bbox_to_anchor=(1, 0.5)) finished_plot(fig, fig_name=fig_name, dpi=dpi)