Commit 0b85f0c6 authored by Amir MOHAMMADI's avatar Amir MOHAMMADI

Merge branch 'finalplot' into 'master'

Various fix

See merge request !48
parents dd69e7f3 3defd9c3
Pipeline #21699 passed with stages
in 15 minutes and 42 seconds
......@@ -37,6 +37,8 @@ def gen(ctx, outdir, mean_match, mean_non_match, n_sys):
@common_options.metrics_command(common_options.METRICS_HELP.format(
names='FtA, APCER, BPCER, FAR, FRR, ACER',
criteria=CRITERIA, score_format=SCORE_FORMAT,
hter_note='Note that FAR = APCER * (1 - FtA), '
'FRR = FtA + BPCER * (1 - FtA) and ACER = (APCER + BPCER) / 2.',
command='bob pad metrics'), criteria=CRITERIA)
def metrics(ctx, scores, evaluation, **kwargs):
process = figure.Metrics(ctx, scores, evaluation, load.split)
......
......@@ -7,13 +7,14 @@ from .error_utils import calc_threshold
ALL_CRITERIA = ('bpcer20', 'eer', 'min-hter')
class Metrics(measure_figure.Metrics):
class Metrics(bio_figure.Metrics):
'''Compute metrics from score files'''
def __init__(self, ctx, scores, evaluation, func_load):
def __init__(self, ctx, scores, evaluation, func_load,
names=('FtA', 'APCER', 'BPCER', 'FAR', 'FRR', 'HTER')):
super(Metrics, self).__init__(
ctx, scores, evaluation, func_load,
names=('FtA', 'APCER', 'BPCER', 'FAR', 'FRR', 'ACER'))
ctx, scores, evaluation, func_load, names
)
def get_thres(self, criterion, dev_neg, dev_pos, far):
if self._criterion == 'bpcer20':
......@@ -61,7 +62,7 @@ class Hist(measure_figure.Hist):
def _setup_hist(self, neg, pos):
self._title_base = 'PAD'
self._density_hist(
pos[0], n=0, label='Bona Fide', color='C1'
pos[0], n=0, label='Bona-fide', color='C1'
)
self._density_hist(
neg[0], n=1, label='Presentation attack', alpha=0.4, color='C7',
......
......@@ -2,17 +2,20 @@
"""
import os
import logging
import numpy
import click
from click.types import FLOAT
from bob.measure.script import common_options
from bob.extension.scripts.click_helper import (
verbosity_option, bool_option, list_float_option)
verbosity_option, bool_option, list_float_option
)
from bob.core import random
from bob.io.base import create_directories_safe
from bob.bio.base.score import load
from . import vuln_figure as figure
LOGGER = logging.getLogger(__name__)
NUM_GENUINE_ACCESS = 5000
NUM_ZEIMPOSTORS = 5000
NUM_PA = 5000
......@@ -70,9 +73,9 @@ def write_scores_to_file(neg, pos, filename, attack=False):
@click.command()
@click.argument('outdir')
@click.option('--mean-gen', default=7, type=FLOAT, show_default=True)
@click.option('--mean-zei', default=3, type=FLOAT, show_default=True)
@click.option('--mean-pa', default=5, type=FLOAT, show_default=True)
@click.option('-mg', '--mean-gen', default=7, type=FLOAT, show_default=True)
@click.option('-mz', '--mean-zei', default=3, type=FLOAT, show_default=True)
@click.option('-mp', '--mean-pa', default=5, type=FLOAT, show_default=True)
@verbosity_option()
def gen(outdir, mean_gen, mean_zei, mean_pa):
"""Generate random scores.
......@@ -103,7 +106,7 @@ def gen(outdir, mean_gen, mean_zei, mean_pa):
@click.command()
@common_options.scores_argument(min_arg=2, nargs=-1)
@common_options.output_plot_file_option(default_out='vuln_roc.pdf')
@common_options.output_plot_file_option(default_out='roc.pdf')
@common_options.legends_option()
@common_options.no_legend_option()
@common_options.legend_loc_option(dflt='upper-right')
......@@ -143,7 +146,7 @@ def roc(ctx, scores, real_data, **kwargs):
@click.command()
@common_options.scores_argument(min_arg=2, nargs=-1)
@common_options.output_plot_file_option(default_out='vuln_det.pdf')
@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')
......@@ -183,7 +186,7 @@ def det(ctx, scores, real_data, **kwargs):
@click.command()
@common_options.scores_argument(min_arg=2, force_eval=True, nargs=-1)
@common_options.output_plot_file_option(default_out='vuln_epc.pdf')
@common_options.output_plot_file_option(default_out='epc.pdf')
@common_options.legends_option()
@common_options.no_legend_option()
@common_options.legend_loc_option()
......@@ -227,23 +230,25 @@ 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.output_plot_file_option(default_out='epsc.pdf')
@common_options.titles_option()
@common_options.legends_option()
@common_options.no_legend_option()
@common_options.legend_loc_option()
@common_options.legend_ncols_option()
@common_options.const_layout_option()
@common_options.x_label_option()
@common_options.y_label_option()
@common_options.figsize_option(dflt=None)
@common_options.figsize_option(dflt='5,3')
@common_options.style_option()
@common_options.bool_option(
'wer', 'w', 'Whether to plot the WER related lines or not.', True
)
@common_options.bool_option(
'three-d', 'D', 'If true, generate 3D plots', False
'three-d', 'D', 'If true, generate 3D plots. You need to turn off '
'wer or iapmr when using this option.', False
)
@common_options.bool_option(
'iapmr', 'I', 'Whether to plot the IAPMR related lines or not.', False
'iapmr', 'I', 'Whether to plot the IAPMR related lines or not.', True
)
@click.option('-c', '--criteria', default="eer", show_default=True,
help='Criteria for threshold selection',
......@@ -251,14 +256,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):
......@@ -282,25 +286,27 @@ 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')
LOGGER.info('Cannot plot both WER and IAPMR in 3D. Will turn IAPMR off.')
ctx.meta['iapmr'] = False
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()
@click.command()
@common_options.scores_argument(nargs=-1, min_arg=2)
@common_options.output_plot_file_option(default_out='vuln_hist.pdf')
@common_options.output_plot_file_option(default_out='hist.pdf')
@common_options.n_bins_option()
@common_options.criterion_option()
@common_options.thresholds_option()
......@@ -346,10 +352,12 @@ def hist(ctx, scores, evaluation, **kwargs):
Examples:
$ bob vuln vuln_hist -e -v licit/scores-dev licit/scores-eval \
$ bob vuln hist -v licit/scores-dev spoof/scores-dev
$ bob vuln hist -e -v licit/scores-dev licit/scores-eval \
spoof/scores-dev spoof/scores-eval
$ bob vuln vuln_hist -e -v {licit,spoof}/scores-{dev,eval}
$ bob vuln hist -e -v {licit,spoof}/scores-{dev,eval}
'''
process = figure.HistVuln(ctx, scores, evaluation, load.split)
process.run()
......@@ -364,7 +372,7 @@ def hist(ctx, scores, evaluation, **kwargs):
@common_options.title_option()
@common_options.const_layout_option()
@common_options.style_option()
@common_options.figsize_option(dflt=None)
@common_options.figsize_option()
@verbosity_option()
@common_options.axes_val_option()
@common_options.x_rotation_option()
......
......@@ -11,6 +11,9 @@ from bob.measure import (
)
from bob.measure import plot
from . import error_utils
import logging
LOGGER = logging.getLogger("bob.pad.base")
def _iapmr_dot(threshold, iapmr, real_data, **kwargs):
......@@ -95,12 +98,13 @@ class HistVuln(measure_figure.Hist):
ax2.spines['right'].set_color('red')
class PadPlot(measure_figure.PlotBase):
'''Base class for PAD plots'''
class VulnPlot(measure_figure.PlotBase):
'''Base class for vulnerability analysis plots'''
def __init__(self, ctx, scores, evaluation, func_load):
super(PadPlot, self).__init__(ctx, scores, evaluation, func_load)
super(VulnPlot, self).__init__(ctx, scores, evaluation, func_load)
mpl.rcParams['figure.constrained_layout.use'] = self._clayout
self._nlegends = ctx.meta.get('legends_ncol', 3)
def end_process(self):
'''Close pdf '''
......@@ -119,10 +123,11 @@ class PadPlot(measure_figure.PlotBase):
labels += la
if self._disp_legend:
mpl.gca().legend(lines, labels, loc=self._legend_loc,
fancybox=True, framealpha=0.5)
ncol=self._nlegends, fancybox=True,
framealpha=0.5)
class Epc(PadPlot):
class Epc(VulnPlot):
''' Handles the plotting of EPC '''
def __init__(self, ctx, scores, evaluation, func_load):
......@@ -132,7 +137,7 @@ class Epc(PadPlot):
self._title = self._title or ('EPC and IAPMR' if self._iapmr else
'EPC')
self._x_label = self._x_label or r"Weight $\beta$"
self._y_label = self._y_label or "WER (%)"
self._y_label = self._y_label or "HTER (%)"
self._eval = True # always eval data with EPC
self._split = False
self._nb_figs = 1
......@@ -151,14 +156,12 @@ class Epc(PadPlot):
mpl.gcf().clear()
mpl.grid()
LOGGER.info("EPC using %s", '%s-%s' % (input_names[0], input_names[1]))
plot.epc(
licit_dev_neg, licit_dev_pos, licit_eval_neg, licit_eval_pos,
self._points,
color='C0', linestyle=self._linestyles[idx],
label=self._label(
'WER', '%s-%s' % (input_names[0], input_names[1]), idx
),
label=self._label('HTER (licit)', idx)
)
mpl.xlabel(self._x_label)
mpl.ylabel(self._y_label)
......@@ -177,10 +180,10 @@ class Epc(PadPlot):
100. * error_utils.calc_pass_rate(k, spoof_eval_neg)
)
LOGGER.info("IAPMR in EPC plot using %s",
'%s-%s' % (input_names[0], input_names[1]))
mpl.plot(
thres, mix_prob_y, label=self._label(
'IAPMR', '%s-%s' % (input_names[0], input_names[1]), idx
), color='C3'
thres, mix_prob_y, label=self._label('IAPMR (spoof)', idx), color='C3'
)
prob_ax.set_yticklabels(prob_ax.get_yticks())
......@@ -189,7 +192,7 @@ class Epc(PadPlot):
prob_ax.spines['right'].set_color('C3')
ylabels = prob_ax.get_yticks()
prob_ax.yaxis.set_ticklabels(["%.0f" % val for val in ylabels])
prob_ax.set_ylabel('IAPMR', color='C3')
prob_ax.set_ylabel('IAPMR (%)', color='C3')
prob_ax.set_axisbelow(True)
ax1.yaxis.label.set_color('C0')
ax1.tick_params(axis='y', colors='C0')
......@@ -204,24 +207,28 @@ class Epc(PadPlot):
self._pdf_page.savefig(mpl.gcf())
class Epsc(PadPlot):
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', []) * 2
self._legend_loc = self._legend_loc or 'upper center'
self._eval = True # always eval data with EPC
self._split = False
self._nb_figs = 1
self._title = ''
self._sampling = ctx.meta.get('sampling', 5)
mpl.grid(True)
self._axis1 = None
self._axis2 = None
if self._min_arg != 4:
raise click.BadParameter("You must provide 4 scores files:{licit,"
......@@ -237,103 +244,123 @@ class Epsc(PadPlot):
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()
merge_sys = (self._fixed_params is None or
len(self._fixed_params) == 1) and self.n_systems > 1
legend = ''
if self._legends is not None and idx < len(self._legends):
legend = self._legends[idx]
elif self.n_systems > 1:
legend = 'Sys%d' % (idx + 1)
n_col = 1 if self._iapmr else 0
n_col += 1 if self._wer else 0
if not merge_sys or idx == 0:
# axes should only be created once
mpl.figure()
self._axis1 = mpl.subplot(1, n_col, 1)
if n_col == 2:
self._axis2 = mpl.subplot(1, n_col, 2)
else:
self._axis2 = self._axis1
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 merge_sys:
assert pi == 0
pi = idx
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
)
if self._iapmr:
axis = mpl.gca()
if self._wer:
axis = mpl.twinx()
axis.grid(False)
if self._var_param == 'omega':
mpl.plot(
omega,
100. * errors[2].flatten(),
color='C3',
linestyle='-',
label='IAPMR')
mpl.xlabel(self._x_label or r"Weight $\omega$")
else:
mpl.plot(
beta,
100. * errors[2].flatten(),
color='C3',
linestyle='-',
label='IAPMR')
mpl.xlabel(self._x_label or r"Weight $\beta$")
mpl.ylabel(self._y_label or r"IAPMR (%)")
if self._wer:
axis.set_yticklabels(axis.get_yticks())
axis.tick_params(axis='y', colors='red')
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))
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
mpl.grid()
self._plot_legends()
ax1.set_xticklabels(ax1.get_xticks())
ax1.set_yticklabels(ax1.get_yticks())
mpl.sca(self._axis1)
# between the negatives (impostors and Presentation attacks)
base = r"(%s) " % legend if legend.strip() else ""
if self._wer:
set_title = self._titles[idx] if self._titles is not None and \
len(self._titles) > idx else None
display = set_title.replace(' ', '') if set_title is not None\
else True
wer_title = set_title or ""
if display:
mpl.title(wer_title)
if self._var_param == 'omega':
label = r"%s$\beta=%.1f$" % (base, fp)
mpl.plot(
omega, 100. * errors[4].flatten(),
color=self._colors[pi], linestyle='-', label=label)
mpl.xlabel(self._x_label or r"Weight $\omega$")
else:
label = r"%s$\omega=%.1f$" % (base, fp)
mpl.plot(
beta, 100. * errors[4].flatten(),
color=self._colors[pi], linestyle='-', label=label)
mpl.xlabel(self._x_label or r"Weight $\beta$")
mpl.ylabel(self._y_label or r"WER$_{\omega,\beta}$ (%)")
if self._iapmr:
mpl.sca(self._axis2)
set_title = self._titles[idx + self.n_systems] \
if self._titles is not None and \
len(self._titles) > self.n_systems + idx else None
display = set_title.replace(' ', '') if set_title is not None\
else True
iapmr_title = set_title or ""
if display:
mpl.title(iapmr_title)
if self._var_param == 'omega':
label = r"$%s $\beta=%.1f$" % (base, fp)
mpl.plot(
omega, 100. * errors[2].flatten(),
color=self._colors[pi], linestyle='-', label=label
)
mpl.xlabel(self._x_label or r"Weight $\omega$")
else:
label = r"%s $\omega=%.1f$" % (base, fp)
mpl.plot(
beta, 100. * errors[2].flatten(), linestyle='-',
color=self._colors[pi], label=label
)
mpl.xlabel(self._x_label or r"Weight $\beta$")
mpl.ylabel(self._y_label or r"IAPMR (%)")
self._axis2.set_xticklabels(self._axis2.get_xticks())
self._axis2.set_yticklabels(self._axis2.get_yticks())
self._axis1.set_xticklabels(self._axis1.get_xticks())
self._axis1.set_yticklabels(self._axis1.get_yticks())
mpl.xticks(rotation=self._x_rotation)
self._pdf_page.savefig()
if self._fixed_params is None or len(self._fixed_params) > 1 or \
idx == self.n_systems - 1:
# all plots share same legends
lines, labels = self._axis1.get_legend_handles_labels()
mpl.gcf().legend(
lines, labels, loc=self._legend_loc, fancybox=True, mode="expand",
framealpha=0.5, ncol=self._nlegends, bbox_to_anchor=(0., 1.12, 1., .102)
)
mpl.tight_layout()
self._pdf_page.savefig(bbox_inches='tight')
class Epsc3D(Epsc):
......@@ -406,7 +433,7 @@ class Epsc3D(Epsc):
self._pdf_page.savefig()
class BaseVulnDetRoc(PadPlot):
class BaseVulnDetRoc(VulnPlot):
'''Base for DET and ROC'''
def __init__(self, ctx, scores, evaluation, func_load, real_data,
......@@ -424,13 +451,14 @@ class BaseVulnDetRoc(PadPlot):
licit_pos = input_scores[0][1]
spoof_neg = input_scores[1][0]
spoof_pos = input_scores[1][1]
LOGGER.info("FNMR licit using %s", input_names[0])
self._plot(
licit_neg,
licit_pos,
self._points,
color='C0',
linestyle='-',
label=self._label("licit", input_names[0], idx)
label=self._label("Licit scenario", idx)
)
if not self._no_spoof and spoof_neg is not None:
ax1 = mpl.gca()
......@@ -443,13 +471,14 @@ class BaseVulnDetRoc(PadPlot):
ax2.spines['bottom'].set_color('C0')
ax1.xaxis.label.set_color('C0')
ax1.tick_params(axis='x', colors='C0')
LOGGER.info("Spoof IAPMR using %s", input_names[1])
self._plot(
spoof_neg,
spoof_pos,
self._points,
color='C3',
linestyle=':',
label=self._label("spoof", input_names[1], idx)
label=self._label("Spoof scenario", idx)
)
mpl.sca(ax1)
......@@ -492,7 +521,7 @@ class BaseVulnDetRoc(PadPlot):
('FMNR', farfrr_licit[1] * 100))
if not self._real_data:
label_licit = '%s @ operating point' % self._y_label
label_licit = '%s @ operating point' % self._x_label
label_spoof = 'IAPMR @ operating point'
else:
label_licit = 'FMR=%.2f%%' % (farfrr_licit[0] * 100)
......@@ -579,6 +608,7 @@ class DetVuln(BaseVulnDetRoc):
return points, [ppndf(i) for i in points]
def _plot(self, x, y, points, **kwargs):
LOGGER.info("Plot DET")
plot.det(
x, y, points,
color=kwargs.get('color'),
......@@ -604,6 +634,7 @@ class RocVuln(BaseVulnDetRoc):
self._legend_loc = self._legend_loc or best_legend
def _plot(self, x, y, points, **kwargs):
LOGGER.info("Plot ROC")
plot.roc_for_far(
x, y,
far_values=plot.log_values(self._min_dig or -4),
......@@ -618,16 +649,15 @@ class RocVuln(BaseVulnDetRoc):
return points, points2
class FmrIapmr(PadPlot):
class FmrIapmr(VulnPlot):
'''FMR vs IAPMR'''
def __init__(self, ctx, scores, evaluation, func_load):
super(FmrIapmr, self).__init__(ctx, scores, evaluation, func_load)
self._eval = True # always eval data with EPC
self._eval = True # Always ask for eval data
self._split = False
self._nb_figs = 1
self._semilogx = False if 'semilogx' not in ctx.meta else\
ctx.meta['semilogx']
self._semilogx = ctx.meta.get('semilogx', False)
if self._min_arg != 4:
raise click.BadParameter("You must provide 4 scores files:{licit,"
"spoof}/{dev,eval}")
......@@ -640,13 +670,15 @@ class FmrIapmr(PadPlot):
fmr_list = np.linspace(0, 1, 100)
iapmr_list = []
for i, fmr in enumerate(fmr_list):
thr = far_threshold(licit_eval_neg, licit_eval_pos, fmr, True)
thr = far_threshold(licit_eval_neg, licit_eval_pos, fmr)
iapmr_list.append(farfrr(spoof_eval_neg, licit_eval_pos, thr)[0])
# re-calculate fmr since threshold might give a different result
# for fmr.
fmr_list[i] = farfrr(licit_eval_neg, licit_eval_pos, thr)[0]
label = self._legends[idx] if self._legends is not None else \
'(%s/%s)' % (input_names[1], input_names[3])
('curve %d' % (idx + 1))
LOGGER.info("Plot FmrIapmr using: %s/%s",
input_names[1], input_names[3])
if self._semilogx:
mpl.semilogx(fmr_list, iapmr_list, label=label)
else:
......@@ -667,7 +699,6 @@ class FmrIapmr(PadPlot):
self._set_axis()
fig = mpl.gcf()
mpl.xticks(rotation=self._x_rotation)
mpl.tick_params(axis='both', which='major', labelsize=4)
self._pdf_page.savefig(fig)
......
......@@ -8,6 +8,6 @@ from bob.extension.scripts.click_helper import AliasedGroup
@with_plugins(pkg_resources.iter_entry_points('bob.vuln.cli'))
@click.group(cls=AliasedGroup)
def vuln():
def vulnerability():
"""Vulnerability analysis related commands."""
pass
......@@ -13,7 +13,7 @@ def test_det_pad():
result = runner.invoke(pad_commands.det, ['-e', '--output',
'DET.pdf',
licit_dev, licit_test])
assert result.exit_code == 0, (result.exit_code, result.output)
assert result.exit_code == 0, (result.exit_code, result.output, result.exception)
def test_det_vuln():
......@@ -32,7 +32,7 @@ def test_det_vuln():
'DET.pdf',
licit_dev, licit_test,
spoof_dev, spoof_test])
assert result.exit_code == 0, (result.exit_code, result.output)
assert result.exit_code == 0, (result.exit_code, result.output, result.exception)
def test_fmr_iapmr_vuln():
......@@ -50,13 +50,13 @@ def test_fmr_iapmr_vuln():
'--output', 'FMRIAPMR.pdf', licit_dev, licit_test, spoof_dev,
spoof_test
])
assert result.exit_code == 0, (result.exit_code, result.output)
assert result.exit_code == 0, (result.exit_code, result.output, result.exception)
result = runner.invoke(vuln_commands.fmr_iapmr, [
'--output', 'FMRIAPMR.pdf', licit_dev, licit_test, spoof_dev,
spoof_test, '-G', '-L', '1e-7,1,0,1'
])
assert result.exit_code == 0, (result.exit_code, result.output)
assert result.exit_code == 0, (result.exit_code, result.output, result.exception)
def test_hist_pad():
......@@ -71,7 +71,7 @@ def test_hist_pad():