def interpgridnodes(Pk=5.0, kappa=np.inf, struct="pp", sampling=1): # 1: Extract the "spectra from the grid nodes grid_name = "[NII]/[SII]+;[OIII]/[SII]+" grid = pyqz.get_grid( grid_name, Pk=Pk, struct=struct, kappa=kappa, coeffs=pyqz.diagnostics[grid_name]["coeffs"], sampling=sampling ) grid_nodes = grid[0][ :, [grid[1].index("LogQ"), grid[1].index("Tot[O]+12"), grid[1].index("Mix_x"), grid[1].index("Mix_y")] ] # 2: Now, interpolate and checks the output interp_qs = pyqz.interp_qz( "LogQ", [grid_nodes[:, -2], grid_nodes[:, -1]], grid_name, coeffs=pyqz.diagnostics[grid_name]["coeffs"], Pk=Pk, kappa=kappa, struct=struct, sampling=sampling, ) interp_zs = pyqz.interp_qz( "Tot[O]+12", [grid_nodes[:, -2], grid_nodes[:, -1]], grid_name, coeffs=pyqz.diagnostics[grid_name]["coeffs"], Pk=Pk, kappa=kappa, struct=struct, sampling=sampling, ) return np.all(np.round(interp_qs, 2) == grid_nodes[:, 0]) and np.all(np.round(interp_zs, 3) == grid_nodes[:, 1])
def plot_grid(ratios, coeffs=[[1, 0], [0, 1]], Pk=5.0, kappa=np.inf, struct='pp', sampling=1, color_mode='Tot[O]+12', figname=None, show_plot=True, data=None, interp_data=None): ''' Creates the diagram of a given line ratio grid for rapid inspection, including wraps (fold-over regions), and of certain line ratios, if "data" is specified. :Args: ratios: string The line ratios defining the grid, e.g. '[NII]/[SII]+;[OIII]/Hb' coeffs: list of list [default: [[1,0],[0,1]] ] The different coefficients with which to mix the line ratios. The size of each sub-list must be equal to the number of line ratios involved. Used for projected 3D diagnostic grids. Pk: float [default: 5.0] MAPPINGS model pressure. This value must match an existing grid file. kappa: float [default: np.inf The kappa value. This value must match an existing grid file. struct: string [default: 'pp'] spherical ('sph') or plane-parallel ('pp') HII regions. This value must match an existing reference grid file. sampling: int [default: 1] Use a resampled grid ? color_mode: string [default: 'Tot[O]+12'] Color the grid according to 'Tot[O]+12', 'gas[O]+12' or 'LogQ'. figname: string [default: None] 'path+name+format' to save the Figure to. show_plot: bool [default: True] Do you want to display the Figure ? data: list of numpy array [default: None] List of Arrays of the line ratio values. One array per line ratio. interp_data: numpy array [default: 'linear'] interpolated line ratios (via pyqz.interp_qz) ''' # 0) Let's get the data in question [grid, grid_cols, metadata] = pyqz.get_grid(ratios, coeffs=coeffs, Pk=Pk, kappa=kappa, struct=struct, sampling=sampling) # 1) What are the bad segments in this grid ? bad_segs = pyqz.check_grid(ratios, coeffs=coeffs, Pk=Pk, kappa=kappa, struct=struct, sampling=sampling) # 2) Start the plotting fig = plt.figure(figsize=(10, 8)) gs = gridspec.GridSpec(1, 2, height_ratios=[1], width_ratios=[1, 0.05]) gs.update(left=0.14, right=0.88, bottom=0.14, top=0.92, wspace=0.1, hspace=0.1) ax1 = fig.add_subplot(gs[0, 0]) if not (color_mode in grid_cols): raise Exception('color_mode unknown: %s' % color_mode) # 2) Plot the grid points # Let's make the distinction between the 'TRUE' MAPPINGS point, # and those that were interpolated in a finer grid using Akima splines pts = ax1.scatter(grid[:, grid_cols.index('Mix_x')], grid[:, grid_cols.index('Mix_y')], marker='o', c=grid[:, grid_cols.index(color_mode)], s=30, cmap=pyqzm.pyqz_cmap_0, edgecolor='none', vmin=np.min(grid[:, grid_cols.index(color_mode)]), vmax=np.max(grid[:, grid_cols.index(color_mode)]), zorder=3) # Now mark the "original" points with a black outline. First, which are they ? if sampling > 1: origin_cond = [ n for n in range(len(grid)) if (grid[n, metadata['columns'].index('LogQ')] in metadata['resampled']['LogQ']) and ( grid[n, metadata['columns'].index('Tot[O]+12')] in metadata['resampled']['Tot[O]+12']) ] else: origin_cond = [n for n in range(len(grid))] # Now plot the black outlines. original_pts = ax1.scatter(grid[origin_cond, grid_cols.index('Mix_x')], grid[origin_cond, grid_cols.index('Mix_y')], marker='o', c=grid[origin_cond, grid_cols.index(color_mode)], s=60, cmap=pyqzm.pyqz_cmap_0, edgecolor='k', facecolor='white', vmin=np.min(grid[:, grid_cols.index(color_mode)]), vmax=np.max(grid[:, grid_cols.index(color_mode)]), zorder=5) # 2-1) Draw the grid lines # Check as a function of LogQ and Tot[O]+12. Where are these ? u = grid_cols.index('LogQ') v = grid_cols.index('Tot[O]+12') for i in [u, v]: # Here, 'var' plays the role of 'q' or 'z' depending on 'i'. for var in np.unique(grid[:, i]): # Plot the grid line ax1.plot(grid[grid[:, i] == var][:, grid_cols.index('Mix_x')], grid[grid[:, i] == var][:, grid_cols.index('Mix_y')], 'k-', lw=1, zorder=1) # Plot the bad segments for bad_seg in bad_segs: ax1.plot([bad_seg[0][0], bad_seg[1][0]], [bad_seg[0][1], bad_seg[1][1]], 'r-', linewidth=4, zorder=0) # Now, also plot the data, if anything was provided ! if not (interp_data is None): # Compute the combined "observed" ratios data_comb = [np.zeros_like(data[0]), np.zeros_like(data[1])] for k in range(len(ratios.split(';'))): data_comb[0] += coeffs[0][k] * data[k] data_comb[1] += coeffs[1][k] * data[k] ax1.scatter(data_comb[0][interp_data == interp_data], data_comb[1][interp_data == interp_data], marker='s', c=interp_data[interp_data == interp_data], s=15, cmap=pyqzm.pyqz_cmap_0, edgecolor='k', vmin=np.min(grid[:, grid_cols.index(color_mode)]), vmax=np.max(grid[:, grid_cols.index(color_mode)]), zorder=2, alpha=0.35) # Plot also the points outside the grid ? # Which are they ? Need to check if they have a valid input first ! # mind the "~" to invert the bools ! isn't this cool ? my_out_pts = ~np.isnan(data_comb[0]) * ~np.isnan(data_comb[1]) * \ np.isnan(interp_data) # Don't do this if this is a test with fullgrid_x ... ax1.scatter(data_comb[0][my_out_pts], data_comb[1][my_out_pts], marker='^', facecolor='none', edgecolor='k', s=60) # 3) Plot the colorbar cb_ax = plt.subplot(gs[0, 1]) cb = Colorbar(ax=cb_ax, mappable=pts, orientation='vertical') # Colorbar legend cb.set_label(color_mode, labelpad=10) # 4) Axis names, kappa value, etc ... rats = ratios.split(';') # Make sure the labels look pretty in ALL cases ... labelx, labely = get_plot_labels(rats, coeffs) ax1.set_xlabel(labelx, labelpad=10) ax1.set_ylabel(labely, labelpad=10) if not (kappa in [np.inf, 'inf']): kappa_str = r'$\kappa$ = ' + str(kappa) else: kappa_str = r'$\kappa$ = $\infty$' ax1.text(0.85, 0.9, kappa_str, horizontalalignment='left', verticalalignment='bottom', transform=ax1.transAxes) ax1.grid(True) if figname: fig.savefig(figname, bbox_inches='tight') if show_plot: plt.show() else: plt.close()
def plot_grid(ratios, coeffs = [[1,0],[0,1]], Pk = 5.0, kappa=np.inf, struct = 'pp', sampling = 1, color_mode = 'Tot[O]+12', figname = None, show_plot = True, data = None, interp_data = None): ''' Creates the diagram of a given line ratio grid for rapid inspection, including wraps (fold-over regions), and of certain line ratios, if "data" is specified. :Args: ratios: string The line ratios defining the grid, e.g. '[NII]/[SII]+;[OIII]/Hb' coeffs: list of list [default: [[1,0],[0,1]] ] The different coefficients with which to mix the line ratios. The size of each sub-list must be equal to the number of line ratios involved. Used for projected 3D diagnostic grids. Pk: float [default: 5.0] MAPPINGS model pressure. This value must match an existing grid file. kappa: float [default: np.inf The kappa value. This value must match an existing grid file. struct: string [default: 'pp'] spherical ('sph') or plane-parallel ('pp') HII regions. This value must match an existing reference grid file. sampling: int [default: 1] Use a resampled grid ? color_mode: string [default: 'Tot[O]+12'] Color the grid according to 'Tot[O]+12', 'gas[O]+12' or 'LogQ'. figname: string [default: None] 'path+name+format' to save the Figure to. show_plot: bool [default: True] Do you want to display the Figure ? data: list of numpy array [default: None] List of Arrays of the line ratio values. One array per line ratio. interp_data: numpy array [default: 'linear'] interpolated line ratios (via pyqz.interp_qz) ''' # 0) Let's get the data in question [grid, grid_cols, metadata] = pyqz.get_grid(ratios, coeffs=coeffs, Pk=Pk, kappa=kappa, struct=struct, sampling = sampling) # 1) What are the bad segments in this grid ? bad_segs = pyqz.check_grid(ratios, coeffs=coeffs, Pk = Pk, kappa=kappa, struct=struct, sampling = sampling) # 2) Start the plotting fig = plt.figure(figsize=(10,8)) gs = gridspec.GridSpec(1,2, height_ratios=[1], width_ratios=[1,0.05]) gs.update(left=0.14,right=0.88,bottom=0.14,top=0.92, wspace=0.1,hspace=0.1) ax1 = fig.add_subplot(gs[0,0]) if not(color_mode in grid_cols): sys.exit('color_mode unknown: %s' % color_mode) # 2) Plot the grid points # Let's make the distinction between the 'TRUE' MAPPINGS point, # and those that were interpolated in a finer grid using Akima splines pts = ax1.scatter(grid[:,grid_cols.index('Mix_x')], grid[:,grid_cols.index('Mix_y')], marker='o', c=grid[:,grid_cols.index(color_mode)], s=30, cmap=pyqz_cmap_0, edgecolor='none', vmin=np.min(grid[:,grid_cols.index(color_mode)]), vmax=np.max(grid[:,grid_cols.index(color_mode)]), zorder=3) # Now mark the "original" points with a black outline. First, which are they ? if sampling > 1: origin_cond = [n for n in range(len(grid)) if (grid[n,metadata['columns'].index('LogQ')] in metadata['resampled']['LogQ']) and (grid[n,metadata['columns'].index('Tot[O]+12')] in metadata['resampled']['Tot[O]+12'])] else: origin_cond = [n for n in range(len(grid))] # Now plot the black outlines. original_pts = ax1.scatter(grid[origin_cond, grid_cols.index('Mix_x')], grid[origin_cond, grid_cols.index('Mix_y')], marker='o', c=grid[origin_cond, grid_cols.index(color_mode)], s=60, cmap=pyqz_cmap_0, edgecolor='k', facecolor='white', vmin=np.min(grid[:,grid_cols.index(color_mode)]), vmax=np.max(grid[:,grid_cols.index(color_mode)]), zorder=5) # 2-1) Draw the grid lines # Check as a function of LogQ and Tot[O]+12. Where are these ? u = grid_cols.index('LogQ') v = grid_cols.index('Tot[O]+12') for i in [u,v]: # Here, 'var' plays the role of 'q' or 'z' depending on 'i'. for var in np.unique(grid[:,i]): # Plot the grid line ax1.plot(grid[grid[:,i]==var][:,grid_cols.index('Mix_x')], grid[grid[:,i]==var][:,grid_cols.index('Mix_y')], 'k-', lw = 1, zorder=1) # Plot the bad segments for bad_seg in bad_segs: ax1.plot([bad_seg[0][0],bad_seg[1][0]],[bad_seg[0][1],bad_seg[1][1]], 'r-', linewidth=4, zorder=0) # Now, also plot the data, if anything was provided ! if not(interp_data is None): # Compute the combined "observed" ratios data_comb = [np.zeros_like(data[0]),np.zeros_like(data[1])] for k in range(len(ratios.split(';'))): data_comb[0] += coeffs[0][k]*data[k] data_comb[1] += coeffs[1][k]*data[k] ax1.scatter(data_comb[0][interp_data == interp_data], data_comb[1][interp_data == interp_data], marker='s', c=interp_data[interp_data == interp_data], s=15, cmap = pyqz_cmap_0, edgecolor='k', vmin = np.min(grid[:,grid_cols.index(color_mode)]), vmax = np.max(grid[:,grid_cols.index(color_mode)]), zorder=2, alpha=0.35) # Plot also the points outside the grid ? # Which are they ? Need to check if they have a valid input first ! # mind the "~" to invert the bools ! isn't this cool ? my_out_pts = ~np.isnan(data_comb[0]) * ~np.isnan(data_comb[1]) * \ np.isnan(interp_data) # Don't do this if this is a test with fullgrid_x ... ax1.scatter(data_comb[0][my_out_pts], data_comb[1][my_out_pts], marker = '^', facecolor = 'none', edgecolor = 'k', s=60) # 3) Plot the colorbar cb_ax = plt.subplot(gs[0,1]) cb = Colorbar(ax = cb_ax, mappable = pts, orientation='vertical') # Colorbar legend cb.set_label(color_mode, labelpad = 10) # 4) Axis names, kappa value, etc ... rats = ratios.split(';') # Make sure the labels look pretty in ALL cases ... labelx,labely = get_plot_labels(rats,coeffs) ax1.set_xlabel(labelx,labelpad = 10) ax1.set_ylabel(labely,labelpad = 10) if not(kappa in [np.inf, 'inf']) : kappa_str = r'$\kappa$ = '+str(kappa) else : kappa_str = r'$\kappa$ = $\infty$' ax1.text(0.85,0.9,kappa_str, horizontalalignment='left',verticalalignment='bottom', transform=ax1.transAxes) ax1.grid(True) if figname : fig.savefig(figname, bbox_inches='tight') if show_plot: plt.show() else: plt.close()