diff --git a/bob/measure/plot.py b/bob/measure/plot.py index 5d414327111535e3a7d36facbe29bdf72dd0a1cb..1512448fd58263c38bebba0b9f272001f3a12d42 100644 --- a/bob/measure/plot.py +++ b/bob/measure/plot.py @@ -260,7 +260,7 @@ def epc(dev_negatives, dev_positives, test_negatives, test_positives, return pyplot.plot(out[0, :], 100.0 * out[1, :], **kwargs) -def det(negatives, positives, npoints=100, axisfontsize='x-small', **kwargs): +def det(negatives, positives, npoints=100, **kwargs): """Plots Detection Error Trade-off (DET) curve as defined in the paper: Martin, A., Doddington, G., Kamm, T., Ordowski, M., & Przybocki, M. (1997). @@ -381,9 +381,9 @@ def det(negatives, positives, npoints=100, axisfontsize='x-small', **kwargs): pticks = [ppndf(float(v)) for v in desiredTicks] ax = pyplot.gca() # and finally we set our own tick marks ax.set_xticks(pticks) - ax.set_xticklabels(desiredLabels, size=axisfontsize) + ax.set_xticklabels(desiredLabels) ax.set_yticks(pticks) - ax.set_yticklabels(desiredLabels, size=axisfontsize) + ax.set_yticklabels(desiredLabels) return retval diff --git a/bob/measure/script/commands.py b/bob/measure/script/commands.py index ae83cded2b246d45d8422f66e176dd8f397e8fe1..9820a757b2c5ba0ffdd484840642b40cd70aeb90 100644 --- a/bob/measure/script/commands.py +++ b/bob/measure/script/commands.py @@ -21,16 +21,14 @@ from bob.extension.scripts.click_helper import (verbosity_option, @verbosity_option() @click.pass_context def metrics(ctx, scores, evaluation, **kwargs): - """Prints a single output line that contains all info for a given - criterion (eer or hter). + """Prints a table that contains FtA, FAR, FRR, FMR, FMNR, HTER for a given + threshold criterion (eer or hter). - You need provide one or more development score file(s) for each experiment. + You need to provide one or more development score file(s) for each experiment. You can also provide evaluation files along with dev files. If only dev scores are provided, you must use flag `--no-evaluation`. - Resulting table format can be changer using the `--tablefmt`. Default - formats are `fancy_grid` when output in the terminal and `latex` when - written in a log file (see `--log`) + Resulting table format can be changed using the `--tablefmt`. Examples: $ bob measure metrics dev-scores @@ -42,7 +40,6 @@ def metrics(ctx, scores, evaluation, **kwargs): process = figure.Metrics(ctx, scores, evaluation, load.split_files) process.run() - @click.command() @common_options.scores_argument(nargs=-1) @common_options.title_option() @@ -53,12 +50,14 @@ def metrics(ctx, scores, evaluation, **kwargs): @common_options.points_curve_option() @common_options.semilogx_option(True) @common_options.axes_val_option(dflt=[1e-4, 1, 1e-4, 1]) -@common_options.axis_fontsize_option() @common_options.x_rotation_option() @common_options.x_label_option() @common_options.y_label_option() @common_options.lines_at_option() @common_options.const_layout_option() +@common_options.figsize_option() +@common_options.style_option() +@common_options.const_layout_option() @verbosity_option() @click.pass_context def roc(ctx, scores, evaluation, **kwargs): @@ -67,7 +66,7 @@ def roc(ctx, scores, evaluation, **kwargs): false non match rate on the vertical axis. The values for the axis will be computed using :py:func:`bob.measure.roc`. - You need provide one or more development score file(s) for each experiment. + You need to provide one or more development score file(s) for each experiment. You can also provide evaluation files along with dev files. If only dev scores are provided, you must use flag `--no-evaluation`. @@ -82,7 +81,6 @@ def roc(ctx, scores, evaluation, **kwargs): process = figure.Roc(ctx, scores, evaluation, load.split_files) process.run() - @click.command() @common_options.scores_argument(nargs=-1) @common_options.output_plot_file_option(default_out='det.pdf') @@ -91,12 +89,14 @@ def roc(ctx, scores, evaluation, **kwargs): @common_options.sep_dev_eval_option() @common_options.eval_option() @common_options.axes_val_option(dflt=[0.01, 95, 0.01, 95]) -@common_options.axis_fontsize_option(dflt=6) @common_options.x_rotation_option(dflt=45) @common_options.x_label_option() @common_options.y_label_option() @common_options.points_curve_option() @common_options.const_layout_option() +@common_options.figsize_option() +@common_options.style_option() +@common_options.const_layout_option() @verbosity_option() @click.pass_context def det(ctx, scores, evaluation, **kwargs): @@ -104,7 +104,7 @@ def det(ctx, scores, evaluation, **kwargs): modified ROC curve which plots error rates on both axes (false positives on the x-axis and false negatives on the y-axis) - You need provide one or more development score file(s) for each experiment. + You need to provide one or more development score file(s) for each experiment. You can also provide evaluation files along with dev files. If only dev scores are provided, you must use flag `--no-evaluation`. @@ -119,17 +119,18 @@ def det(ctx, scores, evaluation, **kwargs): process = figure.Det(ctx, scores, evaluation, load.split_files) process.run() - @click.command() @common_options.scores_argument(eval_mandatory=True, nargs=-1) @common_options.output_plot_file_option(default_out='epc.pdf') @common_options.title_option() @common_options.titles_option() @common_options.points_curve_option() -@common_options.axis_fontsize_option() @common_options.const_layout_option() @common_options.x_label_option() @common_options.y_label_option() +@common_options.figsize_option() +@common_options.style_option() +@common_options.const_layout_option() @verbosity_option() @click.pass_context def epc(ctx, scores, **kwargs): @@ -138,7 +139,7 @@ def epc(ctx, scores, **kwargs): a-priori on the development set and accounts for varying relative cost in [0; 1] of FPR and FNR when calculating the threshold. - You need provide one or more development score and eval file(s) + You need to provide one or more development score and eval file(s) for each experiment. Examples: @@ -149,27 +150,28 @@ def epc(ctx, scores, **kwargs): process = figure.Epc(ctx, scores, True, load.split_files) process.run() - @click.command() @common_options.scores_argument(nargs=-1) @common_options.output_plot_file_option(default_out='hist.pdf') @common_options.eval_option() @common_options.n_bins_option() @common_options.criterion_option() -@common_options.axis_fontsize_option() @common_options.thresholds_option() @common_options.const_layout_option() @common_options.show_dev_option() @common_options.print_filenames_option() @common_options.title_option() @common_options.titles_option() +@common_options.figsize_option() +@common_options.style_option() +@common_options.const_layout_option() @verbosity_option() @click.pass_context def hist(ctx, scores, evaluation, **kwargs): """ Plots histograms of positive and negatives along with threshold criterion. - You need provide one or more development score file(s) for each experiment. + You need to provide one or more development score file(s) for each experiment. You can also provide evaluation files along with dev files. If only dev scores are provided, you must use flag `--no-evaluation`. @@ -189,7 +191,6 @@ def hist(ctx, scores, evaluation, **kwargs): process = figure.Hist(ctx, scores, evaluation, load.split_files) process.run() - @click.command() @common_options.scores_argument(nargs=-1) @common_options.titles_option() @@ -203,6 +204,9 @@ def hist(ctx, scores, evaluation, **kwargs): @common_options.n_bins_option() @common_options.lines_at_option() @common_options.const_layout_option() +@common_options.figsize_option() +@common_options.style_option() +@common_options.const_layout_option() @verbosity_option() @click.pass_context def evaluate(ctx, scores, evaluation, **kwargs): @@ -227,6 +231,11 @@ def evaluate(ctx, scores, evaluation, **kwargs): Examples: $ bob measure evaluate dev-scores + $ bob measure evaluate scores-dev1 scores-eval1 scores-dev2 + scores-eval2 + + $ bob measure evaluate /path/to/sys-{1,2,3}/scores-{dev,eval} + $ bob measure evaluate -l metrics.txt -o my_plots.pdf dev-scores eval-scores ''' # first time erase if existing file @@ -256,11 +265,10 @@ def evaluate(ctx, scores, evaluation, **kwargs): if evaluation: click.echo("Computing EPC...") ctx.forward(epc) # use class defaults plot settings - ctx.forward(epc) # the last one closes the file ctx.meta['closef'] = True click.echo("Computing score histograms...") - ctx.meta['criter'] = 'hter' # no criterion passed in evaluate + ctx.meta['criter'] = 'eer' # no criterion passed in evaluate ctx.forward(hist) click.echo("Evaluate successfully completed!") click.echo("[plots] => %s" % (ctx.meta['output'])) diff --git a/bob/measure/script/common_options.py b/bob/measure/script/common_options.py index 86aca83c336fa1146c4e866576a7ac06ba05f24b..43a58c981c7b1880f48a52eb3b3b2d3857752a2c 100644 --- a/bob/measure/script/common_options.py +++ b/bob/measure/script/common_options.py @@ -1,16 +1,14 @@ '''Stores click common options for plots''' -import math import pkg_resources # to make sure bob gets imported properly import logging import click -from click.types import INT, FLOAT, Choice, File +from click.types import INT, FLOAT import matplotlib.pyplot as plt from matplotlib.backends.backend_pdf import PdfPages -from bob.extension.scripts.click_helper import (verbosity_option, bool_option, - list_float_option) +from bob.extension.scripts.click_helper import (bool_option, list_float_option) -logger = logging.getLogger(__name__) +LOGGER = logging.getLogger(__name__) def scores_argument(eval_mandatory=False, min_len=1, **kwargs): """Get the argument for scores, and add `dev-scores` and `eval-scores` in @@ -18,7 +16,6 @@ def scores_argument(eval_mandatory=False, min_len=1, **kwargs): Parameters ---------- - eval_mandatory : If evaluation files are mandatory min_len : @@ -27,7 +24,8 @@ def scores_argument(eval_mandatory=False, min_len=1, **kwargs): Returns ------- - Click option + callable + A decorator to be used for adding score arguments for click commands """ def custom_scores_argument(func): def callback(ctx, param, value): @@ -129,23 +127,10 @@ def lines_at_option(**kwargs): '''Get option to draw const far line''' return list_float_option( name='lines-at', short_name='la', - desc='If given, draw a veritcal lines on ROC plots', + desc='If given, draw veritcal lines on ROC plots', nitems=None, dflt=None, **kwargs ) -def axis_fontsize_option(dflt=8, **kwargs): - '''Get option for axis font size''' - def custom_axis_fontsize_option(func): - def callback(ctx, param, value): - value = abs(value) - ctx.meta['fontsize'] = value - return value - return click.option( - '-F', '--fontsize', type=click.INT, default=dflt, show_default=True, - help='Axis fontsize', - callback=callback, **kwargs)(func) - return custom_axis_fontsize_option - def x_rotation_option(dflt=0, **kwargs): '''Get option for rotartion of the x axis lables''' def custom_x_rotation_option(func): @@ -159,7 +144,6 @@ def x_rotation_option(dflt=0, **kwargs): callback=callback, **kwargs)(func) return custom_x_rotation_option - def cost_option(**kwargs): '''Get option to get cost for FAR''' def custom_cost_option(func): @@ -174,18 +158,6 @@ def cost_option(**kwargs): callback=callback, **kwargs)(func) return custom_cost_option -def n_sys_option(**kwargs): - '''Get the number of systems to be processed''' - def custom_n_sys_option(func): - def callback(ctx, param, value): - ctx.meta['n_sys'] = value - return value - return click.option( - '--n-sys', type=INT, default=1, show_default=True, - help='The number of systems to be processed', - callback=callback, is_eager=True , **kwargs)(func) - return custom_n_sys_option - def points_curve_option(**kwargs): '''Get the number of points use to draw curves''' def custom_points_curve_option(func): @@ -248,7 +220,7 @@ def output_plot_file_option(default_out='plots.pdf', **kwargs): print the path of the file in the log''' ctx.meta['output'] = value ctx.meta['PdfPages'] = PdfPages(value) - logger.debug("Plots will be output in %s", value) + LOGGER.debug("Plots will be output in %s", value) return value return click.option( '-o', '--output', @@ -264,7 +236,7 @@ def output_plot_metric_option(**kwargs): ''' Save ouput file and associated pdf in context list, print the path of the file in the log''' if value is not None: - logger.debug("Metrics will be output in %s", value) + LOGGER.debug("Metrics will be output in %s", value) ctx.meta['log'] = value return value return click.option( @@ -279,7 +251,6 @@ def criterion_option(lcriteria=['eer', 'hter', 'far'], **kwargs): Parameters ---------- - lcriteria : :any:`list` List of possible criteria """ @@ -299,7 +270,6 @@ def criterion_option(lcriteria=['eer', 'hter', 'far'], **kwargs): callback=callback, is_eager=True ,**kwargs)(func) return custom_criterion_option - def far_option(**kwargs): '''Get option to get far value''' def custom_far_option(func): @@ -314,40 +284,6 @@ def far_option(**kwargs): callback=callback, show_default=True,**kwargs)(func) return custom_far_option -def rank_option(**kwargs): - '''Get option for rank parameter''' - def custom_rank_option(func): - def callback(ctx, param, value): - value = 1 if value < 0 else value - ctx.meta['rank'] = value - return value - return click.option( - '--rank', type=click.INT, default=1, - help='Given threshold for metrics computations', - callback=callback, show_default=True,**kwargs)(func) - return custom_rank_option - -def label_option(name_option='x_label', **kwargs): - '''Get labels options based on the given name. - - Parameters: - ---------- - name_option: str, optional - Name of the label option (e.g. x-lable, y1-label) - ''' - def custom_label_option(func): - def callback(ctx, param, value): - ''' Get and save labels list in the context list ''' - ctx.meta[name_option.replace('-', '_')] = value if value is None else \ - [int(i) for i in value.split(',')] - return value - return click.option( - '--' + name_option, - help='The id of figures which should have x_label separated by ' - 'comma. For example ``--%s 1,2,4``.' % name_option, - callback=callback, **kwargs)(func) - return custom_label_option - def figsize_option(**kwargs): '''Get option for matplotlib figsize''' def custom_figsize_option(func): diff --git a/bob/measure/script/figure.py b/bob/measure/script/figure.py index 2ce0afc6067007a77dfc13d95412e47ad9309973..7a453396e0cc1f1e786e90c798ccf9320069be33 100644 --- a/bob/measure/script/figure.py +++ b/bob/measure/script/figure.py @@ -4,7 +4,6 @@ from __future__ import division, print_function from abc import ABCMeta, abstractmethod import sys import ntpath -import numpy import click import matplotlib import matplotlib.pyplot as mpl @@ -36,29 +35,14 @@ class MeasureBase(object): Attributes ---------- - - _scores: :any:`list`: - List of input files (e.g. dev-{1, 2, 3}, {dev,eval}-scores1 - - _ctx : :py:class:`dict` - Click context dictionary. - - _eval : :py:class:`bool` - True if eval data are used - - _titles: :any:`list` - List of titles for each system (dev + (eval) scores) - func_load: Function that is used to load the input files - """ __metaclass__ = ABCMeta #for python 2.7 compatibility def __init__(self, ctx, scores, eval, func_load): """ Parameters ---------- - ctx : :py:class:`dict` Click context dictionary. @@ -137,10 +121,8 @@ class MeasureBase(object): Parameters ---------- - idx : :obj:`int` index of the system - dev_score: Development scores. Can be a tuple (neg, pos) of :py:class:`numpy.ndarray` (e.g. @@ -173,7 +155,6 @@ class MeasureBase(object): Returns ------- - dev_scores: :any:`list`: A list that contains, for each required dev score file, the output of ``func_load`` eval_scores: :any:`list`: A list that contains, for each required @@ -210,8 +191,7 @@ class MeasureBase(object): '''Process score files and return neg/pos/fta for eval and dev''' dev_neg = dev_pos = dev_fta = eval_neg = eval_pos = eval_fta = None if dev_score[0] is not None: - dev_score, dev_fta = utils.get_fta(dev_score) - dev_neg, dev_pos = dev_score + (dev_neg, dev_pos), dev_fta = utils.get_fta(dev_score) if dev_neg is None: raise click.UsageError("While loading dev-score file") @@ -229,29 +209,8 @@ class Metrics(MeasureBase): Attributes ---------- - - _tablefmt: str - Table format - - _criter: str - Criterion to compute threshold, see :py:func:`bob.measure.utils.get_thres` - - _open_mode: str - Open mode of the output file (e.g. `w`, `a+`) - - _thres: :any:`list` - If given, uses those threshold instead of computing them. Lenght of the - list must be the same as the number of systems. - - _far: :obj:`float` - If given, uses this FAR to compute threshold - - _log: str - Path to output log file - log_file: str output stream - ''' def __init__(self, ctx, scores, evaluation, func_load): super(Metrics, self).__init__(ctx, scores, evaluation, func_load) @@ -361,33 +320,11 @@ class Metrics(MeasureBase): class PlotBase(MeasureBase): ''' Base class for plots. Regroup several options and code shared by the different plots - - Attributes - ---------- - - _output: str - Path to the output pdf file - - _points: :obj:`int` - Number of points used to draw curves - - - _split: :obj:`bool` - If False, dev and eval curves will be printed on the some figure - - _axlim: :any:`list` - Minimum/Maximum values for the X and Y axes - - _x_rotation: :obj:`int` - Rotation of the X axis labels - - _axisfontsize: :obj:`int` - Axis font size ''' def __init__(self, ctx, scores, evaluation, func_load): super(PlotBase, self).__init__(ctx, scores, evaluation, func_load) self._output = None if 'output' not in ctx.meta else ctx.meta['output'] - self._points = None if 'points' not in ctx.meta else ctx.meta['points'] + self._points = 100 if 'points' not in ctx.meta else ctx.meta['points'] self._split = None if 'split' not in ctx.meta else ctx.meta['split'] self._axlim = None if 'axlim' not in ctx.meta else ctx.meta['axlim'] self._clayout = None if 'clayout' not in ctx.meta else\ @@ -396,9 +333,8 @@ class PlotBase(MeasureBase): ctx.meta['show_fn'] self._x_rotation = None if 'x_rotation' not in ctx.meta else \ ctx.meta['x_rotation'] - self._axisfontsize = 6 if 'fontsize' not in ctx.meta else \ - ctx.meta['fontsize'] - + if 'style' in ctx.meta: + mpl.style.use(ctx.meta['style']) self._nb_figs = 2 if self._eval and self._split else 1 self._multi_plots = len(self.dev_scores) > 1 self._colors = utils.get_colors(len(self.dev_scores)) @@ -422,14 +358,11 @@ class PlotBase(MeasureBase): self._ctx.meta else PdfPages(self._output) for i in range(self._nb_figs): - fig = mpl.figure(i + 1) + fs = None if 'figsize' not in self._ctx.meta else\ + self._ctx.meta['figsize'] + fig = mpl.figure(i + 1, figsize=fs) + fig.set_constrained_layout(self._clayout) fig.clear() - if self._axisfontsize is not None: - mpl.rc('xtick', labelsize=self._axisfontsize) - mpl.rc('ytick', labelsize=self._axisfontsize) - mpl.rc('legend', fontsize=6) - mpl.rc('axes', labelsize=8) - #mpl.rcParams['figure.constrained_layout.use'] = self._clayout def end_process(self): ''' Set title, legend, axis labels, grid colors, save figures and @@ -449,8 +382,6 @@ class PlotBase(MeasureBase): mpl.grid(True, color=self._grid_color) mpl.legend(loc='best') self._set_axis() - #gives warning when applied with mpl - fig.set_tight_layout(True) mpl.xticks(rotation=self._x_rotation) self._pdf_page.savefig(fig) @@ -472,22 +403,9 @@ class PlotBase(MeasureBase): def _set_axis(self): if self._axlim is not None and None not in self._axlim: mpl.axis(self._axlim) - else: - mpl.axes().autoscale() class Roc(PlotBase): - ''' Handles the plotting of ROC - - Attributes - ---------- - - _semilogx: :obj:`bool` - If true, X-axis will be semilog10 - - _fmr_at: :obj:`float` - If not None, plot a vertical line at this value on the dev plot and - corresponding dots on the eval plot (if any). - ''' + ''' Handles the plotting of ROC''' def __init__(self, ctx, scores, evaluation, func_load): super(Roc, self).__init__(ctx, scores, evaluation, func_load) self._semilogx = True if 'semilogx' not in ctx.meta else\ @@ -588,7 +506,7 @@ class Det(PlotBase): linestyle = '-' if not self._split else LINESTYLES[idx % 14] plot.det( dev_neg, dev_pos, self._points, color=self._colors[idx], - linestyle=linestyle, axisfontsize=self._axisfontsize, + linestyle=linestyle, label=self._label('development', dev_file, idx, **self._kwargs) ) if self._split: @@ -596,13 +514,13 @@ class Det(PlotBase): linestyle = '--' if not self._split else LINESTYLES[idx % 14] plot.det( eval_neg, eval_pos, self._points, color=self._colors[idx], - linestyle=linestyle, axisfontsize=self._axisfontsize, + linestyle=linestyle, label=self._label('eval', eval_file, idx, **self._kwargs) ) else: plot.det( dev_neg, dev_pos, self._points, color=self._colors[idx], - linestyle=LINESTYLES[idx % 14], axisfontsize=self._axisfontsize, + linestyle=LINESTYLES[idx % 14], label=self._label('development', dev_file, idx, **self._kwargs) ) @@ -619,39 +537,26 @@ class Epc(PlotBase): if 'eval_scores_0' not in self._ctx.meta: raise click.UsageError("EPC requires dev and eval score files") self._title = self._title or 'EPC' - self._x_label = self._x_label or 'Cost' - self._y_label = self._y_label or 'Min. HTER (%)' + self._x_label = self._x_label or r'$\alpha$' + self._y_label = self._y_label or 'HTER (%)' self._eval = True #always eval data with EPC self._split = False self._nb_figs = 1 def compute(self, idx, dev_score, dev_file, eval_score, eval_file=None): - ''' Plot EPC using - :py:func:`bob.measure.plot.epc`''' + ''' Plot EPC using :py:func:`bob.measure.plot.epc` ''' dev_neg, dev_pos, _, eval_neg, eval_pos, _ =\ self._process_scores(dev_score, eval_score) plot.epc( dev_neg, dev_pos, eval_neg, eval_pos, self._points, color=self._colors[idx], linestyle=LINESTYLES[idx % 14], - label=self._label('curve', dev_file + "_" + eval_file, idx, **self._kwargs) + label=self._label( + 'curve', dev_file + "_" + eval_file, idx, **self._kwargs + ) ) class Hist(PlotBase): - ''' Functional base class for histograms - - Attributes - ---------- - - _nbins: :obj:`int`, str - Number of bins. Default: `auto` - - _thres: :any:`list` - If given, uses those threshold instead of computing them. Lenght of the - list must be the same as the number of systems. - - _criter: str - Criterion to compute threshold (eer or hter) - ''' + ''' Functional base class for histograms''' def __init__(self, ctx, scores, evaluation, func_load): super(Hist, self).__init__(ctx, scores, evaluation, func_load) self._nbins = None if 'nbins' not in ctx.meta else ctx.meta['nbins'] @@ -710,7 +615,6 @@ class Hist(PlotBase): if not self._show_dev: self._plot_legends() - fig.set_tight_layout(True) self._pdf_page.savefig(fig) def _get_title(self, idx, dev_file, eval_file): @@ -739,7 +643,6 @@ class Hist(PlotBase): mpl.legend(lines, labels, loc='best', fancybox=True, framealpha=0.5) - def _get_neg_pos_thres(self, idx, dev_score, eval_score): dev_neg, dev_pos, _, eval_neg, eval_pos, _ = self._process_scores( dev_score, eval_score @@ -752,7 +655,7 @@ class Hist(PlotBase): def _density_hist(self, scores, **kwargs): n, bins, patches = mpl.hist( - scores, normed=True, bins=self._nbins, **kwargs + scores, density=True, bins=self._nbins, **kwargs ) return (n, bins, patches) @@ -761,9 +664,8 @@ class Hist(PlotBase): kwargs.setdefault('color', 'C3') kwargs.setdefault('linestyle', '--') kwargs.setdefault('label', label) - _, _, ymax, ymin = mpl.axis() # plot a vertical threshold line - mpl.axvline(x=threshold, ymin=ymin, ymax=ymax, **kwargs) + mpl.axvline(x=threshold, ymin=0, ymax=1, **kwargs) def _setup_hist(self, neg, pos): ''' This function can be overwritten in derived classes''' diff --git a/bob/measure/script/gen.py b/bob/measure/script/gen.py index bab91956622de869d83a22002398f43bb8f63217..67d0ce42497f3e2189aee83999683aed09a6e7bc 100644 --- a/bob/measure/script/gen.py +++ b/bob/measure/script/gen.py @@ -16,11 +16,10 @@ NUM_NEG = 5000 NUM_POS = 5000 def gen_score_distr(mean_neg, mean_pos, sigma_neg=1, sigma_pos=1): - """Generate scores from normal distributions + """Generate scores from normal distributions Parameters ---------- - mean_neg : float Mean for negative scores mean_pos : float @@ -32,10 +31,9 @@ def gen_score_distr(mean_neg, mean_pos, sigma_neg=1, sigma_pos=1): Returns ------- - - neg_scores : array_like + neg_scores : :any:`list` Negatives scores - pos_scores : array_like + pos_scores : :any:`list` Positive scores """ mt = random.mt19937() # initialise the random number generator @@ -56,9 +54,9 @@ def write_scores_to_file(pos, neg, filename): Parameters ---------- - pos : array_like + pos : :py:class:`numpy.ndarray` Scores for positive samples. - neg : array_like + neg : :py:class:`numpy.ndarray` Scores for negative samples. filename : str The path to write the score to. diff --git a/bob/measure/script/measure.py b/bob/measure/script/measure.py index 7a4206eb4d1d40b930ff7b4656908b762b5a213d..eb2050e14cf8586783e23c23e7eeba9432fc5721 100644 --- a/bob/measure/script/measure.py +++ b/bob/measure/script/measure.py @@ -7,8 +7,8 @@ from click.types import INT, FLOAT, Choice, File @with_plugins(pkg_resources.iter_entry_points('bob.measure.cli')) -@click.group(chain=True) +@click.group() def measure(): - """Entry for bob.measure commands.""" + """Generic performance evaluation commands.""" pass diff --git a/bob/measure/utils.py b/bob/measure/utils.py index 9a42dbcb4ffba143a40156b852a2849278848278..cc7688a0b0306eef9486b4b03c2d3cac4b7db61c 100644 --- a/bob/measure/utils.py +++ b/bob/measure/utils.py @@ -2,7 +2,6 @@ import numpy import scipy.stats -import click import bob.core def remove_nan(scores): @@ -12,7 +11,6 @@ def remove_nan(scores): Parameters ---------- - scores : :py:class:`numpy.ndarray` : array @@ -37,7 +35,6 @@ def get_fta(scores): Parameters ---------- - scores : Tuple of (``positive``, ``negative``) :py:class:`numpy.ndarray`. @@ -61,7 +58,6 @@ def get_thres(criter, neg, pos, far=None): Parameters ---------- - criter : Criterion (`eer` or `hter`) neg : :py:class:`numpy.ndarray`: @@ -71,10 +67,8 @@ def get_thres(criter, neg, pos, far=None): Returns ------- - :py:obj:`float` threshold - """ if criter == 'eer': from . import eer_threshold @@ -84,13 +78,12 @@ def get_thres(criter, neg, pos, far=None): return min_hter_threshold(neg, pos) elif criter == 'far': if far is None: - raise click.UsageError("FAR value must be provided through " - "``--far-value`` option.") + raise ValueError("FAR value must be provided through " + "``--far-value`` option.") from . import far_threshold return far_threshold(neg, pos, far) - else: - raise click.UsageError("Incorrect plotting criterion: ``%s``" % criter) + raise ValueError("Incorrect plotting criterion: ``%s``" % criter) def get_colors(n): """get_colors @@ -98,13 +91,11 @@ def get_colors(n): Parameters ---------- - n : :obj:`int` Number of colors to output Returns ------- - :any:`list` list of colors """ diff --git a/doc/py_api.rst b/doc/py_api.rst index 4824df94aa8d774b5fbe57c480e6b8a6117e353f..1ad954d5a145319fcfc51d1e0ccc41d89b3e7847 100644 --- a/doc/py_api.rst +++ b/doc/py_api.rst @@ -127,3 +127,5 @@ Details .. automodule:: bob.measure.utils .. automodule:: bob.measure.script.figure .. automodule:: bob.measure.script.commands +.. automodule:: bob.measure.script.gen +.. automodule:: bob.measure.script.common_options