1 # Copyright (c) 2018 Cisco and/or its affiliates.
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at:
6 # http://www.apache.org/licenses/LICENSE-2.0
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
14 """Algorithms to generate plots.
20 import plotly.offline as ploff
21 import plotly.graph_objs as plgo
23 from plotly.exceptions import PlotlyError
25 from utils import mean
28 def generate_plots(spec, data):
29 """Generate all plots specified in the specification file.
31 :param spec: Specification read from the specification file.
32 :param data: Data to process.
33 :type spec: Specification
37 logging.info("Generating the plots ...")
38 for index, plot in enumerate(spec.plots):
40 logging.info(" Plot nr {0}:".format(index + 1))
41 eval(plot["algorithm"])(plot, data)
43 logging.error("The algorithm '{0}' is not defined.".
44 format(plot["algorithm"]))
48 def plot_performance_box(plot, input_data):
49 """Generate the plot(s) with algorithm: plot_performance_box
50 specified in the specification file.
52 :param plot: Plot to generate.
53 :param input_data: Data to process.
54 :type plot: pandas.Series
55 :type input_data: InputData
58 logging.info(" Generating the plot {0} ...".
59 format(plot.get("title", "")))
62 logging.info(" Creating the data set for the {0} '{1}'.".
63 format(plot.get("type", ""), plot.get("title", "")))
64 data = input_data.filter_data(plot)
66 logging.error("No data.")
69 # Prepare the data for the plot
74 if y_vals.get(test["parent"], None) is None:
75 y_vals[test["parent"]] = list()
77 y_vals[test["parent"]].append(test["throughput"]["value"])
78 except (KeyError, TypeError):
79 y_vals[test["parent"]].append(None)
81 # Add None to the lists with missing data
83 for val in y_vals.values():
84 if len(val) > max_len:
86 for key, val in y_vals.items():
87 if len(val) < max_len:
88 val.extend([None for _ in range(max_len - len(val))])
92 df = pd.DataFrame(y_vals)
94 for i, col in enumerate(df.columns):
95 name = "{0}. {1}".format(i + 1, col.lower().replace('-ndrpdrdisc', ''))
96 traces.append(plgo.Box(x=[str(i + 1) + '.'] * len(df[col]),
103 plpl = plgo.Figure(data=traces, layout=plot["layout"])
106 logging.info(" Writing file '{0}{1}'.".
107 format(plot["output-file"], plot["output-file-type"]))
109 show_link=False, auto_open=False,
110 filename='{0}{1}'.format(plot["output-file"],
111 plot["output-file-type"]))
112 except PlotlyError as err:
113 logging.error(" Finished with error: {}".
114 format(str(err).replace("\n", " ")))
117 logging.info(" Done.")
120 def plot_latency_box(plot, input_data):
121 """Generate the plot(s) with algorithm: plot_latency_box
122 specified in the specification file.
124 :param plot: Plot to generate.
125 :param input_data: Data to process.
126 :type plot: pandas.Series
127 :type input_data: InputData
130 logging.info(" Generating the plot {0} ...".
131 format(plot.get("title", "")))
134 logging.info(" Creating the data set for the {0} '{1}'.".
135 format(plot.get("type", ""), plot.get("title", "")))
136 data = input_data.filter_data(plot)
138 logging.error("No data.")
141 # Prepare the data for the plot
146 if y_tmp_vals.get(test["parent"], None) is None:
147 y_tmp_vals[test["parent"]] = [
148 list(), # direction1, min
149 list(), # direction1, avg
150 list(), # direction1, max
151 list(), # direction2, min
152 list(), # direction2, avg
153 list() # direction2, max
156 y_tmp_vals[test["parent"]][0].append(
157 test["latency"]["direction1"]["50"]["min"])
158 y_tmp_vals[test["parent"]][1].append(
159 test["latency"]["direction1"]["50"]["avg"])
160 y_tmp_vals[test["parent"]][2].append(
161 test["latency"]["direction1"]["50"]["max"])
162 y_tmp_vals[test["parent"]][3].append(
163 test["latency"]["direction2"]["50"]["min"])
164 y_tmp_vals[test["parent"]][4].append(
165 test["latency"]["direction2"]["50"]["avg"])
166 y_tmp_vals[test["parent"]][5].append(
167 test["latency"]["direction2"]["50"]["max"])
168 except (KeyError, TypeError):
172 for key, values in y_tmp_vals.items():
179 y_vals[key].append(average)
180 y_vals[key].append(average) # Twice for plot.ly
185 df = pd.DataFrame(y_vals)
187 except ValueError as err:
188 logging.error(" Finished with error: {}".
189 format(str(err).replace("\n", " ")))
192 for i, col in enumerate(df.columns):
193 name = "{0}. {1}".format(i + 1, col.lower().replace('-ndrpdrdisc', ''))
194 traces.append(plgo.Box(x=['TGint1-to-SUT1-to-SUT2-to-TGint2',
195 'TGint1-to-SUT1-to-SUT2-to-TGint2',
196 'TGint1-to-SUT1-to-SUT2-to-TGint2',
197 'TGint1-to-SUT1-to-SUT2-to-TGint2',
198 'TGint1-to-SUT1-to-SUT2-to-TGint2',
199 'TGint1-to-SUT1-to-SUT2-to-TGint2',
200 'TGint2-to-SUT2-to-SUT1-to-TGint1',
201 'TGint2-to-SUT2-to-SUT1-to-TGint1',
202 'TGint2-to-SUT2-to-SUT1-to-TGint1',
203 'TGint2-to-SUT2-to-SUT1-to-TGint1',
204 'TGint2-to-SUT2-to-SUT1-to-TGint1',
205 'TGint2-to-SUT2-to-SUT1-to-TGint1'],
212 logging.info(" Writing file '{0}{1}'.".
213 format(plot["output-file"], plot["output-file-type"]))
214 plpl = plgo.Figure(data=traces, layout=plot["layout"])
218 show_link=False, auto_open=False,
219 filename='{0}{1}'.format(plot["output-file"],
220 plot["output-file-type"]))
221 except PlotlyError as err:
222 logging.error(" Finished with error: {}".
223 format(str(err).replace("\n", " ")))
226 logging.info(" Done.")
229 def plot_throughput_speedup_analysis(plot, input_data):
230 """Generate the plot(s) with algorithm: plot_throughput_speedup_analysis
231 specified in the specification file.
233 :param plot: Plot to generate.
234 :param input_data: Data to process.
235 :type plot: pandas.Series
236 :type input_data: InputData
239 logging.info(" Generating the plot {0} ...".
240 format(plot.get("title", "")))
243 logging.info(" Creating the data set for the {0} '{1}'.".
244 format(plot.get("type", ""), plot.get("title", "")))
245 data = input_data.filter_data(plot)
247 logging.error("No data.")
254 if throughput.get(test["parent"], None) is None:
255 throughput[test["parent"]] = {"1": list(),
259 if "1T1C" in test["tags"]:
260 throughput[test["parent"]]["1"].\
261 append(test["throughput"]["value"])
262 elif "2T2C" in test["tags"]:
263 throughput[test["parent"]]["2"]. \
264 append(test["throughput"]["value"])
265 elif "4T4C" in test["tags"]:
266 throughput[test["parent"]]["4"]. \
267 append(test["throughput"]["value"])
268 except (KeyError, TypeError):
272 logging.warning("No data for the plot '{}'".
273 format(plot.get("title", "")))
276 for test_name, test_vals in throughput.items():
277 for key, test_val in test_vals.items():
279 throughput[test_name][key] = sum(test_val) / len(test_val)
281 names = ['1 core', '2 cores', '4 cores']
287 for test_name, test_vals in throughput.items():
289 x_vals.append("-".join(test_name.split('-')[1:-1]))
293 round(float(test_vals["2"]) / float(test_vals["1"]), 2))
295 y_vals_2.append(None)
298 round(float(test_vals["4"]) / float(test_vals["1"]), 2))
300 y_vals_4.append(None)
302 y_vals = [y_vals_1, y_vals_2, y_vals_4]
304 y_vals_zipped = zip(names, y_vals)
306 for val in y_vals_zipped:
307 traces.append(plgo.Bar(x=x_vals,
313 logging.info(" Writing file '{0}{1}'.".
314 format(plot["output-file"], plot["output-file-type"]))
315 plpl = plgo.Figure(data=traces, layout=plot["layout"])
319 show_link=False, auto_open=False,
320 filename='{0}{1}'.format(plot["output-file"],
321 plot["output-file-type"]))
322 except PlotlyError as err:
323 logging.error(" Finished with error: {}".
324 format(str(err).replace("\n", " ")))
327 logging.info(" Done.")
330 def plot_http_server_performance_box(plot, input_data):
331 """Generate the plot(s) with algorithm: plot_http_server_performance_box
332 specified in the specification file.
334 :param plot: Plot to generate.
335 :param input_data: Data to process.
336 :type plot: pandas.Series
337 :type input_data: InputData
340 logging.info(" Generating the plot {0} ...".
341 format(plot.get("title", "")))
344 logging.info(" Creating the data set for the {0} '{1}'.".
345 format(plot.get("type", ""), plot.get("title", "")))
346 data = input_data.filter_data(plot)
348 logging.error("No data.")
351 # Prepare the data for the plot
356 if y_vals.get(test["name"], None) is None:
357 y_vals[test["name"]] = list()
359 y_vals[test["name"]].append(test["result"]["value"])
360 except (KeyError, TypeError):
361 y_vals[test["name"]].append(None)
363 # Add None to the lists with missing data
365 for val in y_vals.values():
366 if len(val) > max_len:
368 for key, val in y_vals.items():
369 if len(val) < max_len:
370 val.extend([None for _ in range(max_len - len(val))])
374 df = pd.DataFrame(y_vals)
376 for i, col in enumerate(df.columns):
377 name = "{0}. {1}".format(i + 1, col.lower().replace('-cps', '').
379 traces.append(plgo.Box(x=[str(i + 1) + '.'] * len(df[col]),
385 plpl = plgo.Figure(data=traces, layout=plot["layout"])
388 logging.info(" Writing file '{0}{1}'.".
389 format(plot["output-file"], plot["output-file-type"]))
391 show_link=False, auto_open=False,
392 filename='{0}{1}'.format(plot["output-file"],
393 plot["output-file-type"]))
394 except PlotlyError as err:
395 logging.error(" Finished with error: {}".
396 format(str(err).replace("\n", " ")))
399 logging.info(" Done.")