diff --git a/bob/pad/base/script/vuln_commands.py b/bob/pad/base/script/vuln_commands.py index 8577a2848083aff65e78af0e30b7a52a123065f8..a61b3ded461a9fa5a25b87be0283da0b9d17b70c 100644 --- a/bob/pad/base/script/vuln_commands.py +++ b/bob/pad/base/script/vuln_commands.py @@ -229,7 +229,7 @@ def epc(ctx, scores, **kwargs): @click.command() @common_options.scores_argument(min_arg=2, force_eval=True, nargs=-1) @common_options.output_plot_file_option(default_out='vuln_epsc.pdf') -@common_options.legends_option() +@common_options.titles_option() @common_options.no_legend_option() @common_options.legend_loc_option() @common_options.const_layout_option() @@ -252,14 +252,13 @@ def epc(ctx, scores, **kwargs): @click.option('-vp', '--var-param', default="omega", show_default=True, help='Name of the varying parameter', type=click.Choice(('omega', 'beta'))) -@click.option('-fp', '--fixed-param', default=0.5, show_default=True, - help='Value of the fixed parameter', - type=click.FLOAT) +@list_float_option(name='fixed-params', short_name='fp', dflt='0.5', + desc='Values of the fixed parameter, separated by commas') @click.option('-s', '--sampling', default=5, show_default=True, help='Sampling of the EPSC 3D surface', type=click.INT) @verbosity_option() @click.pass_context -def epsc(ctx, scores, criteria, var_param, fixed_param, three_d, sampling, +def epsc(ctx, scores, criteria, var_param, three_d, sampling, **kwargs): """Plot EPSC (expected performance spoofing curve): @@ -283,18 +282,19 @@ def epsc(ctx, scores, criteria, var_param, fixed_param, three_d, sampling, $ bob vuln epsc -v -D {licit,spoof}/scores-{dev,eval} """ + fixed_params = ctx.meta.get('fixed_params', [0.5]) if three_d: if (ctx.meta['wer'] and ctx.meta['iapmr']): raise click.BadParameter('Cannot plot both WER and IAPMR in 3D') ctx.meta['sampling'] = sampling process = figure.Epsc3D( ctx, scores, True, load.split, - criteria, var_param, fixed_param + criteria, var_param, fixed_params ) else: process = figure.Epsc( ctx, scores, True, load.split, - criteria, var_param, fixed_param + criteria, var_param, fixed_params ) process.run() diff --git a/bob/pad/base/script/vuln_figure.py b/bob/pad/base/script/vuln_figure.py index d5fb6a8a1db8f5f23cc3df712c2b951455e89cf6..11403363a8ef99da211d0700cc240d55763ae5de 100644 --- a/bob/pad/base/script/vuln_figure.py +++ b/bob/pad/base/script/vuln_figure.py @@ -209,19 +209,19 @@ class Epsc(VulnPlot): ''' Handles the plotting of EPSC ''' def __init__(self, ctx, scores, evaluation, func_load, - criteria, var_param, fixed_param): + criteria, var_param, fixed_params): super(Epsc, self).__init__(ctx, scores, evaluation, func_load) self._iapmr = False if 'iapmr' not in self._ctx.meta else \ self._ctx.meta['iapmr'] self._wer = True if 'wer' not in self._ctx.meta else \ self._ctx.meta['wer'] - self._criteria = 'eer' if criteria is None else criteria - self._var_param = "omega" if var_param is None else var_param - self._fixed_param = 0.5 if fixed_param is None else fixed_param + self._criteria = criteria or 'eer' + self._var_param = var_param or "omega" + self._fixed_params = fixed_params or [0.5] + self._titles = ctx.meta.get('titles', []) self._eval = True # always eval data with EPC self._split = False self._nb_figs = 1 - self._title = ctx.meta.get('title') self._sampling = ctx.meta.get('sampling', 5) if self._min_arg != 4: @@ -238,59 +238,55 @@ class Epsc(VulnPlot): spoof_dev_pos = input_scores[2][1] spoof_eval_neg = input_scores[3][0] spoof_eval_pos = input_scores[3][1] - title = self._legends[idx] if self._legends is not None else None mpl.gcf().clear() points = 10 - - if self._var_param == 'omega': - omega, beta, thrs = error_utils.epsc_thresholds( - licit_dev_neg, - licit_dev_pos, - spoof_dev_neg, - spoof_dev_pos, - points=points, - criteria=self._criteria, - beta=self._fixed_param) - else: - omega, beta, thrs = error_utils.epsc_thresholds( - licit_dev_neg, - licit_dev_pos, - spoof_dev_neg, - spoof_dev_pos, - points=points, - criteria=self._criteria, - omega=self._fixed_param - ) - - errors = error_utils.all_error_rates( - licit_eval_neg, licit_eval_pos, spoof_eval_neg, - spoof_eval_pos, thrs, omega, beta - ) # error rates are returned in a list in the - # following order: frr, far, IAPMR, far_w, wer_w - - ax1 = mpl.subplot( - 111 - ) # EPC like curves for FVAS fused scores for weighted error rates - # between the negatives (impostors and Presentation attacks) - if self._wer: + for pi, fp in enumerate(self._fixed_params): if self._var_param == 'omega': - mpl.plot( - omega, - 100. * errors[4].flatten(), - color='C0', - linestyle='-', - label=r"WER$_{\omega,\beta}$") - mpl.xlabel(self._x_label or r"Weight $\omega$") + omega, beta, thrs = error_utils.epsc_thresholds( + licit_dev_neg, + licit_dev_pos, + spoof_dev_neg, + spoof_dev_pos, + points=points, + criteria=self._criteria, + beta=fp) else: - mpl.plot( - beta, - 100. * errors[4].flatten(), - color='C0', - linestyle='-', - label=r"WER$_{\omega,\beta}$") - mpl.xlabel(self._x_label or r"Weight $\beta$") - mpl.ylabel(self._y_label or r"WER$_{\omega,\beta}$ (%)") + omega, beta, thrs = error_utils.epsc_thresholds( + licit_dev_neg, + licit_dev_pos, + spoof_dev_neg, + spoof_dev_pos, + points=points, + criteria=self._criteria, + omega=fp + ) + + errors = error_utils.all_error_rates( + licit_eval_neg, licit_eval_pos, spoof_eval_neg, + spoof_eval_pos, thrs, omega, beta + ) # error rates are returned in a list in the + # following order: frr, far, IAPMR, far_w, wer_w + + # between the negatives (impostors and Presentation attacks) + if self._wer: + if self._var_param == 'omega': + mpl.plot( + omega, + 100. * errors[4].flatten(), + color=self._colors[pi], + linestyle='-', + label=r"WER$_{\omega,\beta}$") + mpl.xlabel(self._x_label or r"Weight $\omega$") + else: + mpl.plot( + beta, + 100. * errors[4].flatten(), + color=self._colors[pi], + linestyle='-', + label=r"WER$_{\omega,\beta}$") + mpl.xlabel(self._x_label or r"Weight $\beta$") + mpl.ylabel(self._y_label or r"WER$_{\omega,\beta}$ (%)") if self._iapmr: axis = mpl.gca() @@ -302,7 +298,7 @@ class Epsc(VulnPlot): omega, 100. * errors[2].flatten(), color='C3', - linestyle='-', + linestyle='--', label='IAPMR') mpl.xlabel(self._x_label or r"Weight $\omega$") else: @@ -310,7 +306,7 @@ class Epsc(VulnPlot): beta, 100. * errors[2].flatten(), color='C3', - linestyle='-', + linestyle='--', label='IAPMR') mpl.xlabel(self._x_label or r"Weight $\beta$") mpl.ylabel(self._y_label or r"IAPMR (%)") @@ -320,19 +316,19 @@ class Epsc(VulnPlot): axis.yaxis.label.set_color('red') axis.spines['right'].set_color('red') - if self._var_param == 'omega': - if title is not None and title.replace(' ', ''): - mpl.title(title or (r"EPSC with $\beta$ = %.2f" % - self._fixed_param)) - else: - if title is not None and title.replace(' ', ''): - mpl.title(title or (r"EPSC with $\omega$ = %.2f" % - self._fixed_param)) - + str_list = ', '.join([str(i) for i in self._fixed_params]) + title = r"EPSC with %s = %s" % ( + r"$\beta$" if self._var_param == 'omega' else r"$\omega$", str_list + ) + if self._titles is not None and len(self._titles) > idx: + title = self._titles[idx] if self._titles[idx].replace(' ', '') \ + else None + mpl.title(title) mpl.grid() self._plot_legends() - ax1.set_xticklabels(ax1.get_xticks()) - ax1.set_yticklabels(ax1.get_yticks()) + ax = mpl.gca() + ax.set_xticklabels(ax.get_xticks()) + ax.set_yticklabels(ax.get_yticks()) mpl.xticks(rotation=self._x_rotation) self._pdf_page.savefig()