Commit f276f395 authored by Theophile GENTILHOMME's avatar Theophile GENTILHOMME
Browse files

Add legend options, small changes utils function and doc

parent a2640f7d
...@@ -10,6 +10,8 @@ from . import figure ...@@ -10,6 +10,8 @@ from . import figure
@common_options.scores_argument(min_arg=2, force_eval=True, nargs=-1) @common_options.scores_argument(min_arg=2, force_eval=True, nargs=-1)
@common_options.output_plot_file_option(default_out='det.pdf') @common_options.output_plot_file_option(default_out='det.pdf')
@common_options.legends_option() @common_options.legends_option()
@common_options.no_legend_option()
@common_options.legend_loc_option(dflt='upper-right')
@common_options.title_option() @common_options.title_option()
@common_options.const_layout_option() @common_options.const_layout_option()
@common_options.style_option() @common_options.style_option()
...@@ -18,7 +20,7 @@ from . import figure ...@@ -18,7 +20,7 @@ from . import figure
'no-spoof', 'ns', '', False 'no-spoof', 'ns', '', False
) )
@verbosity_option() @verbosity_option()
@common_options.axes_val_option(dflt=[0.01, 95, 0.01, 95]) @common_options.axes_val_option(dflt='0.01,95,0.01,95')
@common_options.x_rotation_option(dflt=45) @common_options.x_rotation_option(dflt=45)
@common_options.x_label_option() @common_options.x_label_option()
@common_options.y_label_option() @common_options.y_label_option()
......
...@@ -10,6 +10,8 @@ from . import figure ...@@ -10,6 +10,8 @@ from . import figure
@common_options.scores_argument(min_arg=2, force_eval=True, nargs=-1) @common_options.scores_argument(min_arg=2, force_eval=True, nargs=-1)
@common_options.output_plot_file_option(default_out='epc.pdf') @common_options.output_plot_file_option(default_out='epc.pdf')
@common_options.legends_option() @common_options.legends_option()
@common_options.no_legend_option()
@common_options.legend_loc_option()
@common_options.title_option() @common_options.title_option()
@common_options.const_layout_option() @common_options.const_layout_option()
@common_options.x_label_option() @common_options.x_label_option()
...@@ -51,6 +53,8 @@ def epc(ctx, scores, **kwargs): ...@@ -51,6 +53,8 @@ def epc(ctx, scores, **kwargs):
@common_options.scores_argument(min_arg=2, force_eval=True, nargs=-1) @common_options.scores_argument(min_arg=2, force_eval=True, nargs=-1)
@common_options.output_plot_file_option(default_out='epsc.pdf') @common_options.output_plot_file_option(default_out='epsc.pdf')
@common_options.legends_option() @common_options.legends_option()
@common_options.no_legend_option()
@common_options.legend_loc_option()
@common_options.const_layout_option() @common_options.const_layout_option()
@common_options.x_label_option() @common_options.x_label_option()
@common_options.y_label_option() @common_options.y_label_option()
......
...@@ -13,12 +13,20 @@ import argparse ...@@ -13,12 +13,20 @@ import argparse
def calc_pass_rate(threshold, attacks): def calc_pass_rate(threshold, attacks):
"""Calculates the rate of successful spoofing attacks """Calculates the rate of successful spoofing attacks
Keyword parameters: Parameters
----------
threshold :
the threshold used for classification
scores :
numpy with the scores of the spoofing attacks
Returns
-------
float
rate of successful spoofing attacks
"""
return (attacks >= threshold).mean()
- threshold - the threshold used for classification
- attack: numpy with the scores of the spoofing attacks
"""
return sum(1 for i in attacks if i >= threshold) / float(attacks.size)
def weighted_neg_error_rate_criteria(data, def weighted_neg_error_rate_criteria(data,
weight, weight,
...@@ -298,30 +306,32 @@ def epsc_error_rates(licit_neg, licit_pos, spoof_neg, spoof_pos, thresholds, ...@@ -298,30 +306,32 @@ def epsc_error_rates(licit_neg, licit_pos, spoof_neg, spoof_pos, thresholds,
(omega and beta) and thresholds (the thresholds need to be computed first (omega and beta) and thresholds (the thresholds need to be computed first
using the method: epsc_thresholds() before passing to this method) using the method: epsc_thresholds() before passing to this method)
Keyword arguments: Parameters
----------
- licit_neg - numpy.array of scores for the negatives (licit scenario) licit_neg : array_like
- licit_pos - numpy.array of scores for the positives (licit scenario) array of scores for the negatives (licit scenario)
- spoof_neg - numpy.array of scores for the negatives (spoof scenario) licit_pos : array_like
- spoof_pos - numpy.array of scores for the positives (spoof scenario) array of scores for the positives (licit scenario)
- thresholds - numpy.ndarray with threshold values spoof_neg : array_like
- omega - numpy.array of the omega parameter balancing between impostors array of scores for the negatives (spoof scenario)
and spoofing attacks spoof_pos : array_like
- beta - numpy.array of the beta parameter balancing between real accesses array of scores for the positives (spoof scenario)
and all negatives (impostors and spoofing attacks) thresholds : array_like
""" ndarray with threshold values
omega : array_like
if not isinstance(omega, list) and not isinstance( array of the omega parameter balancing between impostors
omega, tuple) and not isinstance(omega, numpy.ndarray): and spoofing attacks
omega = numpy.array([omega]) beta : array_like
else: array of the beta parameter balancing between real accesses
omega = numpy.array(omega) and all negatives (impostors and spoofing attacks)
if not isinstance(beta, list) and not isinstance( Returns
beta, tuple) and not isinstance(beta, numpy.ndarray): -------
beta = numpy.array([beta]) far_w_errors: array_like
else: FAR_w
beta = numpy.array(beta) wer_wb_errors: array_like
WER_wb
"""
far_w_errors = numpy.ndarray((beta.size, omega.size), 'float64') far_w_errors = numpy.ndarray((beta.size, omega.size), 'float64')
wer_wb_errors = numpy.ndarray((beta.size, omega.size), 'float64') wer_wb_errors = numpy.ndarray((beta.size, omega.size), 'float64')
...@@ -340,34 +350,36 @@ def epsc_error_rates(licit_neg, licit_pos, spoof_neg, spoof_pos, thresholds, ...@@ -340,34 +350,36 @@ def epsc_error_rates(licit_neg, licit_pos, spoof_neg, spoof_pos, thresholds,
def all_error_rates(licit_neg, licit_pos, spoof_neg, spoof_pos, thresholds, def all_error_rates(licit_neg, licit_pos, spoof_neg, spoof_pos, thresholds,
omega, beta): omega, beta):
"""Calculates several error rates: FAR_w and HTER_w for the given weights """Calculates several error rates: FAR_w and WER_wb for the given weights
(omega and beta) and thresholds (the thresholds need to be computed first (omega and beta) and thresholds (the thresholds need to be computed first
using the method: epsc_thresholds() before passing to this method) using the method: epsc_thresholds() before passing to this method)
Keyword arguments: Parameters
----------
- licit_neg - numpy.array of scores for the negatives (licit scenario) licit_neg : array_like
- licit_pos - numpy.array of scores for the positives (licit scenario) array of scores for the negatives (licit scenario)
- spoof_neg - numpy.array of scores for the negatives (spoof scenario) licit_pos : array_like
- spoof_pos - numpy.array of scores for the positives (spoof scenario) array of scores for the positives (licit scenario)
- thresholds - numpy.array with threshold values spoof_neg : array_like
- omega - numpy.array of the omega parameter balancing between impostors array of scores for the negatives (spoof scenario)
and spoofing attacks spoof_pos : array_like
- beta - numpy.array of the beta parameter balancing between real accesses array of scores for the positives (spoof scenario)
and all negatives (impostors and spoofing attacks) thresholds : array_like
""" ndarray with threshold values
omega : array_like
if not isinstance(omega, list) and not isinstance( array of the omega parameter balancing between impostors
omega, tuple) and not isinstance(omega, numpy.ndarray): and spoofing attacks
omega = numpy.array([omega]) beta : array_like
else: array of the beta parameter balancing between real accesses
omega = numpy.array(omega) and all negatives (impostors and spoofing attacks)
if not isinstance(beta, list) and not isinstance( Returns
beta, tuple) and not isinstance(beta, numpy.ndarray): -------
beta = numpy.array([beta]) far_w_errors: array_like
else: FAR_w
beta = numpy.array(beta) wer_wb_errors: array_like
WER_wb
"""
frr_errors = numpy.ndarray((beta.size, omega.size), 'float64') frr_errors = numpy.ndarray((beta.size, omega.size), 'float64')
far_errors = numpy.ndarray((beta.size, omega.size), 'float64') far_errors = numpy.ndarray((beta.size, omega.size), 'float64')
......
...@@ -17,6 +17,7 @@ from . import error_utils ...@@ -17,6 +17,7 @@ from . import error_utils
ALL_CRITERIA = ('bpcer20', 'eer', 'min-hter') ALL_CRITERIA = ('bpcer20', 'eer', 'min-hter')
def calc_threshold(method, neg, pos): def calc_threshold(method, neg, pos):
"""Calculates the threshold based on the given method. """Calculates the threshold based on the given method.
The scores should be sorted! The scores should be sorted!
...@@ -52,6 +53,7 @@ def calc_threshold(method, neg, pos): ...@@ -52,6 +53,7 @@ def calc_threshold(method, neg, pos):
return threshold return threshold
class Metrics(measure_figure.Metrics): class Metrics(measure_figure.Metrics):
def __init__(self, ctx, scores, evaluation, func_load): def __init__(self, ctx, scores, evaluation, func_load):
super(Metrics, self).__init__(ctx, scores, evaluation, func_load) super(Metrics, self).__init__(ctx, scores, evaluation, func_load)
...@@ -90,6 +92,7 @@ class Metrics(measure_figure.Metrics): ...@@ -90,6 +92,7 @@ class Metrics(measure_figure.Metrics):
file=self.log_file file=self.log_file
) )
class HistPad(measure_figure.Hist): class HistPad(measure_figure.Hist):
''' Histograms for PAD ''' ''' Histograms for PAD '''
...@@ -103,8 +106,6 @@ class HistPad(measure_figure.Hist): ...@@ -103,8 +106,6 @@ class HistPad(measure_figure.Hist):
hatch='\\\\' hatch='\\\\'
) )
def _calc_pass_rate(threshold, scores):
return (scores >= threshold).mean()
def _iapmr_dot(threshold, iapmr, real_data, **kwargs): def _iapmr_dot(threshold, iapmr, real_data, **kwargs):
# plot a dot on threshold versus IAPMR line and show IAPMR as a number # plot a dot on threshold versus IAPMR line and show IAPMR as a number
...@@ -127,20 +128,23 @@ def _iapmr_dot(threshold, iapmr, real_data, **kwargs): ...@@ -127,20 +128,23 @@ def _iapmr_dot(threshold, iapmr, real_data, **kwargs):
mpl.text(threshold + (threshold - axlim[0]) / 12, 100. * iapmr, mpl.text(threshold + (threshold - axlim[0]) / 12, 100. * iapmr,
'%.1f%%' % (100. * iapmr,), color='C3') '%.1f%%' % (100. * iapmr,), color='C3')
def _iapmr_line_plot(scores, n_points=100, **kwargs): def _iapmr_line_plot(scores, n_points=100, **kwargs):
axlim = mpl.axis() axlim = mpl.axis()
step = (axlim[1] - axlim[0]) / float(n_points) step = (axlim[1] - axlim[0]) / float(n_points)
thres = [(k * step) + axlim[0] for k in range(2, n_points - 1)] thres = [(k * step) + axlim[0] for k in range(2, n_points - 1)]
mix_prob_y = [] mix_prob_y = []
for k in thres: for k in thres:
mix_prob_y.append(100. * _calc_pass_rate(k, scores)) mix_prob_y.append(100. * error_utils.calc_pass_rate(k, scores))
mpl.plot(thres, mix_prob_y, label='IAPMR', color='C3', **kwargs) mpl.plot(thres, mix_prob_y, label='IAPMR', color='C3', **kwargs)
def _iapmr_plot(scores, threshold, iapmr, real_data, **kwargs): def _iapmr_plot(scores, threshold, iapmr, real_data, **kwargs):
_iapmr_dot(threshold, iapmr, real_data, **kwargs) _iapmr_dot(threshold, iapmr, real_data, **kwargs)
_iapmr_line_plot(scores, n_points=100, **kwargs) _iapmr_line_plot(scores, n_points=100, **kwargs)
class HistVuln(measure_figure.Hist): class HistVuln(measure_figure.Hist):
''' Histograms for vulnerability ''' ''' Histograms for vulnerability '''
...@@ -169,15 +173,7 @@ class HistVuln(measure_figure.Hist): ...@@ -169,15 +173,7 @@ class HistVuln(measure_figure.Hist):
ax2.grid(False) ax2.grid(False)
real_data = True if 'real_data' not in self._ctx.meta else \ real_data = True if 'real_data' not in self._ctx.meta else \
self._ctx.meta['real_data'] self._ctx.meta['real_data']
far, frr = farfrr(neg[0], pos[0], threshold)
_iapmr_plot(neg[1], threshold, iapmr, real_data=real_data) _iapmr_plot(neg[1], threshold, iapmr, real_data=real_data)
click.echo(
'%s (t=%.2g) = %.2f%%; IAPMR = %.2f%%' % (
self._criterion.upper(),
threshold,
50*(far+frr), 100*iapmr
)
)
n = idx % self._step_print n = idx % self._step_print
col = n % self._ncols col = n % self._ncols
rest_print = self.n_systems - int(idx / self._step_print) * self._step_print rest_print = self.n_systems - int(idx / self._step_print) * self._step_print
...@@ -187,6 +183,7 @@ class HistVuln(measure_figure.Hist): ...@@ -187,6 +183,7 @@ class HistVuln(measure_figure.Hist):
ax2.yaxis.label.set_color('red') ax2.yaxis.label.set_color('red')
ax2.spines['right'].set_color('red') ax2.spines['right'].set_color('red')
class PadPlot(measure_figure.PlotBase): class PadPlot(measure_figure.PlotBase):
'''Base class for PAD plots''' '''Base class for PAD plots'''
def __init__(self, ctx, scores, evaluation, func_load): def __init__(self, ctx, scores, evaluation, func_load):
...@@ -208,7 +205,10 @@ class PadPlot(measure_figure.PlotBase): ...@@ -208,7 +205,10 @@ class PadPlot(measure_figure.PlotBase):
li, la = ax.get_legend_handles_labels() li, la = ax.get_legend_handles_labels()
lines += li lines += li
labels += la labels += la
mpl.gca().legend(lines, labels, loc=0, fancybox=True, framealpha=0.5) if self._disp_legend:
mpl.gca().legend(lines, labels, loc=self._legend_loc,
fancybox=True, framealpha=0.5)
class Epc(PadPlot): class Epc(PadPlot):
''' Handles the plotting of EPC ''' ''' Handles the plotting of EPC '''
...@@ -277,12 +277,14 @@ class Epc(PadPlot): ...@@ -277,12 +277,14 @@ class Epc(PadPlot):
prob_ax.yaxis.set_ticklabels(["%.0f" % val for val in ylabels]) prob_ax.yaxis.set_ticklabels(["%.0f" % val for val in ylabels])
prob_ax.set_axisbelow(True) prob_ax.set_axisbelow(True)
title = self._legends[idx] if self._legends is not None else self._title title = self._legends[idx] if self._legends is not None else self._title
mpl.title(title) if title.replace(' ', ''):
mpl.title(title)
#legends for all axes #legends for all axes
self._plot_legends() self._plot_legends()
mpl.xticks(rotation=self._x_rotation) mpl.xticks(rotation=self._x_rotation)
self._pdf_page.savefig(mpl.gcf()) self._pdf_page.savefig(mpl.gcf())
class Epsc(PadPlot): class Epsc(PadPlot):
''' Handles the plotting of EPSC ''' ''' Handles the plotting of EPSC '''
def __init__(self, ctx, scores, evaluation, func_load, def __init__(self, ctx, scores, evaluation, func_load,
...@@ -397,11 +399,13 @@ class Epsc(PadPlot): ...@@ -397,11 +399,13 @@ class Epsc(PadPlot):
axis.spines['right'].set_color('red') axis.spines['right'].set_color('red')
if self._var_param == 'omega': if self._var_param == 'omega':
mpl.title(title or (r"EPSC with $\beta$ = %.2f" %\ if title.replace(' ', ''):
self._fixed_param)) mpl.title(title or (r"EPSC with $\beta$ = %.2f" %\
self._fixed_param))
else: else:
mpl.title(title or (r"EPSC with $\omega$ = %.2f" %\ if title.replace(' ', ''):
self._fixed_param)) mpl.title(title or (r"EPSC with $\omega$ = %.2f" %\
self._fixed_param))
mpl.grid() mpl.grid()
self._plot_legends() self._plot_legends()
...@@ -410,6 +414,7 @@ class Epsc(PadPlot): ...@@ -410,6 +414,7 @@ class Epsc(PadPlot):
mpl.xticks(rotation=self._x_rotation) mpl.xticks(rotation=self._x_rotation)
self._pdf_page.savefig() self._pdf_page.savefig()
class Epsc3D(Epsc): class Epsc3D(Epsc):
''' 3D EPSC plots for PAD''' ''' 3D EPSC plots for PAD'''
def compute(self, idx, input_scores, input_names): def compute(self, idx, input_scores, input_names):
...@@ -469,7 +474,8 @@ class Epsc3D(Epsc): ...@@ -469,7 +474,8 @@ class Epsc3D(Epsc):
r"WER$_{\omega,\beta}$ (%)" if self._wer else "IAPMR (%)" r"WER$_{\omega,\beta}$ (%)" if self._wer else "IAPMR (%)"
) )
mpl.title(title or "3D EPSC") if title.replace(' ', ''):
mpl.title(title or "3D EPSC")
ax1.set_xticklabels(ax1.get_xticks()) ax1.set_xticklabels(ax1.get_xticks())
ax1.set_yticklabels(ax1.get_yticks()) ax1.set_yticklabels(ax1.get_yticks())
...@@ -477,6 +483,7 @@ class Epsc3D(Epsc): ...@@ -477,6 +483,7 @@ class Epsc3D(Epsc):
self._pdf_page.savefig() self._pdf_page.savefig()
class Det(PadPlot): class Det(PadPlot):
'''DET for PAD''' '''DET for PAD'''
def __init__(self, ctx, scores, evaluation, func_load, criteria, real_data): def __init__(self, ctx, scores, evaluation, func_load, criteria, real_data):
...@@ -617,11 +624,13 @@ class Det(PadPlot): ...@@ -617,11 +624,13 @@ class Det(PadPlot):
add = " and overlaid SPOOF scenario" add = " and overlaid SPOOF scenario"
title = self._title if self._title is not None else \ title = self._title if self._title is not None else \
('DET: LICIT' + add) ('DET: LICIT' + add)
mpl.title(title) if title.replace(' ', ''):
mpl.title(title)
mpl.xlabel(self._x_label or "False Acceptance Rate (%)") mpl.xlabel(self._x_label or "False Acceptance Rate (%)")
mpl.ylabel(self._y_label or "False Rejection Rate (%)") mpl.ylabel(self._y_label or "False Rejection Rate (%)")
mpl.grid(True, color=self._grid_color) mpl.grid(True, color=self._grid_color)
mpl.legend(loc='best') if self._disp_legend:
mpl.legend(loc=self._legend_loc)
self._set_axis() self._set_axis()
fig = mpl.gcf() fig = mpl.gcf()
mpl.xticks(rotation=self._x_rotation) mpl.xticks(rotation=self._x_rotation)
...@@ -644,6 +653,7 @@ class Det(PadPlot): ...@@ -644,6 +653,7 @@ class Det(PadPlot):
else: else:
det_axis([0.01, 99, 0.01, 99]) det_axis([0.01, 99, 0.01, 99])
class FmrIapmr(PadPlot): class FmrIapmr(PadPlot):
'''FMR vs IAPMR''' '''FMR vs IAPMR'''
def __init__(self, ctx, scores, evaluation, func_load): def __init__(self, ctx, scores, evaluation, func_load):
...@@ -682,11 +692,13 @@ class FmrIapmr(PadPlot): ...@@ -682,11 +692,13 @@ class FmrIapmr(PadPlot):
close pdf is needed ''' close pdf is needed '''
#only for plots #only for plots
title = self._title if self._title is not None else "FMR vs IAPMR" title = self._title if self._title is not None else "FMR vs IAPMR"
mpl.title(title) if title.replace(' ', ''):
mpl.title(title)
mpl.xlabel(self._x_label or "False Match Rate (%)") mpl.xlabel(self._x_label or "False Match Rate (%)")
mpl.ylabel(self._y_label or "IAPMR (%)") mpl.ylabel(self._y_label or "IAPMR (%)")
mpl.grid(True, color=self._grid_color) mpl.grid(True, color=self._grid_color)
mpl.legend(loc='best') if self._disp_legend:
mpl.legend(loc=self._legend_loc)
self._set_axis() self._set_axis()
fig = mpl.gcf() fig = mpl.gcf()
mpl.xticks(rotation=self._x_rotation) mpl.xticks(rotation=self._x_rotation)
......
...@@ -10,6 +10,8 @@ from . import figure ...@@ -10,6 +10,8 @@ from . import figure
@common_options.scores_argument(min_arg=2, force_eval=True, nargs=-1) @common_options.scores_argument(min_arg=2, force_eval=True, nargs=-1)
@common_options.output_plot_file_option(default_out='fmr_iapmr.pdf') @common_options.output_plot_file_option(default_out='fmr_iapmr.pdf')
@common_options.legends_option() @common_options.legends_option()
@common_options.no_legend_option()
@common_options.legend_loc_option()
@common_options.title_option() @common_options.title_option()
@common_options.const_layout_option() @common_options.const_layout_option()
@common_options.style_option() @common_options.style_option()
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment