From f76f3ae9cf66839f057638ab76c7bc3b4364aaf3 Mon Sep 17 00:00:00 2001 From: Michel Aguena Date: Tue, 29 Mar 2022 19:23:13 +0200 Subject: [PATCH 01/12] add position to add_panel_bin_label --- clevar/match_metrics/plot_helper.py | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/clevar/match_metrics/plot_helper.py b/clevar/match_metrics/plot_helper.py index fe66d851..8872d838 100644 --- a/clevar/match_metrics/plot_helper.py +++ b/clevar/match_metrics/plot_helper.py @@ -86,7 +86,8 @@ def get_bin_label(edge_lower, edge_higher, def add_panel_bin_label(axes, edges_lower, edges_higher, - format_func=lambda v:v, prefix=''): + format_func=lambda v:v, prefix='', + position='top'): """ Adds label with bin range on the top of panel @@ -102,11 +103,25 @@ def add_panel_bin_label(axes, edges_lower, edges_higher, Function to format the values of the bins prefix: str Prefix to add to labels + position: str + Position od the panel, must be in: top, bottom, left, right """ for ax, vb, vt in zip(axes.flatten(), edges_lower, edges_higher): - topax = ax.twiny() - topax.set_xticks([]) - topax.set_xlabel(get_bin_label(vb, vt, format_func, prefix)) + if position=='top': + use_ax = ax.twiny() + use_ax.set_xticks([]) + set_label = use_ax.set_xlabel + elif position=='bottom': + set_label = ax.set_xlabel + elif position=='left': + set_label = ax.set_ylabel + elif position=='right': + use_ax = ax.twinx() + use_ax.set_yticks([]) + set_label = use_ax.set_ylabel + else: + raise ValueError(f'position (={position}) must be in: top, bottom, left, right') + set_label(get_bin_label(vb, vt, format_func, prefix)) def get_density_colors(x, y, xbins, ybins, ax_rotation=0, rotation_resolution=30, xscale='linear', From 683acfcb2078a3714c299f7f319674dfa60b14bd Mon Sep 17 00:00:00 2001 From: Michel Aguena Date: Tue, 29 Mar 2022 19:24:00 +0200 Subject: [PATCH 02/12] add basic fscore functions --- clevar/match_metrics/recovery/array_funcs.py | 137 ++++++++++++++++++ .../match_metrics/recovery/catalog_funcs.py | 120 +++++++++++++++ 2 files changed, 257 insertions(+) diff --git a/clevar/match_metrics/recovery/array_funcs.py b/clevar/match_metrics/recovery/array_funcs.py index d47c1bb8..b30b96df 100644 --- a/clevar/match_metrics/recovery/array_funcs.py +++ b/clevar/match_metrics/recovery/array_funcs.py @@ -330,3 +330,140 @@ def skyplot(ra, dec, is_matched, nside=256, nest=True, auto_lim=False, ra_lim=No info = {'fig':fig, 'nc_pix':all_pix, 'nc_mt_pix':mt_pix} return info + +def get_fscore(cat1_values1, cat1_values2, cat1_bins1, cat1_bins2, cat1_is_matched, + cat2_values1, cat2_values2, cat2_bins1, cat2_bins2, cat2_is_matched, + beta=1, pref='cat1'): + """ + Get recovery rate binned in 2 components + + Parameters + ---------- + values1, values2: array + Component 1 and 2. + bins1, bins2: array, int + Bins for components 1 and 2. + is_matched: array (boolean) + Boolean array indicating matching status + + Returns + ------- + dict + Binned recovery rate. Its sections are: + + * `recovery`: Recovery rate binned with (bin1, bin2).\ + bins where no cluster was found have nan value. + * `edges1`: The bin edges along the first dimension. + * `edges2`: The bin edges along the second dimension. + * `counts`: Counts of all clusters in bins. + * `matched`: Counts of matched clusters in bins. + """ + rec1 = get_recovery_rate( + cat1_values1, cat1_values2, cat1_bins1, cat1_bins2, cat1_is_matched) + rec2 = get_recovery_rate( + cat2_values1, cat2_values2, cat2_bins1, cat2_bins2, cat2_is_matched) + + r1_grid = np.outer(np.ones(rec2['recovery'].size), rec1['recovery'].flatten()) + r2_grid = np.outer(rec2['recovery'].flatten(), np.ones(rec1['recovery'].size)) + + beta2 = beta**2 + fscore = (1+beta2)*r1_grid*r2_grid + if pref=='cat1': + fscore /= (beta2*r1_grid+r2_grid) + elif pref=='cat2': + fscore /= (r1_grid+beta2*r2_grid) + else: + raise ValueError(f'pref (={pref}) must be cat1 or cat2') + fscore = fscore.reshape(*rec2['recovery'].shape, *rec1['recovery'].shape) + + out = {'fscore': fscore} + out.update({f'cat1_{k}':v for k, v in rec1.items()}) + out.update({f'cat2_{k}':v for k, v in rec2.items()}) + return out + +def plot_fscore(cat1_values1, cat1_values2, cat1_bins1, cat1_bins2, cat1_is_matched, + cat2_values1, cat2_values2, cat2_bins1, cat2_bins2, cat2_is_matched, + beta=1, pref='cat1', shape='steps', plt_kwargs={}, lines_kwargs_list=None, + fig_kwargs={}, add_label=True, add_legend=True, legend_format=lambda v: v, + legend_kwargs={}, label_format1=lambda v: v, label_format2=lambda v: v, + cat2_values1_label=None, cat2_values2_label=None): + """ + Plot recovery rate as lines in panels, with each line binned by bins1 + and each panel is based on the data inside a bins2 bin. + + Parameters + ---------- + values1, values2: array + Component 1 and 2. + bins1, bins2: array, int + Bins for components 1 and 2. + is_matched: array (boolean) + Boolean array indicating matching status + shape: str + Shape of the lines. Can be steps or line. + ax: matplotlib.axes + Ax to add plot + plt_kwargs: dict + Additional arguments for pylab.plot + panel_kwargs_list: list, None + List of additional arguments for plotting each panel (using pylab.plot). + Must have same size as len(bins2)-1 + fig_kwargs: dict + Additional arguments for plt.subplots + add_label: bool + Add bin label to panel + label_format: function + Function to format the values of the bins + + + Returns + ------- + info: dict + Information of data in the plots, it contains the sections: + + * `fig`: `matplotlib.figure.Figure` object. + * `axes`: `matplotlib.axes` used in the plot. + * `data`: Binned data used in the plot. It has the sections: + + * `recovery`: Recovery rate binned with (bin1, bin2).\ + bins where no cluster was found have nan value. + * `edges1`: The bin edges along the first dimension. + * `edges2`: The bin edges along the second dimension. + * `counts`: Counts of all clusters in bins. + * `matched`: Counts of matched clusters in bins. + """ + info = {'data': get_fscore( + cat1_values1, cat1_values2, cat1_bins1, cat1_bins2, cat1_is_matched, + cat2_values1, cat2_values2, cat2_bins1, cat2_bins2, cat2_is_matched, + beta=beta, pref=pref)} + ni = info['data']['cat2_edges1'].size-1 + nj = info['data']['cat2_edges2'].size-1 + fig_kwargs_ = dict(sharex=True, sharey=True, figsize=(8, 6)) + fig_kwargs_.update(fig_kwargs) + info.update({key: value for key, value in zip( + ('fig', 'axes'), plt.subplots(ni, nj, **fig_kwargs_))}) + add_legend_ = add_legend + for ax, fscore in zip( + info['axes'].flatten(), + info['data']['fscore'].reshape(ni*nj, *info['data']['cat1_recovery'].shape), + ): + ph.add_grid(ax) + ph.plot_histograms(fscore.T, info['data']['cat1_edges1'], info['data']['cat1_edges2'], + ax=ax, shape=shape, plt_kwargs=plt_kwargs, + lines_kwargs_list=lines_kwargs_list, + add_legend=add_legend_, legend_format=legend_format, + legend_kwargs=legend_kwargs) + add_legend_ = False + for ax in info['axes'][:,0]: + ax.set_ylabel('$F_{1}$ score') + if add_label: + ph.add_panel_bin_label( + info['axes'], info['data']['cat2_edges2'][:-1], info['data']['cat2_edges2'][1:], + prefix='' if cat2_values2_label is None else f'{cat2_values2_label}: ', + format_func=label_format2) + ph.add_panel_bin_label( + info['axes'][:,-1], info['data']['cat2_edges1'][:-1], info['data']['cat2_edges1'][1:], + prefix='' if cat2_values1_label is None else f'{cat2_values1_label}: ', + format_func=label_format1, position='right') + + return info diff --git a/clevar/match_metrics/recovery/catalog_funcs.py b/clevar/match_metrics/recovery/catalog_funcs.py index 47331ca9..4c792646 100644 --- a/clevar/match_metrics/recovery/catalog_funcs.py +++ b/clevar/match_metrics/recovery/catalog_funcs.py @@ -358,3 +358,123 @@ def skyplot(cat, matching_type, nside=256, nest=True, mask=None, mask_unmatched= cat['ra'][mask_], cat['dec'][mask_], is_matched[mask_], nside=nside, nest=nest, auto_lim=auto_lim, ra_lim=ra_lim, dec_lim=dec_lim, recovery_label=recovery_label, fig=fig, figsize=figsize, **kwargs) + + +def _plot_fscore_base(pltfunc, cat1, cat1_col1, cat1_col2, cat1_bins1, cat1_bins2, + cat2, cat2_col1, cat2_col2, cat2_bins1, cat2_bins2, matching_type, + mask1=None, mask2=None, mask_unmatched1=None, mask_unmatched2=None, + **kwargs): + """ + Adapts local function to use a ArrayFuncs function. + + Parameters + ---------- + pltfunc: function + ArrayFuncs function + cat: clevar.ClCatalog + ClCatalog with matching information + col1, col2: str + Names of columns 1 and 2. + bins1, bins2: array, int + Bins for components 1 and 2. + matching_type: str + Type of matching to be considered. Must be in: + 'cross', 'cat1', 'cat2', 'multi_cat1', 'multi_cat2', 'multi_join' + mask: array + Mask of unwanted clusters + mask_unmatched: array + Mask of unwanted unmatched clusters (ex: out of footprint) + **kwargs: + Additional arguments to be passed to pltfunc + + Returns + ------- + Same as pltfunc + """ + c1_mask, c1_is_matched = _rec_masks(cat1, matching_type, mask1, mask_unmatched1) + c2_mask, c2_is_matched = _rec_masks(cat2, matching_type, mask2, mask_unmatched2) + # make sure bins stay consistent regardless of mask + c1_edges1, c1_edges2 = np.histogram2d(cat1[cat1_col1], cat1[cat1_col2], + bins=(cat1_bins1, cat1_bins2))[1:] + c2_edges1, c2_edges2 = np.histogram2d(cat2[cat2_col1], cat2[cat2_col2], + bins=(cat2_bins1, cat2_bins2))[1:] + return pltfunc( + cat1[cat1_col1][c1_mask], cat1[cat1_col2][c1_mask], c1_edges1, c1_edges2, c1_is_matched[c1_mask], + cat2[cat2_col1][c2_mask], cat2[cat2_col2][c2_mask], c2_edges1, c2_edges2, c2_is_matched[c2_mask], + **kwargs) + + +def plot_fscore(cat1, cat1_col1, cat1_col2, cat1_bins1, cat1_bins2, + cat2, cat2_col1, cat2_col2, cat2_bins1, cat2_bins2, + matching_type, beta=1, pref='cat1', xlabel=None, ylabel=None, + scale1='linear', **kwargs): + """ + Plot recovery rate as lines, with each line binned by bins1 inside a bin of bins2. + + Parameters + ---------- + cat: clevar.ClCatalog + ClCatalog with matching information + col1, col2: str + Names of columns 1 and 2. + bins1, bins2: array, int + Bins for components 1 and 2. + matching_type: str + Type of matching to be considered. Must be in: + 'cross', 'cat1', 'cat2', 'multi_cat1', 'multi_cat2', 'multi_join' + mask: array + Mask of unwanted clusters + mask_unmatched: array + Mask of unwanted unmatched clusters (ex: out of footprint) + + Other parameters + ---------------- + shape: str + Shape of the lines. Can be steps or line. + ax: matplotlib.axes + Ax to add plot + xlabel: str + Label of component 1. Default is col1. + ylabel: str + Label of recovery rate. + scale1: str + Scale of col 1 component + plt_kwargs: dict + Additional arguments for pylab.plot + lines_kwargs_list: list, None + List of additional arguments for plotting each line (using pylab.plot). + Must have same size as len(bins2)-1 + add_legend: bool + Add legend of bins + legend_format: function + Function to format the values of the bins in legend + legend_kwargs: dict + Additional arguments for pylab.legend + + Returns + ------- + info: dict + Information of data in the plots, it contains the sections: + + * `ax`: ax used in the plot. + * `data`: Binned data used in the plot. It has the sections: + + * `recovery`: Recovery rate binned with (bin1, bin2).\ + bins where no cluster was found have nan value. + * `edges1`: The bin edges along the first dimension. + * `edges2`: The bin edges along the second dimension. + * `counts`: Counts of all clusters in bins. + * `matched`: Counts of matched clusters in bins. + """ + info = _plot_fscore_base(array_funcs.plot_fscore, + cat1, cat1_col1, cat1_col2, cat1_bins1, cat1_bins2, + cat2, cat2_col1, cat2_col2, cat2_bins1, cat2_bins2, + matching_type, beta=beta, pref=pref, **kwargs) + for ax in info['axes'][-1]: + ax.set_xlabel(xlabel if xlabel else f'${cat1.labels[cat1_col1]}$') + for ax in info['axes'][:, 0]: + ax.set_ylabel(ylabel if ylabel else f'$F_{beta}$ score') + for ax in info['axes'].flatten(): + ax.set_xscale(scale1) + ax.set_ylim(-.01, 1.05) + return info From 39cff4d09b01d297a9d766929e192512f4b17c3c Mon Sep 17 00:00:00 2001 From: Michel Aguena Date: Fri, 1 Apr 2022 11:26:54 +0200 Subject: [PATCH 03/12] update docstring --- clevar/match_metrics/recovery/array_funcs.py | 25 ++++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/clevar/match_metrics/recovery/array_funcs.py b/clevar/match_metrics/recovery/array_funcs.py index b30b96df..eb5b1df1 100644 --- a/clevar/match_metrics/recovery/array_funcs.py +++ b/clevar/match_metrics/recovery/array_funcs.py @@ -335,16 +335,27 @@ def get_fscore(cat1_values1, cat1_values2, cat1_bins1, cat1_bins2, cat1_is_match cat2_values1, cat2_values2, cat2_bins1, cat2_bins2, cat2_is_matched, beta=1, pref='cat1'): """ - Get recovery rate binned in 2 components + Computes fscore Parameters ---------- - values1, values2: array - Component 1 and 2. - bins1, bins2: array, int - Bins for components 1 and 2. - is_matched: array (boolean) - Boolean array indicating matching status + cat1_values1, cat2_values2: array + Component 1 and 2 of catalog 1. + cat1_bins1, cat1_bins2: array, int + Bins for components 1 and 2 of catalog 1. + cat1_is_matched: array (boolean) + Boolean array indicating matching status of catalog 1. + cat2_values1, cat2_values2: array + Component 1 and 2 of catalog 2. + cat2_bins1, cat2_bins2: array, int + Bins for components 1 and 2 of catalog 2. + cat2_is_matched: array (boolean) + Boolean array indicating matching status of catalog 2. + beta: float + Additional recall weight in f-score + pref: str + Peference to which recovery rate beta is applied, must be cat1 or cat2. + Returns ------- From 177e051606821cf0a5e49bfff221e4d564d5427e Mon Sep 17 00:00:00 2001 From: Michel Aguena Date: Fri, 1 Apr 2022 11:52:42 +0200 Subject: [PATCH 04/12] add to par_order plot_fscore --- clevar/match_metrics/recovery/array_funcs.py | 150 +++++++++++-------- clevar/utils.py | 17 +++ 2 files changed, 101 insertions(+), 66 deletions(-) diff --git a/clevar/match_metrics/recovery/array_funcs.py b/clevar/match_metrics/recovery/array_funcs.py index eb5b1df1..0cb94b22 100644 --- a/clevar/match_metrics/recovery/array_funcs.py +++ b/clevar/match_metrics/recovery/array_funcs.py @@ -5,7 +5,7 @@ import numpy as np import healpy as hp -from ...utils import none_val +from ...utils import none_val, index_list from .. import plot_helper as ph from ..plot_helper import plt @@ -360,14 +360,11 @@ def get_fscore(cat1_values1, cat1_values2, cat1_bins1, cat1_bins2, cat1_is_match Returns ------- dict - Binned recovery rate. Its sections are: + Binned fscore and recovery rate. Its sections are: - * `recovery`: Recovery rate binned with (bin1, bin2).\ - bins where no cluster was found have nan value. - * `edges1`: The bin edges along the first dimension. - * `edges2`: The bin edges along the second dimension. - * `counts`: Counts of all clusters in bins. - * `matched`: Counts of matched clusters in bins. + * `fscore`: F-n score binned with (cat2_bins1, cat2_bins2, cat1_bins1, cat1_bins2). + * `cat1`: Dictionary with recovery rate of catalog 1, see get_recovery_rate for info. + * `cat2`: Dictionary with recovery rate of catalog 2, see get_recovery_rate for info. """ rec1 = get_recovery_rate( cat1_values1, cat1_values2, cat1_bins1, cat1_bins2, cat1_is_matched) @@ -385,46 +382,61 @@ def get_fscore(cat1_values1, cat1_values2, cat1_bins1, cat1_bins2, cat1_is_match fscore /= (r1_grid+beta2*r2_grid) else: raise ValueError(f'pref (={pref}) must be cat1 or cat2') - fscore = fscore.reshape(*rec2['recovery'].shape, *rec1['recovery'].shape) - - out = {'fscore': fscore} - out.update({f'cat1_{k}':v for k, v in rec1.items()}) - out.update({f'cat2_{k}':v for k, v in rec2.items()}) - return out - -def plot_fscore(cat1_values1, cat1_values2, cat1_bins1, cat1_bins2, cat1_is_matched, - cat2_values1, cat2_values2, cat2_bins1, cat2_bins2, cat2_is_matched, - beta=1, pref='cat1', shape='steps', plt_kwargs={}, lines_kwargs_list=None, - fig_kwargs={}, add_label=True, add_legend=True, legend_format=lambda v: v, - legend_kwargs={}, label_format1=lambda v: v, label_format2=lambda v: v, - cat2_values1_label=None, cat2_values2_label=None): + return {'fscore': fscore.reshape(*rec2['recovery'].shape, *rec1['recovery'].shape), + 'cat1':rec1, 'cat2':rec2} + +def plot_fscore(cat1_val1, cat1_val2, cat1_bins1, cat1_bins2, cat1_is_matched, + cat2_val1, cat2_val2, cat2_bins1, cat2_bins2, cat2_is_matched, + beta=1, pref='cat1', par_order=(0, 1, 2, 3), shape='steps', plt_kwargs={}, + lines_kwargs_list=None, fig_kwargs={}, legend_kwargs={}, + cat1_val1_label=None, cat1_val2_label=None, + cat2_val1_label=None, cat2_val2_label=None, + cat1_datalabel1_format=lambda v: v, cat1_datalabel2_format=lambda v: v, + cat2_datalabel1_format=lambda v: v, cat2_datalabel2_format=lambda v: v, + ): """ Plot recovery rate as lines in panels, with each line binned by bins1 and each panel is based on the data inside a bins2 bin. Parameters ---------- - values1, values2: array - Component 1 and 2. - bins1, bins2: array, int - Bins for components 1 and 2. - is_matched: array (boolean) - Boolean array indicating matching status + cat1_values1, cat2_values2: array + Component 1 and 2 of catalog 1. + cat1_bins1, cat1_bins2: array, int + Bins for components 1 and 2 of catalog 1. + cat1_is_matched: array (boolean) + Boolean array indicating matching status of catalog 1. + cat2_values1, cat2_values2: array + Component 1 and 2 of catalog 2. + cat2_bins1, cat2_bins2: array, int + Bins for components 1 and 2 of catalog 2. + cat2_is_matched: array (boolean) + Boolean array indicating matching status of catalog 2. + beta: float + Additional recall weight in f-score + pref: str + Peference to which recovery rate beta is applied, must be cat1 or cat2. + par_order: list, bool + It transposes quantities used, must be a percolation of (0, 1, 2, 3). shape: str Shape of the lines. Can be steps or line. - ax: matplotlib.axes - Ax to add plot plt_kwargs: dict Additional arguments for pylab.plot - panel_kwargs_list: list, None - List of additional arguments for plotting each panel (using pylab.plot). + lines_kwargs_list: list, None + List of additional arguments for plotting each line (using pylab.plot). Must have same size as len(bins2)-1 fig_kwargs: dict Additional arguments for plt.subplots - add_label: bool - Add bin label to panel - label_format: function - Function to format the values of the bins + legend_kwargs: dict + Additional arguments for pylab.legend + cat1_val1_label, cat1_val2_label: str + Labels for quantities 1 and 2 of catalog 1. + cat2_val1_label, cat2_val2_label: str + Labels for quantities 1 and 2 of catalog 2. + cat1_datalabel1_format, cat1_datalabel2_format: function + Function to format the values of labels for catalog 1. + cat2_datalabel1_format, cat2_datalabel2_format: function + Function to format the values of labels for catalog 2. Returns @@ -436,45 +448,51 @@ def plot_fscore(cat1_values1, cat1_values2, cat1_bins1, cat1_bins2, cat1_is_matc * `axes`: `matplotlib.axes` used in the plot. * `data`: Binned data used in the plot. It has the sections: - * `recovery`: Recovery rate binned with (bin1, bin2).\ - bins where no cluster was found have nan value. - * `edges1`: The bin edges along the first dimension. - * `edges2`: The bin edges along the second dimension. - * `counts`: Counts of all clusters in bins. - * `matched`: Counts of matched clusters in bins. + * `fscore`: F-n score binned with (cat2_bins1, cat2_bins2, cat1_bins1, cat1_bins2). + * `cat1`: Dictionary with recovery rate of catalog 1, see get_recovery_rate. + * `cat2`: Dictionary with recovery rate of catalog 2, see get_recovery_rate. """ info = {'data': get_fscore( - cat1_values1, cat1_values2, cat1_bins1, cat1_bins2, cat1_is_matched, - cat2_values1, cat2_values2, cat2_bins1, cat2_bins2, cat2_is_matched, + cat1_val1, cat1_val2, cat1_bins1, cat1_bins2, cat1_is_matched, + cat2_val1, cat2_val2, cat2_bins1, cat2_bins2, cat2_is_matched, beta=beta, pref=pref)} - ni = info['data']['cat2_edges1'].size-1 - nj = info['data']['cat2_edges2'].size-1 + + # Order of parameters + edges = index_list([info['data']['cat1']['edges1'], info['data']['cat1']['edges2'], + info['data']['cat2']['edges1'], info['data']['cat2']['edges2']], + par_order) + labels = index_list([cat1_val1_label, cat1_val2_label, + cat2_val1_label, cat2_val2_label], par_order) + label_formats = index_list( + [cat1_datalabel1_format, cat1_datalabel2_format, + cat2_datalabel1_format, cat2_datalabel2_format], par_order) + tr_order = index_list([2, 3, 0, 1], index_list(par_order, [2, 3, 0, 1])) + + ni = edges[2].size-1 + nj = edges[3].size-1 fig_kwargs_ = dict(sharex=True, sharey=True, figsize=(8, 6)) fig_kwargs_.update(fig_kwargs) info.update({key: value for key, value in zip( ('fig', 'axes'), plt.subplots(ni, nj, **fig_kwargs_))}) - add_legend_ = add_legend - for ax, fscore in zip( - info['axes'].flatten(), - info['data']['fscore'].reshape(ni*nj, *info['data']['cat1_recovery'].shape), - ): - ph.add_grid(ax) - ph.plot_histograms(fscore.T, info['data']['cat1_edges1'], info['data']['cat1_edges2'], - ax=ax, shape=shape, plt_kwargs=plt_kwargs, - lines_kwargs_list=lines_kwargs_list, - add_legend=add_legend_, legend_format=legend_format, - legend_kwargs=legend_kwargs) - add_legend_ = False + add_legend = True + for axl, fscl in zip(info['axes'], info['data']['fscore'].transpose(*tr_order)): + for ax, fsc in zip(axl, fscl): + ph.add_grid(ax) + ph.plot_histograms(fsc.T, edges[0], edges[1], + ax=ax, shape=shape, plt_kwargs=plt_kwargs, + lines_kwargs_list=lines_kwargs_list, + add_legend=add_legend, legend_format=label_formats[1], + legend_kwargs=legend_kwargs) + add_legend = False for ax in info['axes'][:,0]: ax.set_ylabel('$F_{1}$ score') - if add_label: - ph.add_panel_bin_label( - info['axes'], info['data']['cat2_edges2'][:-1], info['data']['cat2_edges2'][1:], - prefix='' if cat2_values2_label is None else f'{cat2_values2_label}: ', - format_func=label_format2) - ph.add_panel_bin_label( - info['axes'][:,-1], info['data']['cat2_edges1'][:-1], info['data']['cat2_edges1'][1:], - prefix='' if cat2_values1_label is None else f'{cat2_values1_label}: ', - format_func=label_format1, position='right') + ph.add_panel_bin_label( + info['axes'], edges[3][:-1], edges[3][1:], + prefix='' if labels[3] is None else f'{labels[3]}: ', + format_func=label_formats[3]) + ph.add_panel_bin_label( + info['axes'][:,-1], edges[2][:-1], edges[2][1:], + prefix='' if labels[2] is None else f'{labels[2]}: ', + format_func=label_formats[2], position='right') return info diff --git a/clevar/utils.py b/clevar/utils.py index 48f1c052..670eaead 100644 --- a/clevar/utils.py +++ b/clevar/utils.py @@ -1,6 +1,23 @@ import numpy as np veclen = np.vectorize(len) +def index_list(input_list, indexes): + """Get list sorted by index list + + Parameters + ---------- + input_list: list + Input list + indexes: list + List of indexes + + Returns + ------- + list + input_list sorted by indexes. + """ + return [input_list[i] for i in indexes] + def none_val(value, none_value): """ Set default value to be returned if input is None From 2230e73364ff403d0a5b7be96403d571d312b1ff Mon Sep 17 00:00:00 2001 From: Michel Aguena Date: Fri, 1 Apr 2022 12:05:40 +0200 Subject: [PATCH 05/12] fix label in plot_fscore --- clevar/match_metrics/recovery/array_funcs.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/clevar/match_metrics/recovery/array_funcs.py b/clevar/match_metrics/recovery/array_funcs.py index 0cb94b22..62ec138e 100644 --- a/clevar/match_metrics/recovery/array_funcs.py +++ b/clevar/match_metrics/recovery/array_funcs.py @@ -485,7 +485,9 @@ def plot_fscore(cat1_val1, cat1_val2, cat1_bins1, cat1_bins2, cat1_is_matched, legend_kwargs=legend_kwargs) add_legend = False for ax in info['axes'][:,0]: - ax.set_ylabel('$F_{1}$ score') + ax.set_ylabel(f'$F_{{{beta}}}$ score') + for ax in info['axes'][-1,:]: + ax.set_xlabel(f'${labels[0]}$') ph.add_panel_bin_label( info['axes'], edges[3][:-1], edges[3][1:], prefix='' if labels[3] is None else f'{labels[3]}: ', From 741c347f78ea0f86520edfc1b0d114dbfd9c7658 Mon Sep 17 00:00:00 2001 From: Michel Aguena Date: Fri, 1 Apr 2022 12:19:11 +0200 Subject: [PATCH 06/12] minor fixes and documentation on catalog_funcs.fscore --- .../match_metrics/recovery/catalog_funcs.py | 100 +++++++++++------- 1 file changed, 63 insertions(+), 37 deletions(-) diff --git a/clevar/match_metrics/recovery/catalog_funcs.py b/clevar/match_metrics/recovery/catalog_funcs.py index 4c792646..535651d0 100644 --- a/clevar/match_metrics/recovery/catalog_funcs.py +++ b/clevar/match_metrics/recovery/catalog_funcs.py @@ -362,8 +362,8 @@ def skyplot(cat, matching_type, nside=256, nest=True, mask=None, mask_unmatched= def _plot_fscore_base(pltfunc, cat1, cat1_col1, cat1_col2, cat1_bins1, cat1_bins2, cat2, cat2_col1, cat2_col2, cat2_bins1, cat2_bins2, matching_type, - mask1=None, mask2=None, mask_unmatched1=None, mask_unmatched2=None, - **kwargs): + cat1_mask=None, cat1_mask_unmatched=None, cat2_mask=None, + cat2_mask_unmatched=None, **kwargs): """ Adapts local function to use a ArrayFuncs function. @@ -380,10 +380,14 @@ def _plot_fscore_base(pltfunc, cat1, cat1_col1, cat1_col2, cat1_bins1, cat1_bins matching_type: str Type of matching to be considered. Must be in: 'cross', 'cat1', 'cat2', 'multi_cat1', 'multi_cat2', 'multi_join' - mask: array - Mask of unwanted clusters - mask_unmatched: array - Mask of unwanted unmatched clusters (ex: out of footprint) + cat1_mask: array + Mask of unwanted clusters of catalog 1. + cat1_mask_unmatched: array + Mask of unwanted unmatched clusters (ex: out of footprint) of catalog 1. + cat2_mask: array + Mask of unwanted clusters of catalog 2. + cat2_mask_unmatched: array + Mask of unwanted unmatched clusters (ex: out of footprint) of catalog 2. **kwargs: Additional arguments to be passed to pltfunc @@ -391,8 +395,8 @@ def _plot_fscore_base(pltfunc, cat1, cat1_col1, cat1_col2, cat1_bins1, cat1_bins ------- Same as pltfunc """ - c1_mask, c1_is_matched = _rec_masks(cat1, matching_type, mask1, mask_unmatched1) - c2_mask, c2_is_matched = _rec_masks(cat2, matching_type, mask2, mask_unmatched2) + c1_mask, c1_is_matched = _rec_masks(cat1, matching_type, cat1_mask, cat1_mask_unmatched) + c2_mask, c2_is_matched = _rec_masks(cat2, matching_type, cat2_mask, cat2_mask_unmatched) # make sure bins stay consistent regardless of mask c1_edges1, c1_edges2 = np.histogram2d(cat1[cat1_col1], cat1[cat1_col2], bins=(cat1_bins1, cat1_bins2))[1:] @@ -406,33 +410,42 @@ def _plot_fscore_base(pltfunc, cat1, cat1_col1, cat1_col2, cat1_bins1, cat1_bins def plot_fscore(cat1, cat1_col1, cat1_col2, cat1_bins1, cat1_bins2, cat2, cat2_col1, cat2_col2, cat2_bins1, cat2_bins2, - matching_type, beta=1, pref='cat1', xlabel=None, ylabel=None, - scale1='linear', **kwargs): + matching_type, beta=1, pref='cat1', + cat1_mask=None, cat1_mask_unmatched=None, cat2_mask=None, cat2_mask_unmatched=None, + xlabel=None, ylabel=None, scale1='linear', **kwargs): """ Plot recovery rate as lines, with each line binned by bins1 inside a bin of bins2. Parameters ---------- - cat: clevar.ClCatalog + cat1: clevar.ClCatalog ClCatalog with matching information - col1, col2: str - Names of columns 1 and 2. - bins1, bins2: array, int - Bins for components 1 and 2. + cat1_col1, cat1_col2: str + Names of columns 1 and 2 of catalog 1. + cat1_bins1, cat1_bins2: array, int + Bins for components 1 and 2 of catalog 1. + cat2: clevar.ClCatalog + ClCatalog with matching information + cat2_col1, cat2_col2: str + Names of columns 1 and 2 of catalog 2. + cat2_bins1, cat2_bins2: array, int + Bins for components 1 and 2 of catalog 2. matching_type: str Type of matching to be considered. Must be in: 'cross', 'cat1', 'cat2', 'multi_cat1', 'multi_cat2', 'multi_join' - mask: array - Mask of unwanted clusters - mask_unmatched: array - Mask of unwanted unmatched clusters (ex: out of footprint) + cat1_mask: array + Mask of unwanted clusters of catalog 1. + cat1_mask_unmatched: array + Mask of unwanted unmatched clusters (ex: out of footprint) of catalog 1. + cat2_mask: array + Mask of unwanted clusters of catalog 2. + cat2_mask_unmatched: array + Mask of unwanted unmatched clusters (ex: out of footprint) of catalog 2. Other parameters ---------------- shape: str Shape of the lines. Can be steps or line. - ax: matplotlib.axes - Ax to add plot xlabel: str Label of component 1. Default is col1. ylabel: str @@ -441,39 +454,52 @@ def plot_fscore(cat1, cat1_col1, cat1_col2, cat1_bins1, cat1_bins2, Scale of col 1 component plt_kwargs: dict Additional arguments for pylab.plot + fig_kwargs: dict + Additional arguments for plt.subplots lines_kwargs_list: list, None List of additional arguments for plotting each line (using pylab.plot). Must have same size as len(bins2)-1 - add_legend: bool - Add legend of bins - legend_format: function - Function to format the values of the bins in legend legend_kwargs: dict Additional arguments for pylab.legend + cat1_val1_label, cat1_val2_label: str + Labels for quantities 1 and 2 of catalog 1. + cat2_val1_label, cat2_val2_label: str + Labels for quantities 1 and 2 of catalog 2. + cat1_datalabel1_format, cat1_datalabel2_format: function + Function to format the values of labels for catalog 1. + cat2_datalabel1_format, cat2_datalabel2_format: function + Function to format the values of labels for catalog 2. Returns ------- info: dict Information of data in the plots, it contains the sections: - * `ax`: ax used in the plot. + * `fig`: `matplotlib.figure.Figure` object. + * `axes`: `matplotlib.axes` used in the plot. * `data`: Binned data used in the plot. It has the sections: - * `recovery`: Recovery rate binned with (bin1, bin2).\ - bins where no cluster was found have nan value. - * `edges1`: The bin edges along the first dimension. - * `edges2`: The bin edges along the second dimension. - * `counts`: Counts of all clusters in bins. - * `matched`: Counts of matched clusters in bins. + * `fscore`: F-n score binned with (cat2_bins1, cat2_bins2, cat1_bins1, cat1_bins2). + * `cat1`: Dictionary with recovery rate of catalog 1, see get_recovery_rate. + * `cat2`: Dictionary with recovery rate of catalog 2, see get_recovery_rate. """ + kwargs_ = { + 'cat1_val1_label':cat1.labels[cat1_col1], + 'cat1_val2_label':cat1.labels[cat1_col2], + 'cat2_val1_label':cat2.labels[cat2_col1], + 'cat2_val2_label':cat2.labels[cat2_col2], + } + kwargs_.update(kwargs) info = _plot_fscore_base(array_funcs.plot_fscore, cat1, cat1_col1, cat1_col2, cat1_bins1, cat1_bins2, cat2, cat2_col1, cat2_col2, cat2_bins1, cat2_bins2, - matching_type, beta=beta, pref=pref, **kwargs) - for ax in info['axes'][-1]: - ax.set_xlabel(xlabel if xlabel else f'${cat1.labels[cat1_col1]}$') - for ax in info['axes'][:, 0]: - ax.set_ylabel(ylabel if ylabel else f'$F_{beta}$ score') + matching_type, beta=beta, pref=pref, **kwargs_) + if xlabel: + for ax in info['axes'][-1]: + ax.set_xlabel(xlabel) + if ylabel: + for ax in info['axes'][:, 0]: + ax.set_ylabel(ylabel) for ax in info['axes'].flatten(): ax.set_xscale(scale1) ax.set_ylim(-.01, 1.05) From 0528885b273c069174bcfb1b721efb782d4a57b1 Mon Sep 17 00:00:00 2001 From: Michel Aguena Date: Fri, 1 Apr 2022 14:43:57 +0200 Subject: [PATCH 07/12] add fscore to recovery --- clevar/match_metrics/recovery/__init__.py | 2 +- .../match_metrics/recovery/catalog_funcs.py | 23 +++- clevar/match_metrics/recovery/funcs.py | 120 ++++++++++++++++++ 3 files changed, 138 insertions(+), 7 deletions(-) diff --git a/clevar/match_metrics/recovery/__init__.py b/clevar/match_metrics/recovery/__init__.py index 72b52e2f..7838308d 100644 --- a/clevar/match_metrics/recovery/__init__.py +++ b/clevar/match_metrics/recovery/__init__.py @@ -1,4 +1,4 @@ from . import array_funcs as ArrayFuncs from . import catalog_funcs as ClCatalogFuncs -from .funcs import plot, plot_panel, plot2D, skyplot +from .funcs import plot, plot_panel, plot2D, skyplot, plot_fscore diff --git a/clevar/match_metrics/recovery/catalog_funcs.py b/clevar/match_metrics/recovery/catalog_funcs.py index 535651d0..933923e1 100644 --- a/clevar/match_metrics/recovery/catalog_funcs.py +++ b/clevar/match_metrics/recovery/catalog_funcs.py @@ -410,9 +410,9 @@ def _plot_fscore_base(pltfunc, cat1, cat1_col1, cat1_col2, cat1_bins1, cat1_bins def plot_fscore(cat1, cat1_col1, cat1_col2, cat1_bins1, cat1_bins2, cat2, cat2_col1, cat2_col2, cat2_bins1, cat2_bins2, - matching_type, beta=1, pref='cat1', + matching_type, beta=1, pref='cat1', par_order=(0, 1, 2, 3), cat1_mask=None, cat1_mask_unmatched=None, cat2_mask=None, cat2_mask_unmatched=None, - xlabel=None, ylabel=None, scale1='linear', **kwargs): + xlabel=None, ylabel=None, xscale='linear', **kwargs): """ Plot recovery rate as lines, with each line binned by bins1 inside a bin of bins2. @@ -433,6 +433,12 @@ def plot_fscore(cat1, cat1_col1, cat1_col2, cat1_bins1, cat1_bins2, matching_type: str Type of matching to be considered. Must be in: 'cross', 'cat1', 'cat2', 'multi_cat1', 'multi_cat2', 'multi_join' + beta: float + Additional recall weight in f-score + pref: str + Peference to which recovery rate beta is applied, must be cat1 or cat2. + par_order: list, bool + It transposes quantities used, must be a percolation of (0, 1, 2, 3). cat1_mask: array Mask of unwanted clusters of catalog 1. cat1_mask_unmatched: array @@ -450,8 +456,8 @@ def plot_fscore(cat1, cat1_col1, cat1_col2, cat1_bins1, cat1_bins2, Label of component 1. Default is col1. ylabel: str Label of recovery rate. - scale1: str - Scale of col 1 component + xscale: str + Scale of x axis. plt_kwargs: dict Additional arguments for pylab.plot fig_kwargs: dict @@ -488,12 +494,17 @@ def plot_fscore(cat1, cat1_col1, cat1_col2, cat1_bins1, cat1_bins2, 'cat1_val2_label':cat1.labels[cat1_col2], 'cat2_val1_label':cat2.labels[cat2_col1], 'cat2_val2_label':cat2.labels[cat2_col2], + 'cat1_mask':cat1_mask, + 'cat1_mask_unmatched':cat1_mask_unmatched, + 'cat2_mask':cat2_mask, + 'cat2_mask_unmatched':cat2_mask_unmatched, } kwargs_.update(kwargs) info = _plot_fscore_base(array_funcs.plot_fscore, cat1, cat1_col1, cat1_col2, cat1_bins1, cat1_bins2, cat2, cat2_col1, cat2_col2, cat2_bins1, cat2_bins2, - matching_type, beta=beta, pref=pref, **kwargs_) + matching_type, beta=beta, pref=pref, par_order=par_order, + **kwargs_) if xlabel: for ax in info['axes'][-1]: ax.set_xlabel(xlabel) @@ -501,6 +512,6 @@ def plot_fscore(cat1, cat1_col1, cat1_col2, cat1_bins1, cat1_bins2, for ax in info['axes'][:, 0]: ax.set_ylabel(ylabel) for ax in info['axes'].flatten(): - ax.set_xscale(scale1) + ax.set_xscale(xscale) ax.set_ylim(-.01, 1.05) return info diff --git a/clevar/match_metrics/recovery/funcs.py b/clevar/match_metrics/recovery/funcs.py index 39abc75d..1a36b136 100644 --- a/clevar/match_metrics/recovery/funcs.py +++ b/clevar/match_metrics/recovery/funcs.py @@ -433,3 +433,123 @@ def skyplot(cat, matching_type, nside=256, nest=True, mask=None, mask_unmatched= cat, matching_type, nside=nside, nest=nest, mask=mask, mask_unmatched=mask_unmatched, auto_lim=auto_lim, ra_lim=ra_lim, dec_lim=dec_lim, recovery_label=recovery_label, fig=fig, figsize=figsize, **kwargs) + + +def plot_fscore(cat1, cat1_redshift_bins, cat1_mass_bins, cat2, cat2_redshift_bins, cat2_mass_bins, + matching_type, beta=1, pref='cat1', par_order=(0, 1, 2, 3), cat1_mask=None, + cat1_mask_unmatched=None, cat2_mask=None, cat2_mask_unmatched=None, log_mass=True, + fscore_label=None, **kwargs): + + """ + Plot recovery rate as lines in panels, with each line binned by redshift + and each panel is based on the data inside a mass bin. + + Parameters + ---------- + cat1: clevar.ClCatalog + ClCatalog with matching information + cat1_redshift_bins: array, int + Bins for redshift of catalog 1. + cat1_mass_bins: array, int + Bins for mass of catalog 1. + cat2: clevar.ClCatalog + ClCatalog with matching information + cat2_redshift_bins: array, int + Bins for redshift of catalog 2. + cat2_mass_bins: array, int + Bins for mass of catalog 2. + matching_type: str + Type of matching to be considered. Must be in: + 'cross', 'cat1', 'cat2', 'multi_cat1', 'multi_cat2', 'multi_join' + beta: float + Additional recall weight in f-score + pref: str + Peference to which recovery rate beta is applied, must be cat1 or cat2. + par_order: list, bool + It transposes quantities used, must be a percolation of (0, 1, 2, 3). + log_mass: bool + Plot mass in log scale + cat1_mask: array + Mask of unwanted clusters of catalog 1. + cat1_mask_unmatched: array + Mask of unwanted unmatched clusters (ex: out of footprint) of catalog 1. + cat2_mask: array + Mask of unwanted clusters of catalog 2. + cat2_mask_unmatched: array + Mask of unwanted unmatched clusters (ex: out of footprint) of catalog 2. + + Other parameters + ---------------- + shape: str + Shape of the lines. Can be steps or line. + cat1_redshift_label, cat1_mass_label: str + Label for redshift and mass of catalog 1. + cat2_redshift_label, cat2_mass_label: str + Label for redshift and mass of catalog 2. + fscore_label: str + Label for fscore. + plt_kwargs: dict + Additional arguments for pylab.plot + fig_kwargs: dict + Additional arguments for plt.subplots + lines_kwargs_list: list, None + List of additional arguments for plotting each line (using pylab.plot). + Must have same size as len(bins2)-1 + legend_kwargs: dict + Additional arguments for pylab.legend + cat1_val1_label, cat1_val2_label: str + Labels for quantities 1 and 2 of catalog 1. + cat2_val1_label, cat2_val2_label: str + Labels for quantities 1 and 2 of catalog 2. + cat1_redshift_format, cat1_mass_format: function + Function to format the values of labels for catalog 1. + cat2_redshift_format, cat2_mass_format: function + Function to format the values of labels for catalog 2. + cat1_redshift_fmt, cat1_mass_fmt: str + Format the values of labels for catalog 1 (ex: '.2f'). + cat2_redshift_fmt, cat2_mass_fmt: str + Format the values of labels for catalog 2 (ex: '.2f'). + + Returns + ------- + info: dict + Information of data in the plots, it contains the sections: + + * `fig`: `matplotlib.figure.Figure` object. + * `axes`: `matplotlib.axes` used in the plot. + * `data`: Binned data used in the plot. It has the sections: + + * `fscore`: F-n score binned with (cat2_redshift_bins, cat2_mass_bins, \ + cat1_redshift_bins, cat1_mass_bins). + * `cat1`: Dictionary with recovery rate of catalog 1, see get_recovery_rate. + * `cat2`: Dictionary with recovery rate of catalog 2, see get_recovery_rate. + """ + kwargs_ = {} + kwargs_.update(kwargs) + # labels + kwargs_['cat1_val1_label'] = kwargs_.pop('cat1_redshift_label', cat1.labels['z']) + kwargs_['cat1_val2_label'] = kwargs_.pop('cat1_mass_label', cat1.labels['mass']) + kwargs_['cat2_val1_label'] = kwargs_.pop('cat2_redshift_label', cat2.labels['z']) + kwargs_['cat2_val2_label'] = kwargs_.pop('cat2_mass_label', cat2.labels['mass']) + # label formats + for i in '12': + ph._set_label_format( + kwargs_, f'cat{i}_redshiftlabel_format', f'cat{i}_redshiftlabel_fmt', + log=False, default_fmt=".2f") + ph._set_label_format( + kwargs_, f'cat{i}_masslabel_format', f'cat{i}_masslabel_fmt', + log=log_mass, default_fmt=".1f") + kwargs_['cat1_datalabel1_format'] = kwargs_.pop('cat1_redshiftlabel_format') + kwargs_['cat1_datalabel2_format'] = kwargs_.pop('cat1_masslabel_format') + kwargs_['cat2_datalabel1_format'] = kwargs_.pop('cat2_redshiftlabel_format') + kwargs_['cat2_datalabel2_format'] = kwargs_.pop('cat2_masslabel_format') + + info = catalog_funcs.plot_fscore( + cat1, 'z', 'mass', cat1_redshift_bins, cat1_mass_bins, + cat2, 'z', 'mass', cat2_redshift_bins, cat2_mass_bins, + matching_type, beta=beta, pref=pref, par_order=par_order, cat1_mask=cat1_mask, + cat1_mask_unmatched=cat1_mask_unmatched, cat2_mask=cat2_mask, + cat2_mask_unmatched=cat2_mask_unmatched, + xscale='log' if par_order[0] in (1, 3) else 'linear', + ylabel=fscore_label, **kwargs_) + return info From c56044c51c4650d410b1379b9b47ecfd96270bc4 Mon Sep 17 00:00:00 2001 From: m-aguena Date: Mon, 23 Sep 2024 02:29:11 -0700 Subject: [PATCH 08/12] format code --- clevar/match_metrics/plot_helper.py | 16 +- clevar/match_metrics/recovery/array_funcs.py | 189 ++++++++++++------ .../match_metrics/recovery/catalog_funcs.py | 124 +++++++++--- clevar/match_metrics/recovery/funcs.py | 85 +++++--- clevar/utils.py | 3 + 5 files changed, 294 insertions(+), 123 deletions(-) diff --git a/clevar/match_metrics/plot_helper.py b/clevar/match_metrics/plot_helper.py index 3ed6d86d..7d854a35 100644 --- a/clevar/match_metrics/plot_helper.py +++ b/clevar/match_metrics/plot_helper.py @@ -140,9 +140,9 @@ def get_bin_label(edge_lower, edge_higher, format_func=lambda v: v, prefix=""): return f"${prefix}[{format_func(edge_lower)}$ : ${format_func(edge_higher)}]$" -def add_panel_bin_label(axes, edges_lower, edges_higher, - format_func=lambda v:v, prefix='', - position='top'): +def add_panel_bin_label( + axes, edges_lower, edges_higher, format_func=lambda v: v, prefix="", position="top" +): """ Adds label with bin range on the top of panel @@ -162,20 +162,20 @@ def add_panel_bin_label(axes, edges_lower, edges_higher, Position od the panel, must be in: top, bottom, left, right """ for ax, vb, vt in zip(axes.flatten(), edges_lower, edges_higher): - if position=='top': + if position == "top": use_ax = ax.twiny() use_ax.set_xticks([]) set_label = use_ax.set_xlabel - elif position=='bottom': + elif position == "bottom": set_label = ax.set_xlabel - elif position=='left': + elif position == "left": set_label = ax.set_ylabel - elif position=='right': + elif position == "right": use_ax = ax.twinx() use_ax.set_yticks([]) set_label = use_ax.set_ylabel else: - raise ValueError(f'position (={position}) must be in: top, bottom, left, right') + raise ValueError(f"position (={position}) must be in: top, bottom, left, right") set_label(get_bin_label(vb, vt, format_func, prefix)) diff --git a/clevar/match_metrics/recovery/array_funcs.py b/clevar/match_metrics/recovery/array_funcs.py index 7b68e369..e795add2 100644 --- a/clevar/match_metrics/recovery/array_funcs.py +++ b/clevar/match_metrics/recovery/array_funcs.py @@ -404,9 +404,21 @@ def skyplot( info = {"fig": fig, "nc_pix": all_pix, "nc_mt_pix": mt_pix} return info -def get_fscore(cat1_values1, cat1_values2, cat1_bins1, cat1_bins2, cat1_is_matched, - cat2_values1, cat2_values2, cat2_bins1, cat2_bins2, cat2_is_matched, - beta=1, pref='cat1'): + +def get_fscore( + cat1_values1, + cat1_values2, + cat1_bins1, + cat1_bins2, + cat1_is_matched, + cat2_values1, + cat2_values2, + cat2_bins1, + cat2_bins2, + cat2_is_matched, + beta=1, + pref="cat1", +): """ Computes fscore @@ -439,34 +451,55 @@ def get_fscore(cat1_values1, cat1_values2, cat1_bins1, cat1_bins2, cat1_is_match * `cat1`: Dictionary with recovery rate of catalog 1, see get_recovery_rate for info. * `cat2`: Dictionary with recovery rate of catalog 2, see get_recovery_rate for info. """ - rec1 = get_recovery_rate( - cat1_values1, cat1_values2, cat1_bins1, cat1_bins2, cat1_is_matched) - rec2 = get_recovery_rate( - cat2_values1, cat2_values2, cat2_bins1, cat2_bins2, cat2_is_matched) + rec1 = get_recovery_rate(cat1_values1, cat1_values2, cat1_bins1, cat1_bins2, cat1_is_matched) + rec2 = get_recovery_rate(cat2_values1, cat2_values2, cat2_bins1, cat2_bins2, cat2_is_matched) - r1_grid = np.outer(np.ones(rec2['recovery'].size), rec1['recovery'].flatten()) - r2_grid = np.outer(rec2['recovery'].flatten(), np.ones(rec1['recovery'].size)) + r1_grid = np.outer(np.ones(rec2["recovery"].size), rec1["recovery"].flatten()) + r2_grid = np.outer(rec2["recovery"].flatten(), np.ones(rec1["recovery"].size)) beta2 = beta**2 - fscore = (1+beta2)*r1_grid*r2_grid - if pref=='cat1': - fscore /= (beta2*r1_grid+r2_grid) - elif pref=='cat2': - fscore /= (r1_grid+beta2*r2_grid) + fscore = (1 + beta2) * r1_grid * r2_grid + if pref == "cat1": + fscore /= beta2 * r1_grid + r2_grid + elif pref == "cat2": + fscore /= r1_grid + beta2 * r2_grid else: - raise ValueError(f'pref (={pref}) must be cat1 or cat2') - return {'fscore': fscore.reshape(*rec2['recovery'].shape, *rec1['recovery'].shape), - 'cat1':rec1, 'cat2':rec2} - -def plot_fscore(cat1_val1, cat1_val2, cat1_bins1, cat1_bins2, cat1_is_matched, - cat2_val1, cat2_val2, cat2_bins1, cat2_bins2, cat2_is_matched, - beta=1, pref='cat1', par_order=(0, 1, 2, 3), shape='steps', plt_kwargs={}, - lines_kwargs_list=None, fig_kwargs={}, legend_kwargs={}, - cat1_val1_label=None, cat1_val2_label=None, - cat2_val1_label=None, cat2_val2_label=None, - cat1_datalabel1_format=lambda v: v, cat1_datalabel2_format=lambda v: v, - cat2_datalabel1_format=lambda v: v, cat2_datalabel2_format=lambda v: v, - ): + raise ValueError(f"pref (={pref}) must be cat1 or cat2") + return { + "fscore": fscore.reshape(*rec2["recovery"].shape, *rec1["recovery"].shape), + "cat1": rec1, + "cat2": rec2, + } + + +def plot_fscore( + cat1_val1, + cat1_val2, + cat1_bins1, + cat1_bins2, + cat1_is_matched, + cat2_val1, + cat2_val2, + cat2_bins1, + cat2_bins2, + cat2_is_matched, + beta=1, + pref="cat1", + par_order=(0, 1, 2, 3), + shape="steps", + plt_kwargs={}, + lines_kwargs_list=None, + fig_kwargs={}, + legend_kwargs={}, + cat1_val1_label=None, + cat1_val2_label=None, + cat2_val1_label=None, + cat2_val2_label=None, + cat1_datalabel1_format=lambda v: v, + cat1_datalabel2_format=lambda v: v, + cat2_datalabel1_format=lambda v: v, + cat2_datalabel2_format=lambda v: v, +): """ Plot recovery rate as lines in panels, with each line binned by bins1 and each panel is based on the data inside a bins2 bin. @@ -525,49 +558,89 @@ def plot_fscore(cat1_val1, cat1_val2, cat1_bins1, cat1_bins2, cat1_is_matched, * `cat1`: Dictionary with recovery rate of catalog 1, see get_recovery_rate. * `cat2`: Dictionary with recovery rate of catalog 2, see get_recovery_rate. """ - info = {'data': get_fscore( - cat1_val1, cat1_val2, cat1_bins1, cat1_bins2, cat1_is_matched, - cat2_val1, cat2_val2, cat2_bins1, cat2_bins2, cat2_is_matched, - beta=beta, pref=pref)} + info = { + "data": get_fscore( + cat1_val1, + cat1_val2, + cat1_bins1, + cat1_bins2, + cat1_is_matched, + cat2_val1, + cat2_val2, + cat2_bins1, + cat2_bins2, + cat2_is_matched, + beta=beta, + pref=pref, + ) + } # Order of parameters - edges = index_list([info['data']['cat1']['edges1'], info['data']['cat1']['edges2'], - info['data']['cat2']['edges1'], info['data']['cat2']['edges2']], - par_order) - labels = index_list([cat1_val1_label, cat1_val2_label, - cat2_val1_label, cat2_val2_label], par_order) + edges = index_list( + [ + info["data"]["cat1"]["edges1"], + info["data"]["cat1"]["edges2"], + info["data"]["cat2"]["edges1"], + info["data"]["cat2"]["edges2"], + ], + par_order, + ) + labels = index_list( + [cat1_val1_label, cat1_val2_label, cat2_val1_label, cat2_val2_label], par_order + ) label_formats = index_list( - [cat1_datalabel1_format, cat1_datalabel2_format, - cat2_datalabel1_format, cat2_datalabel2_format], par_order) + [ + cat1_datalabel1_format, + cat1_datalabel2_format, + cat2_datalabel1_format, + cat2_datalabel2_format, + ], + par_order, + ) tr_order = index_list([2, 3, 0, 1], index_list(par_order, [2, 3, 0, 1])) - ni = edges[2].size-1 - nj = edges[3].size-1 + ni = edges[2].size - 1 + nj = edges[3].size - 1 fig_kwargs_ = dict(sharex=True, sharey=True, figsize=(8, 6)) fig_kwargs_.update(fig_kwargs) - info.update({key: value for key, value in zip( - ('fig', 'axes'), plt.subplots(ni, nj, **fig_kwargs_))}) + info.update( + {key: value for key, value in zip(("fig", "axes"), plt.subplots(ni, nj, **fig_kwargs_))} + ) add_legend = True - for axl, fscl in zip(info['axes'], info['data']['fscore'].transpose(*tr_order)): + for axl, fscl in zip(info["axes"], info["data"]["fscore"].transpose(*tr_order)): for ax, fsc in zip(axl, fscl): ph.add_grid(ax) - ph.plot_histograms(fsc.T, edges[0], edges[1], - ax=ax, shape=shape, plt_kwargs=plt_kwargs, - lines_kwargs_list=lines_kwargs_list, - add_legend=add_legend, legend_format=label_formats[1], - legend_kwargs=legend_kwargs) + ph.plot_histograms( + fsc.T, + edges[0], + edges[1], + ax=ax, + shape=shape, + plt_kwargs=plt_kwargs, + lines_kwargs_list=lines_kwargs_list, + add_legend=add_legend, + legend_format=label_formats[1], + legend_kwargs=legend_kwargs, + ) add_legend = False - for ax in info['axes'][:,0]: - ax.set_ylabel(f'$F_{{{beta}}}$ score') - for ax in info['axes'][-1,:]: - ax.set_xlabel(f'${labels[0]}$') + for ax in info["axes"][:, 0]: + ax.set_ylabel(f"$F_{{{beta}}}$ score") + for ax in info["axes"][-1, :]: + ax.set_xlabel(f"${labels[0]}$") ph.add_panel_bin_label( - info['axes'], edges[3][:-1], edges[3][1:], - prefix='' if labels[3] is None else f'{labels[3]}: ', - format_func=label_formats[3]) + info["axes"], + edges[3][:-1], + edges[3][1:], + prefix="" if labels[3] is None else f"{labels[3]}: ", + format_func=label_formats[3], + ) ph.add_panel_bin_label( - info['axes'][:,-1], edges[2][:-1], edges[2][1:], - prefix='' if labels[2] is None else f'{labels[2]}: ', - format_func=label_formats[2], position='right') + info["axes"][:, -1], + edges[2][:-1], + edges[2][1:], + prefix="" if labels[2] is None else f"{labels[2]}: ", + format_func=label_formats[2], + position="right", + ) return info diff --git a/clevar/match_metrics/recovery/catalog_funcs.py b/clevar/match_metrics/recovery/catalog_funcs.py index 5cc84d50..b08313b8 100644 --- a/clevar/match_metrics/recovery/catalog_funcs.py +++ b/clevar/match_metrics/recovery/catalog_funcs.py @@ -419,10 +419,25 @@ def skyplot( ) -def _plot_fscore_base(pltfunc, cat1, cat1_col1, cat1_col2, cat1_bins1, cat1_bins2, - cat2, cat2_col1, cat2_col2, cat2_bins1, cat2_bins2, matching_type, - cat1_mask=None, cat1_mask_unmatched=None, cat2_mask=None, - cat2_mask_unmatched=None, **kwargs): +def _plot_fscore_base( + pltfunc, + cat1, + cat1_col1, + cat1_col2, + cat1_bins1, + cat1_bins2, + cat2, + cat2_col1, + cat2_col2, + cat2_bins1, + cat2_bins2, + matching_type, + cat1_mask=None, + cat1_mask_unmatched=None, + cat2_mask=None, + cat2_mask_unmatched=None, + **kwargs, +): """ Adapts local function to use a ArrayFuncs function. @@ -457,21 +472,51 @@ def _plot_fscore_base(pltfunc, cat1, cat1_col1, cat1_col2, cat1_bins1, cat1_bins c1_mask, c1_is_matched = _rec_masks(cat1, matching_type, cat1_mask, cat1_mask_unmatched) c2_mask, c2_is_matched = _rec_masks(cat2, matching_type, cat2_mask, cat2_mask_unmatched) # make sure bins stay consistent regardless of mask - c1_edges1, c1_edges2 = np.histogram2d(cat1[cat1_col1], cat1[cat1_col2], - bins=(cat1_bins1, cat1_bins2))[1:] - c2_edges1, c2_edges2 = np.histogram2d(cat2[cat2_col1], cat2[cat2_col2], - bins=(cat2_bins1, cat2_bins2))[1:] + c1_edges1, c1_edges2 = np.histogram2d( + cat1[cat1_col1], cat1[cat1_col2], bins=(cat1_bins1, cat1_bins2) + )[1:] + c2_edges1, c2_edges2 = np.histogram2d( + cat2[cat2_col1], cat2[cat2_col2], bins=(cat2_bins1, cat2_bins2) + )[1:] return pltfunc( - cat1[cat1_col1][c1_mask], cat1[cat1_col2][c1_mask], c1_edges1, c1_edges2, c1_is_matched[c1_mask], - cat2[cat2_col1][c2_mask], cat2[cat2_col2][c2_mask], c2_edges1, c2_edges2, c2_is_matched[c2_mask], - **kwargs) + cat1[cat1_col1][c1_mask], + cat1[cat1_col2][c1_mask], + c1_edges1, + c1_edges2, + c1_is_matched[c1_mask], + cat2[cat2_col1][c2_mask], + cat2[cat2_col2][c2_mask], + c2_edges1, + c2_edges2, + c2_is_matched[c2_mask], + **kwargs, + ) -def plot_fscore(cat1, cat1_col1, cat1_col2, cat1_bins1, cat1_bins2, - cat2, cat2_col1, cat2_col2, cat2_bins1, cat2_bins2, - matching_type, beta=1, pref='cat1', par_order=(0, 1, 2, 3), - cat1_mask=None, cat1_mask_unmatched=None, cat2_mask=None, cat2_mask_unmatched=None, - xlabel=None, ylabel=None, xscale='linear', **kwargs): +def plot_fscore( + cat1, + cat1_col1, + cat1_col2, + cat1_bins1, + cat1_bins2, + cat2, + cat2_col1, + cat2_col2, + cat2_bins1, + cat2_bins2, + matching_type, + beta=1, + pref="cat1", + par_order=(0, 1, 2, 3), + cat1_mask=None, + cat1_mask_unmatched=None, + cat2_mask=None, + cat2_mask_unmatched=None, + xlabel=None, + ylabel=None, + xscale="linear", + **kwargs, +): """ Plot recovery rate as lines, with each line binned by bins1 inside a bin of bins2. @@ -549,28 +594,41 @@ def plot_fscore(cat1, cat1_col1, cat1_col2, cat1_bins1, cat1_bins2, * `cat2`: Dictionary with recovery rate of catalog 2, see get_recovery_rate. """ kwargs_ = { - 'cat1_val1_label':cat1.labels[cat1_col1], - 'cat1_val2_label':cat1.labels[cat1_col2], - 'cat2_val1_label':cat2.labels[cat2_col1], - 'cat2_val2_label':cat2.labels[cat2_col2], - 'cat1_mask':cat1_mask, - 'cat1_mask_unmatched':cat1_mask_unmatched, - 'cat2_mask':cat2_mask, - 'cat2_mask_unmatched':cat2_mask_unmatched, + "cat1_val1_label": cat1.labels[cat1_col1], + "cat1_val2_label": cat1.labels[cat1_col2], + "cat2_val1_label": cat2.labels[cat2_col1], + "cat2_val2_label": cat2.labels[cat2_col2], + "cat1_mask": cat1_mask, + "cat1_mask_unmatched": cat1_mask_unmatched, + "cat2_mask": cat2_mask, + "cat2_mask_unmatched": cat2_mask_unmatched, } kwargs_.update(kwargs) - info = _plot_fscore_base(array_funcs.plot_fscore, - cat1, cat1_col1, cat1_col2, cat1_bins1, cat1_bins2, - cat2, cat2_col1, cat2_col2, cat2_bins1, cat2_bins2, - matching_type, beta=beta, pref=pref, par_order=par_order, - **kwargs_) + info = _plot_fscore_base( + array_funcs.plot_fscore, + cat1, + cat1_col1, + cat1_col2, + cat1_bins1, + cat1_bins2, + cat2, + cat2_col1, + cat2_col2, + cat2_bins1, + cat2_bins2, + matching_type, + beta=beta, + pref=pref, + par_order=par_order, + **kwargs_, + ) if xlabel: - for ax in info['axes'][-1]: + for ax in info["axes"][-1]: ax.set_xlabel(xlabel) if ylabel: - for ax in info['axes'][:, 0]: + for ax in info["axes"][:, 0]: ax.set_ylabel(ylabel) - for ax in info['axes'].flatten(): + for ax in info["axes"].flatten(): ax.set_xscale(xscale) - ax.set_ylim(-.01, 1.05) + ax.set_ylim(-0.01, 1.05) return info diff --git a/clevar/match_metrics/recovery/funcs.py b/clevar/match_metrics/recovery/funcs.py index b2004585..3ef1d1b7 100644 --- a/clevar/match_metrics/recovery/funcs.py +++ b/clevar/match_metrics/recovery/funcs.py @@ -556,11 +556,25 @@ def skyplot( ) -def plot_fscore(cat1, cat1_redshift_bins, cat1_mass_bins, cat2, cat2_redshift_bins, cat2_mass_bins, - matching_type, beta=1, pref='cat1', par_order=(0, 1, 2, 3), cat1_mask=None, - cat1_mask_unmatched=None, cat2_mask=None, cat2_mask_unmatched=None, log_mass=True, - fscore_label=None, **kwargs): - +def plot_fscore( + cat1, + cat1_redshift_bins, + cat1_mass_bins, + cat2, + cat2_redshift_bins, + cat2_mass_bins, + matching_type, + beta=1, + pref="cat1", + par_order=(0, 1, 2, 3), + cat1_mask=None, + cat1_mask_unmatched=None, + cat2_mask=None, + cat2_mask_unmatched=None, + log_mass=True, + fscore_label=None, + **kwargs, +): """ Plot recovery rate as lines in panels, with each line binned by redshift and each panel is based on the data inside a mass bin. @@ -648,29 +662,52 @@ def plot_fscore(cat1, cat1_redshift_bins, cat1_mass_bins, cat2, cat2_redshift_bi kwargs_ = {} kwargs_.update(kwargs) # labels - kwargs_['cat1_val1_label'] = kwargs_.pop('cat1_redshift_label', cat1.labels['z']) - kwargs_['cat1_val2_label'] = kwargs_.pop('cat1_mass_label', cat1.labels['mass']) - kwargs_['cat2_val1_label'] = kwargs_.pop('cat2_redshift_label', cat2.labels['z']) - kwargs_['cat2_val2_label'] = kwargs_.pop('cat2_mass_label', cat2.labels['mass']) + kwargs_["cat1_val1_label"] = kwargs_.pop("cat1_redshift_label", cat1.labels["z"]) + kwargs_["cat1_val2_label"] = kwargs_.pop("cat1_mass_label", cat1.labels["mass"]) + kwargs_["cat2_val1_label"] = kwargs_.pop("cat2_redshift_label", cat2.labels["z"]) + kwargs_["cat2_val2_label"] = kwargs_.pop("cat2_mass_label", cat2.labels["mass"]) # label formats - for i in '12': + for i in "12": ph._set_label_format( - kwargs_, f'cat{i}_redshiftlabel_format', f'cat{i}_redshiftlabel_fmt', - log=False, default_fmt=".2f") + kwargs_, + f"cat{i}_redshiftlabel_format", + f"cat{i}_redshiftlabel_fmt", + log=False, + default_fmt=".2f", + ) ph._set_label_format( - kwargs_, f'cat{i}_masslabel_format', f'cat{i}_masslabel_fmt', - log=log_mass, default_fmt=".1f") - kwargs_['cat1_datalabel1_format'] = kwargs_.pop('cat1_redshiftlabel_format') - kwargs_['cat1_datalabel2_format'] = kwargs_.pop('cat1_masslabel_format') - kwargs_['cat2_datalabel1_format'] = kwargs_.pop('cat2_redshiftlabel_format') - kwargs_['cat2_datalabel2_format'] = kwargs_.pop('cat2_masslabel_format') + kwargs_, + f"cat{i}_masslabel_format", + f"cat{i}_masslabel_fmt", + log=log_mass, + default_fmt=".1f", + ) + kwargs_["cat1_datalabel1_format"] = kwargs_.pop("cat1_redshiftlabel_format") + kwargs_["cat1_datalabel2_format"] = kwargs_.pop("cat1_masslabel_format") + kwargs_["cat2_datalabel1_format"] = kwargs_.pop("cat2_redshiftlabel_format") + kwargs_["cat2_datalabel2_format"] = kwargs_.pop("cat2_masslabel_format") info = catalog_funcs.plot_fscore( - cat1, 'z', 'mass', cat1_redshift_bins, cat1_mass_bins, - cat2, 'z', 'mass', cat2_redshift_bins, cat2_mass_bins, - matching_type, beta=beta, pref=pref, par_order=par_order, cat1_mask=cat1_mask, - cat1_mask_unmatched=cat1_mask_unmatched, cat2_mask=cat2_mask, + cat1, + "z", + "mass", + cat1_redshift_bins, + cat1_mass_bins, + cat2, + "z", + "mass", + cat2_redshift_bins, + cat2_mass_bins, + matching_type, + beta=beta, + pref=pref, + par_order=par_order, + cat1_mask=cat1_mask, + cat1_mask_unmatched=cat1_mask_unmatched, + cat2_mask=cat2_mask, cat2_mask_unmatched=cat2_mask_unmatched, - xscale='log' if par_order[0] in (1, 3) else 'linear', - ylabel=fscore_label, **kwargs_) + xscale="log" if par_order[0] in (1, 3) else "linear", + ylabel=fscore_label, + **kwargs_, + ) return info diff --git a/clevar/utils.py b/clevar/utils.py index 86de6f57..1a2e5732 100644 --- a/clevar/utils.py +++ b/clevar/utils.py @@ -200,6 +200,8 @@ def _convert_keys(self): veclen = np.vectorize(len) + + def index_list(input_list, indexes): """Get list sorted by index list @@ -217,6 +219,7 @@ def index_list(input_list, indexes): """ return [input_list[i] for i in indexes] + def none_val(value, none_value): """ Set default value to be returned if input is None From 4d53e5e860a2e10f29802ebd1752fa403e6d761c Mon Sep 17 00:00:00 2001 From: m-aguena Date: Mon, 23 Sep 2024 03:12:17 -0700 Subject: [PATCH 09/12] pylint fmt --- clevar/match_metrics/recovery/array_funcs.py | 20 ++++-- .../match_metrics/recovery/catalog_funcs.py | 63 +++++++++++-------- clevar/match_metrics/recovery/funcs.py | 1 + 3 files changed, 51 insertions(+), 33 deletions(-) diff --git a/clevar/match_metrics/recovery/array_funcs.py b/clevar/match_metrics/recovery/array_funcs.py index e795add2..f952fb3e 100644 --- a/clevar/match_metrics/recovery/array_funcs.py +++ b/clevar/match_metrics/recovery/array_funcs.py @@ -487,10 +487,10 @@ def plot_fscore( pref="cat1", par_order=(0, 1, 2, 3), shape="steps", - plt_kwargs={}, + plt_kwargs=None, lines_kwargs_list=None, - fig_kwargs={}, - legend_kwargs={}, + fig_kwargs=None, + legend_kwargs=None, cat1_val1_label=None, cat1_val2_label=None, cat2_val1_label=None, @@ -558,6 +558,7 @@ def plot_fscore( * `cat1`: Dictionary with recovery rate of catalog 1, see get_recovery_rate. * `cat2`: Dictionary with recovery rate of catalog 2, see get_recovery_rate. """ + # pylint: disable=too-many-locals info = { "data": get_fscore( cat1_val1, @@ -601,10 +602,17 @@ def plot_fscore( ni = edges[2].size - 1 nj = edges[3].size - 1 - fig_kwargs_ = dict(sharex=True, sharey=True, figsize=(8, 6)) - fig_kwargs_.update(fig_kwargs) info.update( - {key: value for key, value in zip(("fig", "axes"), plt.subplots(ni, nj, **fig_kwargs_))} + dict( + zip( + ("fig", "axes"), + plt.subplots( + ni, + nj, + **updated_dict({"sharex": True, "sharey": True, "figsize": (8, 6)}, fig_kwargs), + ), + ) + ) ) add_legend = True for axl, fscl in zip(info["axes"], info["data"]["fscore"].transpose(*tr_order)): diff --git a/clevar/match_metrics/recovery/catalog_funcs.py b/clevar/match_metrics/recovery/catalog_funcs.py index b08313b8..e2784876 100644 --- a/clevar/match_metrics/recovery/catalog_funcs.py +++ b/clevar/match_metrics/recovery/catalog_funcs.py @@ -3,7 +3,7 @@ Main recovery functions using catalogs, wrapper of array_funcs functions """ import numpy as np -from ...utils import none_val +from ...utils import none_val, updated_dict, subdict from .. import plot_helper as ph from . import array_funcs @@ -469,6 +469,7 @@ def _plot_fscore_base( ------- Same as pltfunc """ + # pylint: disable=too-many-locals c1_mask, c1_is_matched = _rec_masks(cat1, matching_type, cat1_mask, cat1_mask_unmatched) c2_mask, c2_is_matched = _rec_masks(cat2, matching_type, cat2_mask, cat2_mask_unmatched) # make sure bins stay consistent regardless of mask @@ -593,34 +594,42 @@ def plot_fscore( * `cat1`: Dictionary with recovery rate of catalog 1, see get_recovery_rate. * `cat2`: Dictionary with recovery rate of catalog 2, see get_recovery_rate. """ - kwargs_ = { - "cat1_val1_label": cat1.labels[cat1_col1], - "cat1_val2_label": cat1.labels[cat1_col2], - "cat2_val1_label": cat2.labels[cat2_col1], - "cat2_val2_label": cat2.labels[cat2_col2], - "cat1_mask": cat1_mask, - "cat1_mask_unmatched": cat1_mask_unmatched, - "cat2_mask": cat2_mask, - "cat2_mask_unmatched": cat2_mask_unmatched, - } - kwargs_.update(kwargs) + # pylint: disable=too-many-locals + # pylint: disable=unused-argument info = _plot_fscore_base( array_funcs.plot_fscore, - cat1, - cat1_col1, - cat1_col2, - cat1_bins1, - cat1_bins2, - cat2, - cat2_col1, - cat2_col2, - cat2_bins1, - cat2_bins2, - matching_type, - beta=beta, - pref=pref, - par_order=par_order, - **kwargs_, + **subdict( + locals(), + ( + "cat1", + "cat1_col1", + "cat1_col2", + "cat1_bins1", + "cat1_bins2", + "cat2", + "cat2_col1", + "cat2_col2", + "cat2_bins1", + "cat2_bins2", + "matching_type", + "beta", + "pref", + "par_order", + ), + ), + **updated_dict( + { + "cat1_val1_label": cat1.labels[cat1_col1], + "cat1_val2_label": cat1.labels[cat1_col2], + "cat2_val1_label": cat2.labels[cat2_col1], + "cat2_val2_label": cat2.labels[cat2_col2], + "cat1_mask": cat1_mask, + "cat1_mask_unmatched": cat1_mask_unmatched, + "cat2_mask": cat2_mask, + "cat2_mask_unmatched": cat2_mask_unmatched, + }, + kwargs, + ), ) if xlabel: for ax in info["axes"][-1]: diff --git a/clevar/match_metrics/recovery/funcs.py b/clevar/match_metrics/recovery/funcs.py index 3ef1d1b7..d2a5d4bb 100644 --- a/clevar/match_metrics/recovery/funcs.py +++ b/clevar/match_metrics/recovery/funcs.py @@ -667,6 +667,7 @@ def plot_fscore( kwargs_["cat2_val1_label"] = kwargs_.pop("cat2_redshift_label", cat2.labels["z"]) kwargs_["cat2_val2_label"] = kwargs_.pop("cat2_mass_label", cat2.labels["mass"]) # label formats + # pylint: disable=protected-access for i in "12": ph._set_label_format( kwargs_, From 5873e64b3027f6e5c40cda69b4e78bed77bdc451 Mon Sep 17 00:00:00 2001 From: m-aguena Date: Mon, 23 Sep 2024 03:14:12 -0700 Subject: [PATCH 10/12] put pylint after unit tests --- .github/workflows/build_check.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build_check.yml b/.github/workflows/build_check.yml index 256e3b42..a7ca2821 100644 --- a/.github/workflows/build_check.yml +++ b/.github/workflows/build_check.yml @@ -43,16 +43,16 @@ jobs: git clone https://github.com/LSSTDESC/healsparse cd healsparse pip install . - - name: Analysing the code with pylint - run: | - pip install pylint - pylint clevar --ignored-classes=astropy.units - name: Run the unit tests run: | pip install pytest pytest-cov pytest tests/ --cov=clevar/ env: DISPLAY: test + - name: Analysing the code with pylint + run: | + pip install pylint + pylint clevar --ignored-classes=astropy.units - name: Install Sphinx prereq run: | conda install -c conda-forge sphinx sphinx_rtd_theme nbconvert>=7 pandoc ipython ipython_genutils From af628f3681c96fd673296590b6fb4164afbaff62 Mon Sep 17 00:00:00 2001 From: m-aguena Date: Wed, 25 Sep 2024 08:41:07 -0700 Subject: [PATCH 11/12] update tests --- tests/test_metrics_recovery.py | 41 ++++++++++++++++++++++++++++++++++ tests/test_utils.py | 8 ++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/tests/test_metrics_recovery.py b/tests/test_metrics_recovery.py index 095411b1..4acdee7b 100644 --- a/tests/test_metrics_recovery.py +++ b/tests/test_metrics_recovery.py @@ -129,3 +129,44 @@ def test_skyplot(): matching_type, recovery_label=None, ) + + +def test_fscore(): + matching_type = "cat1" + redshift_bins = [0, 0.5, 1] + mass_bins = [1e13, 1e14, 1e15, 1e16] + args = ( + _test_data.cat1, + redshift_bins, + mass_bins, + _test_data.cat2, + redshift_bins, + mass_bins, + matching_type, + ) + rc.plot_fscore( + *args, + beta=1, + pref="cat1", + par_order=(0, 1, 2, 3), + cat1_mask=None, + cat1_mask_unmatched=None, + cat2_mask=None, + cat2_mask_unmatched=None, + log_mass=True, + fscore_label="fscore", + xlabel="x", + ) + rc.plot_fscore( + *args, + beta=1, + pref="cat2", + par_order=(0, 1, 2, 3), + cat1_mask=None, + cat1_mask_unmatched=None, + cat2_mask=None, + cat2_mask_unmatched=None, + log_mass=True, + fscore_label=None, + ) + assert_raises(ValueError, rc.plot_fscore, *args, pref="unknown") diff --git a/tests/test_utils.py b/tests/test_utils.py index 627c508c..44d33e4f 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -21,4 +21,10 @@ def test_timer_class(): LPtime = utils.Timer("test_name") LPtime.title(" (some subtitle)") LPtime.time() - LPtime.end() # close object + LPtime.end() + + +def test_other(): + assert utils.none_val("y", "x") == "y" + assert utils.none_val(None, "x") == "x" + assert utils.index_list(["A", "B"], [1, 0]) == ["B", "A"] From 7796b5e38a7dbd18ba65c87a8b2d30a0c29b29ee Mon Sep 17 00:00:00 2001 From: m-aguena Date: Wed, 25 Sep 2024 09:28:56 -0700 Subject: [PATCH 12/12] update tests --- tests/test_metrics_plot_helper.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tests/test_metrics_plot_helper.py diff --git a/tests/test_metrics_plot_helper.py b/tests/test_metrics_plot_helper.py new file mode 100644 index 00000000..0dced890 --- /dev/null +++ b/tests/test_metrics_plot_helper.py @@ -0,0 +1,15 @@ +"""Tests for clevar/match_metrics/plot_helper""" +import pylab as plt +from numpy.testing import assert_raises +from clevar.match_metrics import plot_helper as ph + + +def test_add_panel_bin_label(): + fig, axes = plt.subplots(2, 2) + edges = range(5) + edges_lower, edges_higher = edges[:-1], edges[1:] + for position in ("top", "bottom", "left", "right"): + ph.add_panel_bin_label(axes, edges_lower, edges_higher, position=position) + assert_raises( + ValueError, ph.add_panel_bin_label, axes, edges_lower, edges_higher, position="unknown" + )