blob: ec87970d7548ad86417f515ebba6fe390488f80c [file] [log] [blame]
#!/usr/bin/env python
# Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
#
# Use of this source code is governed by a BSD-style license
# that can be found in the LICENSE file in the root of the source
# tree. An additional intellectual property rights grant can be found
# in the file PATENTS. All contributing project authors may
# be found in the AUTHORS file in the root of the source tree.
"""Shows boxplots of given score for different values of selected
parameters. Can be used to compare scores by audioproc_f flag.
Usage: apm_quality_assessment_boxplot.py -o /path/to/output
-v polqa
-n /path/to/dir/with/apm_configs
-z audioproc_f_arg1 [arg2 ...]
Arguments --config_names, --render_names, --echo_simulator_names,
--test_data_generators, --eval_scores can be used to filter the data
used for plotting.
"""
import collections
import logging
import matplotlib.pyplot as plt
import os
import quality_assessment.data_access as data_access
import quality_assessment.collect_data as collect_data
def InstanceArgumentsParser():
"""Arguments parser factory.
"""
parser = collect_data.InstanceArgumentsParser()
parser.description = (
'Shows boxplot of given score for different values of selected'
'parameters. Can be used to compare scores by audioproc_f flag')
parser.add_argument('-v', '--eval_score', required=True,
help=('Score name for constructing boxplots'))
parser.add_argument('-n', '--config_dir', required=False,
help=('path to the folder with the configuration files'),
default='apm_configs')
parser.add_argument('-z', '--params_to_plot', required=True,
nargs='+', help=('audioproc_f parameter values'
'by which to group scores (no leading dash)'))
return parser
def FilterScoresByParams(data_frame, filter_params, score_name, config_dir):
"""Filters data on the values of one or more parameters.
Args:
data_frame: pandas.DataFrame of all used input data.
filter_params: each config of the input data is assumed to have
exactly one parameter from `filter_params` defined. Every value
of the parameters in `filter_params` is a key in the returned
dict; the associated value is all cells of the data with that
value of the parameter.
score_name: Name of score which value is boxplotted. Currently cannot do
more than one value.
config_dir: path to dir with APM configs.
Returns: dictionary, key is a param value, result is all scores for
that param value (see `filter_params` for explanation).
"""
results = collections.defaultdict(dict)
config_names = data_frame['apm_config'].drop_duplicates().values.tolist()
for config_name in config_names:
config_json = data_access.AudioProcConfigFile.Load(
os.path.join(config_dir, config_name + '.json'))
data_with_config = data_frame[data_frame.apm_config == config_name]
data_cell_scores = data_with_config[data_with_config.eval_score_name ==
score_name]
# Exactly one of |params_to_plot| must match:
(matching_param, ) = [x for x in filter_params if '-' + x in config_json]
# Add scores for every track to the result.
for capture_name in data_cell_scores.capture:
result_score = float(data_cell_scores[data_cell_scores.capture ==
capture_name].score)
config_dict = results[config_json['-' + matching_param]]
if capture_name not in config_dict:
config_dict[capture_name] = {}
config_dict[capture_name][matching_param] = result_score
return results
def _FlattenToScoresList(config_param_score_dict):
"""Extracts a list of scores from input data structure.
Args:
config_param_score_dict: of the form {'capture_name':
{'param_name' : score_value,.. } ..}
Returns: Plain list of all score value present in input data
structure
"""
result = []
for capture_name in config_param_score_dict:
result += list(config_param_score_dict[capture_name].values())
return result
def main():
# Init.
# TODO(alessiob): INFO once debugged.
logging.basicConfig(level=logging.DEBUG)
parser = InstanceArgumentsParser()
args = parser.parse_args()
# Get the scores.
src_path = collect_data.ConstructSrcPath(args)
logging.debug(src_path)
scores_data_frame = collect_data.FindScores(src_path, args)
# Filter the data by `args.params_to_plot`
scores_filtered = FilterScoresByParams(scores_data_frame,
args.params_to_plot,
args.eval_score,
args.config_dir)
data_list = sorted(scores_filtered.items())
data_values = [_FlattenToScoresList(x) for (_, x) in data_list]
data_labels = [x for (x, _) in data_list]
_, axes = plt.subplots(nrows=1, ncols=1, figsize=(6, 6))
axes.boxplot(data_values, labels=data_labels)
axes.set_ylabel(args.eval_score)
axes.set_xlabel('/'.join(args.params_to_plot))
plt.show()
if __name__ == "__main__":
main()