intracom-telecom-sdn/nstat

View on GitHub
util/plot_json.py

Summary

Maintainability
F
3 days
Test Coverage
File `plot_json.py` has 318 lines of code (exceeds 250 allowed). Consider refactoring.
# Copyright (c) 2015 Intracom S.A. Telecom Solutions. All rights reserved.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License v1.0 which accompanies this distribution,
# and is available at http://www.eclipse.org/legal/epl-v10.html
 
"""Methods that implement plotting functionality in NSTAT"""
 
import util.plot_utils
import util.stats
 
 
Cyclomatic complexity is too high in function plot_json. (7)
Function `plot_json` has 7 arguments (exceeds 4 allowed). Consider refactoring.
Function `plot_json` has a Cognitive Complexity of 7 (exceeds 5 allowed). Consider refactoring.
def plot_json(results_file, x_axis_key, y_axis_key, z_axis_key, plot_type,
plot_subtitle_keys, plot_options):
"""
Acts as a wrapper method for plotting a set of samples from a \
JSON file. The method ends up calling specific methods for one of the \
following plot types: errorbar plots, scatter plots \
Prerequisites: \
1. the result JSON file must have the following format: \
[ \
{"k1": v1, "k2": v2, ... }, # 1st line (sample) \
{"k1": v3, "k2": v4, ... }, # 2nd line (sample) \
{"k1": v5, "k2": v6, ... }, # ... \
... \
] \
2. the values for both the x_axis_key and y_axis_key must be numeric
 
:param results_file: results file to plot samples from
:param x_axis_key: some key from the results file with numeric type \
value, which is intended to serve as the x-axis key
:param y_axis_key: some key from the result file with numeric type value, \
which is intended to serve as the y-axis key
:param z_axis_key: some key from the result file with numeric type value, \
which is intended to serve as the z-axis key
:param plot_type: plot type, one of: \
- 'errorbar \
- 'errorbar_connected' \
- 'scatter' \
- 'multi_errorbar \
- 'multi_errorbar_connected' \
- 'multi_scatter' \
:param plot_subtitle_keys: list of keys from the result file which we \
would like to print as key-value pairs in the plot subtitle \
:param plot_options: object containing configuration parameters of the \
produced plot.
:raises ValueError: When we give an invalid plot_type.
:type results_file: str
:type x_axis_key: str
:type y_axis_key: str
:type z_axis_key: str
:type plot_type: str
:type plot_subtitle_keys: list<str>
:type plot_options: PlotOptions
"""
 
if plot_type == 'errorbar':
plot_errorbar_json(results_file, x_axis_key, y_axis_key,
plot_subtitle_keys, plot_options)
elif plot_type == 'errorbar_connected':
plot_options.fmt = '-o'
plot_errorbar_json(results_file, x_axis_key, y_axis_key,
plot_subtitle_keys, plot_options)
elif plot_type == 'multi_errorbar':
multiplot_errorbar_json(results_file, x_axis_key, y_axis_key,
z_axis_key, plot_subtitle_keys, plot_options)
elif plot_type == 'multi_errorbar_connected':
plot_options.fmt = '-o'
multiplot_errorbar_json(results_file, x_axis_key, y_axis_key,
z_axis_key, plot_subtitle_keys, plot_options)
elif plot_type == 'scatter':
plot_scatter_json(results_file, x_axis_key, y_axis_key,
plot_subtitle_keys, plot_options)
elif plot_type == 'multi_scatter':
multiplot_scatter_json(results_file, x_axis_key, y_axis_key,
z_axis_key, plot_subtitle_keys, plot_options)
else:
raise ValueError('Unknown plot type:' + plot_type)
 
 
Function `plot_errorbar_json` has 5 arguments (exceeds 4 allowed). Consider refactoring.
def plot_errorbar_json(results_file, x_axis_key, y_axis_key,
plot_subtitle_keys, plot_options):
"""
Draw a single collection of errorbars over a set of samples from a JSON \
file. \
For each different x value, the function finds one or more \
corresponding y values and plots an errorbar over them. \
The x and y values are determined by the x_axis_key and y_axis_key \
arguments. \
Prerequisites: \
1. the result JSON file must have the following format: \
[ \
{"k1": v1, "k2": v2, ... }, # 1st line (sample) \
{"k1": v3, "k2": v4, ... }, # 2nd line (sample) \
{"k1": v5, "k2": v6, ... }, # ... \
... \
] \
2. the values for both the x_axis_key and y_axis_key must be numeric
 
:param results_file: results file to plot samples from
:param x_axis_key: some key from the results file with numeric type value, \
which is intended to serve as the x-axis key
:param y_axis_key: some key from the result file with numeric type value, \
which is intended to serve as the y-axis key
:param plot_subtitle_keys: list of keys from the result file which we \
would like to print as key-value pairs in the plot subtitle
:param plot_options: object containing configuration parameters of the \
produced plot.
:type results_file: str
:type x_axis_key: str
:type y_axis_key: str
:type z_axis_key: str
:type plot_type: str
:type plot_subtitle_keys: list<str>
:type plot_options: PlotOptions
"""
 
# Dictionary that maps a x_axis_key value to one or more y_axis_key values
lines, y_values = util.plot_utils.create_xy_dict_from_file(results_file,
x_axis_key,
y_axis_key)
 
# Create plot title
subtitle = ''
for sub_key in plot_subtitle_keys:
value = lines[0][sub_key]
 
# If key value is a list, convert it to a single
# string consisting of its elements
if isinstance(value, list):
curr_string = ' '.join(map(str, value))
else:
curr_string = str(value)
subtitle += sub_key + ':' + curr_string + ', '
 
plot_options.subtitle = subtitle
# Compute mean and +/- diff values
y_mean = []
y_diff_plus = []
y_diff_minus = []
x_keys_sorted = sorted(y_values.keys())
 
for key in x_keys_sorted:
mean = util.stats.mean(y_values[key])
diff_plus = plot_options.y_axis_fct * (max(y_values[key]) - mean)
diff_minus = plot_options.y_axis_fct * (mean - min(y_values[key]))
y_mean.append(mean)
y_diff_plus.append(diff_plus)
y_diff_minus.append(diff_minus)
 
# Plot
util.plot_utils.plot_errorbar(x_keys_sorted, y_mean, y_diff_minus,
y_diff_plus, plot_options)
 
 
Function `multiplot_errorbar_json` has 6 arguments (exceeds 4 allowed). Consider refactoring.
Similar blocks of code found in 2 locations. Consider refactoring.
def multiplot_errorbar_json(results_file, x_axis_key, y_axis_key, z_axis_key,
plot_subtitle_keys, plot_options):
"""
Draw multiple collection of errorbars over a set of samples from a \
JSON file. \
For each different z value do the following: \
for each different x value, the function finds one or more \
corresponding y values and plots an errorbar over them. \
The x and y values are determined by the x_axis_key and y_axis_key \
arguments. \
The z value is determined by the z_axis_key argument. \
Prerequisites: \
1. the result JSON file must have the following format: \
[ \
{"k1": v1, "k2": v2, ... }, # 1st line (sample) \
{"k1": v3, "k2": v4, ... }, # 2nd line (sample) \
{"k1": v5, "k2": v6, ... }, # ... \
... \
] \
2. the values for x_axis_key, y_axis_key and z_axis_key must be numeric
 
:param results_file: results file to plot samples from
:param x_axis_key: some key from the results file with numeric type \
value, which is intended to serve as the x-axis key
:param y_axis_key: some key from the result file with numeric type value, \
which is intended to serve as the y-axis key
:param z_axis_key: some key from the result file with numeric type value, \
which is intended to serve as the z-axis key
:param plot_subtitle_keys: list of keys from the result file which we \
would like to print as key-value pairs in the plot subtitle
:param plot_options: object containing configuration parameters of the \
produced plot.
:type results_file: str
:type x_axis_key: str
:type y_axis_key: str
:type z_axis_key: str
:type plot_type: str
:type plot_subtitle_keys: list<str>
:type plot_options: PlotOptions
"""
 
lines, y_values = util.plot_utils.create_xyz_dict_from_file(results_file,
x_axis_key,
y_axis_key,
z_axis_key)
 
# Create plot title
subtitle = ''
 
for sub_key in plot_subtitle_keys:
value = lines[0][sub_key]
# if key value is a list, convert it to a single
# string consisting of its elements
if isinstance(value, list):
curr_string = ' '.join(map(str, value))
else:
curr_string = str(value)
subtitle += sub_key + ':' + curr_string + ', '
 
# Plot
plot_options.subtitle = subtitle
util.plot_utils.plot_multi_errorbar(y_values, z_axis_key, plot_options)
 
 
Function `plot_scatter_json` has 5 arguments (exceeds 4 allowed). Consider refactoring.
Function `plot_scatter_json` has a Cognitive Complexity of 7 (exceeds 5 allowed). Consider refactoring.
def plot_scatter_json(results_file, x_axis_key, y_axis_key, plot_subtitle_keys,
plot_options):
"""
Draw a single scatter-plot over a set of samples from a JSON file. \
For each different x value, the function plots a point for every \
corresponding y values it finds. \
The x and y values are determined by the x_axis_key and y_axis_key \
arguments. \
Prerequisites: \
1. the result JSON file must have the following format: \
[ \
{"k1": v1, "k2": v2, ... }, # 1st line (sample) \
{"k1": v3, "k2": v4, ... }, # 2nd line (sample) \
{"k1": v5, "k2": v6, ... }, # ... \
... \
] \
2. the values for both the x_axis_key and y_axis_key must be numeric
 
:param results_file: results file to plot samples from
:param x_axis_key: some key from the results file with numeric type \
value, which is intended to serve as the x-axis key
:param y_axis_key: some key from the result file with numeric type value, \
which is intended to serve as the y-axis key
:param plot_title: description for the plot title
:param plot_subtitle_keys: list of keys from the result file which we \
would like to print as key-value pairs in the plot subtitle
:param plot_options: object containing configuration parameters of the \
produced plot.
:type results_file: str
:type x_axis_key: str
:type y_axis_key: str
:type z_axis_key: str
:type plot_type: str
:type plot_subtitle_keys: list<str>
:type plot_options: PlotOptions
"""
 
# Dictionary that maps a x_axis_key value to one or more y_axis_key values
lines, y_values = util.plot_utils.create_xy_dict_from_file(results_file,
x_axis_key,
y_axis_key)
 
# Create plot title
subtitle = ''
 
for sub_key in plot_subtitle_keys:
value = lines[0][sub_key]
 
# if key value is a list, convert it to a single
# string consisting of its elements
if isinstance(value, list):
curr_string = ' '.join(map(str, value))
else:
curr_string = str(value)
subtitle += sub_key + ':' + curr_string + ', '
 
plot_options.subtitle = subtitle
x_coords = []
y_coords = []
for key in y_values:
for val in y_values[key]:
x_coords.append(key)
y_coords.append(val)
 
# Plot
util.plot_utils.plot_scatter(x_coords, y_coords, plot_options)
 
 
Function `multiplot_scatter_json` has 6 arguments (exceeds 4 allowed). Consider refactoring.
Similar blocks of code found in 2 locations. Consider refactoring.
def multiplot_scatter_json(results_file, x_axis_key, y_axis_key, z_axis_key,
plot_subtitle_keys, plot_options):
"""
Draw multiple scatter-plots over a set of samples from a JSON file. \
Each scatter-plot is determined by a specific value of the z_axis_key \
For each different z value do the following: \
for each different x value, plot a point for every corresponding y \
value found. \
The x and y values are determined by the x_axis_key and y_axis_key \
arguments. \
The z value is determined by the z_axis_key argument. \
Prerequisites: \
1. the result JSON file must have the following format: \
[ \
{"k1": v1, "k2": v2, ... }, # 1st line (sample) \
{"k1": v3, "k2": v4, ... }, # 2nd line (sample) \
{"k1": v5, "k2": v6, ... }, # ... \
... \
] \
2. the values for x_axis_key, y_axis_key and z_axis_key must be \
numeric
 
:param results_file: results file to plot samples from
:param x_axis_key: some key from the results file with numeric type \
value, which is intended to serve as the x-axis key
:param y_axis_key: some key from the result file with numeric type value, \
which is intended to serve as the y-axis key
:param z_axis_key: some key from the result file with numeric type value, \
which is intended to serve as the z-axis key
:param plot_subtitle_keys: list of keys from the result file which we \
would like to print as key-value pairs in the plot subtitle
:param plot_options: object containing configuration parameters of the \
produced plot.
:type results_file: str
:type x_axis_key: str
:type y_axis_key: str
:type z_axis_key: str
:type plot_type: str
:type plot_subtitle_keys: list<str>
:type plot_options: PlotOptions
"""
 
lines, y_values = util.plot_utils.create_xyz_dict_from_file(results_file,
x_axis_key,
y_axis_key,
z_axis_key)
 
# Create plot title
subtitle = ''
 
for sub_key in plot_subtitle_keys:
value = lines[0][sub_key]
 
# if key value is a list, convert it to a single
# string consisting of its elements
if isinstance(value, list):
curr_string = ' '.join(map(str, value))
else:
curr_string = str(value)
subtitle += sub_key + ':' + curr_string + ', '
 
plot_options.subtitle = subtitle
# Plot
util.plot_utils.plot_multi_scatter(y_values, z_axis_key, plot_options)
 
# This is for self testing.
def self_test():
"""
Function used for self testing purposes
"""
plot_options_arg = util.plot_utils.PlotOptions()
plot_options_arg.x_axis_label = 'Number of switches'
plot_options_arg.y_axis_label = 'Throughput (flows/sec)'
plot_options_arg.plot_title = 'Controller throughput'
plot_options_arg.out_fig = 'errorbar.png'
plot_options_arg.ymin = 0
 
 
plot_subtitle_keys = ['java_opts', 'controller']
 
plot_json('./sample_result_file.json', 'switches', 'throughput', None,
'errorbar', plot_subtitle_keys, plot_options_arg)
 
plot_options_arg.out_fig = 'errorbar_connected.png'
plot_json('./sample_result_file.json', 'switches', 'throughput', None,
'errorbar_connected', plot_subtitle_keys, plot_options_arg)
 
plot_options_arg.out_fig = 'scatter.png'
plot_json('./sample_result_file.json', 'switches', 'throughput', None,
'scatter', plot_subtitle_keys, plot_options_arg)
 
plot_options_arg.out_fig = 'multi_scatter.png'
plot_json('./sample_result_file.json', 'switches', 'throughput', 'hosts',
'multi_scatter', plot_subtitle_keys, plot_options_arg)
 
plot_options_arg.out_fig = 'multi_errorbar.png'
plot_json('./sample_result_file.json', 'switches', 'throughput', 'hosts',
'multi_errorbar', plot_subtitle_keys, plot_options_arg)
 
plot_options_arg.out_fig = 'multi_errorbar_connected.png'
 
plot_json('./sample_result_file.json', 'switches', 'throughput', 'hosts',
'multi_errorbar_connected', plot_subtitle_keys, plot_options_arg)
# This is for self testing.
if __name__ == '__main__':
self_test()