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
@common_options.scores_argument(min_arg=2, force_eval=True, nargs=-1)
@common_options.output_plot_file_option(default_out='det.pdf')
@common_options.legends_option()
@common_options.no_legend_option()
@common_options.legend_loc_option(dflt='upper-right')
@common_options.title_option()
@common_options.const_layout_option()
@common_options.style_option()
......@@ -18,7 +20,7 @@ from . import figure
'no-spoof', 'ns', '', False
)
@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_label_option()
@common_options.y_label_option()
......
......@@ -10,6 +10,8 @@ from . import figure
@common_options.scores_argument(min_arg=2, force_eval=True, nargs=-1)
@common_options.output_plot_file_option(default_out='epc.pdf')
@common_options.legends_option()
@common_options.no_legend_option()
@common_options.legend_loc_option()
@common_options.title_option()
@common_options.const_layout_option()
@common_options.x_label_option()
......@@ -51,6 +53,8 @@ def epc(ctx, scores, **kwargs):
@common_options.scores_argument(min_arg=2, force_eval=True, nargs=-1)
@common_options.output_plot_file_option(default_out='epsc.pdf')
@common_options.legends_option()
@common_options.no_legend_option()
@common_options.legend_loc_option()
@common_options.const_layout_option()
@common_options.x_label_option()
@common_options.y_label_option()
......
......@@ -13,12 +13,20 @@ import argparse
def calc_pass_rate(threshold, attacks):
"""Calculates the rate of successful spoofing attacks
Keyword parameters:
- threshold - the threshold used for classification
- attack: numpy with the scores of the spoofing attacks
Parameters
----------
threshold :
the threshold used for classification
scores :
numpy with the scores of the spoofing attacks
Returns
-------
float
rate of successful spoofing attacks
"""
return sum(1 for i in attacks if i >= threshold) / float(attacks.size)
return (attacks >= threshold).mean()
def weighted_neg_error_rate_criteria(data,
weight,
......@@ -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
using the method: epsc_thresholds() before passing to this method)
Keyword arguments:
- licit_neg - numpy.array of scores for the negatives (licit scenario)
- licit_pos - numpy.array of scores for the positives (licit scenario)
- spoof_neg - numpy.array of scores for the negatives (spoof scenario)
- spoof_pos - numpy.array of scores for the positives (spoof scenario)
- thresholds - numpy.ndarray with threshold values
- omega - numpy.array of the omega parameter balancing between impostors
Parameters
----------
licit_neg : array_like
array of scores for the negatives (licit scenario)
licit_pos : array_like
array of scores for the positives (licit scenario)
spoof_neg : array_like
array of scores for the negatives (spoof scenario)
spoof_pos : array_like
array of scores for the positives (spoof scenario)
thresholds : array_like
ndarray with threshold values
omega : array_like
array of the omega parameter balancing between impostors
and spoofing attacks
- beta - numpy.array of the beta parameter balancing between real accesses
beta : array_like
array of the beta parameter balancing between real accesses
and all negatives (impostors and spoofing attacks)
"""
if not isinstance(omega, list) and not isinstance(
omega, tuple) and not isinstance(omega, numpy.ndarray):
omega = numpy.array([omega])
else:
omega = numpy.array(omega)
if not isinstance(beta, list) and not isinstance(
beta, tuple) and not isinstance(beta, numpy.ndarray):
beta = numpy.array([beta])
else:
beta = numpy.array(beta)
Returns
-------
far_w_errors: array_like
FAR_w
wer_wb_errors: array_like
WER_wb
"""
far_w_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,
def all_error_rates(licit_neg, licit_pos, spoof_neg, spoof_pos, thresholds,
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
using the method: epsc_thresholds() before passing to this method)
Keyword arguments:
- licit_neg - numpy.array of scores for the negatives (licit scenario)
- licit_pos - numpy.array of scores for the positives (licit scenario)
- spoof_neg - numpy.array of scores for the negatives (spoof scenario)
- spoof_pos - numpy.array of scores for the positives (spoof scenario)
- thresholds - numpy.array with threshold values
- omega - numpy.array of the omega parameter balancing between impostors
Parameters
----------
licit_neg : array_like
array of scores for the negatives (licit scenario)
licit_pos : array_like
array of scores for the positives (licit scenario)
spoof_neg : array_like
array of scores for the negatives (spoof scenario)
spoof_pos : array_like
array of scores for the positives (spoof scenario)
thresholds : array_like
ndarray with threshold values
omega : array_like
array of the omega parameter balancing between impostors
and spoofing attacks
- beta - numpy.array of the beta parameter balancing between real accesses
beta : array_like
array of the beta parameter balancing between real accesses
and all negatives (impostors and spoofing attacks)
"""
if not isinstance(omega, list) and not isinstance(
omega, tuple) and not isinstance(omega, numpy.ndarray):
omega = numpy.array([omega])
else:
omega = numpy.array(omega)
if not isinstance(beta, list) and not isinstance(
beta, tuple) and not isinstance(beta, numpy.ndarray):
beta = numpy.array([beta])
else:
beta = numpy.array(beta)
Returns
-------
far_w_errors: array_like
FAR_w
wer_wb_errors: array_like
WER_wb
"""
frr_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
ALL_CRITERIA = ('bpcer20', 'eer', 'min-hter')
def calc_threshold(method, neg, pos):
"""Calculates the threshold based on the given method.
The scores should be sorted!
......@@ -52,6 +53,7 @@ def calc_threshold(method, neg, pos):
return threshold
class Metrics(measure_figure.Metrics):
def __init__(self, ctx, scores, evaluation, func_load):
super(Metrics, self).__init__(ctx, scores, evaluation, func_load)
......@@ -90,6 +92,7 @@ class Metrics(measure_figure.Metrics):
file=self.log_file
)
class HistPad(measure_figure.Hist):
''' Histograms for PAD '''
......@@ -103,8 +106,6 @@ class HistPad(measure_figure.Hist):
hatch='\\\\'
)
def _calc_pass_rate(threshold, scores):
return (scores >= threshold).mean()
def _iapmr_dot(threshold, iapmr, real_data, **kwargs):
# 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):
mpl.text(threshold + (threshold - axlim[0]) / 12, 100. * iapmr,
'%.1f%%' % (100. * iapmr,), color='C3')
def _iapmr_line_plot(scores, n_points=100, **kwargs):
axlim = mpl.axis()
step = (axlim[1] - axlim[0]) / float(n_points)
thres = [(k * step) + axlim[0] for k in range(2, n_points - 1)]
mix_prob_y = []
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)
def _iapmr_plot(scores, threshold, iapmr, real_data, **kwargs):
_iapmr_dot(threshold, iapmr, real_data, **kwargs)
_iapmr_line_plot(scores, n_points=100, **kwargs)
class HistVuln(measure_figure.Hist):
''' Histograms for vulnerability '''
......@@ -169,15 +173,7 @@ class HistVuln(measure_figure.Hist):
ax2.grid(False)
real_data = True if 'real_data' not in self._ctx.meta else \
self._ctx.meta['real_data']
far, frr = farfrr(neg[0], pos[0], threshold)
_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
col = n % self._ncols
rest_print = self.n_systems - int(idx / self._step_print) * self._step_print
......@@ -187,6 +183,7 @@ class HistVuln(measure_figure.Hist):
ax2.yaxis.label.set_color('red')
ax2.spines['right'].set_color('red')
class PadPlot(measure_figure.PlotBase):
'''Base class for PAD plots'''
def __init__(self, ctx, scores, evaluation, func_load):
......@@ -208,7 +205,10 @@ class PadPlot(measure_figure.PlotBase):
li, la = ax.get_legend_handles_labels()
lines += li
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):
''' Handles the plotting of EPC '''
......@@ -277,12 +277,14 @@ class Epc(PadPlot):
prob_ax.yaxis.set_ticklabels(["%.0f" % val for val in ylabels])
prob_ax.set_axisbelow(True)
title = self._legends[idx] if self._legends is not None else self._title
if title.replace(' ', ''):
mpl.title(title)
#legends for all axes
self._plot_legends()
mpl.xticks(rotation=self._x_rotation)
self._pdf_page.savefig(mpl.gcf())
class Epsc(PadPlot):
''' Handles the plotting of EPSC '''
def __init__(self, ctx, scores, evaluation, func_load,
......@@ -397,9 +399,11 @@ class Epsc(PadPlot):
axis.spines['right'].set_color('red')
if self._var_param == 'omega':
if title.replace(' ', ''):
mpl.title(title or (r"EPSC with $\beta$ = %.2f" %\
self._fixed_param))
else:
if title.replace(' ', ''):
mpl.title(title or (r"EPSC with $\omega$ = %.2f" %\
self._fixed_param))
......@@ -410,6 +414,7 @@ class Epsc(PadPlot):
mpl.xticks(rotation=self._x_rotation)
self._pdf_page.savefig()
class Epsc3D(Epsc):
''' 3D EPSC plots for PAD'''
def compute(self, idx, input_scores, input_names):
......@@ -469,6 +474,7 @@ class Epsc3D(Epsc):
r"WER$_{\omega,\beta}$ (%)" if self._wer else "IAPMR (%)"
)
if title.replace(' ', ''):
mpl.title(title or "3D EPSC")
ax1.set_xticklabels(ax1.get_xticks())
......@@ -477,6 +483,7 @@ class Epsc3D(Epsc):
self._pdf_page.savefig()
class Det(PadPlot):
'''DET for PAD'''
def __init__(self, ctx, scores, evaluation, func_load, criteria, real_data):
......@@ -617,11 +624,13 @@ class Det(PadPlot):
add = " and overlaid SPOOF scenario"
title = self._title if self._title is not None else \
('DET: LICIT' + add)
if title.replace(' ', ''):
mpl.title(title)
mpl.xlabel(self._x_label or "False Acceptance Rate (%)")
mpl.ylabel(self._y_label or "False Rejection Rate (%)")
mpl.grid(True, color=self._grid_color)
mpl.legend(loc='best')
if self._disp_legend:
mpl.legend(loc=self._legend_loc)
self._set_axis()
fig = mpl.gcf()
mpl.xticks(rotation=self._x_rotation)
......@@ -644,6 +653,7 @@ class Det(PadPlot):
else:
det_axis([0.01, 99, 0.01, 99])
class FmrIapmr(PadPlot):
'''FMR vs IAPMR'''
def __init__(self, ctx, scores, evaluation, func_load):
......@@ -682,11 +692,13 @@ class FmrIapmr(PadPlot):
close pdf is needed '''
#only for plots
title = self._title if self._title is not None else "FMR vs IAPMR"
if title.replace(' ', ''):
mpl.title(title)
mpl.xlabel(self._x_label or "False Match Rate (%)")
mpl.ylabel(self._y_label or "IAPMR (%)")
mpl.grid(True, color=self._grid_color)
mpl.legend(loc='best')
if self._disp_legend:
mpl.legend(loc=self._legend_loc)
self._set_axis()
fig = mpl.gcf()
mpl.xticks(rotation=self._x_rotation)
......
......@@ -10,6 +10,8 @@ from . import figure
@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.legends_option()
@common_options.no_legend_option()
@common_options.legend_loc_option()
@common_options.title_option()
@common_options.const_layout_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