* Change copyright header This updates the copyright header to say "The noVNC Authors". People who previously had copyright listings are now under the AUTHORS file.
207 lines
6.5 KiB
Python
Executable File
207 lines
6.5 KiB
Python
Executable File
#!/usr/bin/env python
|
|
|
|
'''
|
|
Use matplotlib to generate performance charts
|
|
Copyright (C) 2018 The noVNC Authors
|
|
Licensed under MPL-2.0 (see docs/LICENSE.MPL-2.0)
|
|
'''
|
|
|
|
# a bar plot with errorbars
|
|
import sys, json
|
|
import numpy as np
|
|
import matplotlib.pyplot as plt
|
|
from matplotlib.font_manager import FontProperties
|
|
|
|
def usage():
|
|
print "%s json_file level1 level2 level3 [legend_height]\n\n" % sys.argv[0]
|
|
print "Description:\n"
|
|
print "level1, level2, and level3 are one each of the following:\n";
|
|
print " select=ITEM - select only ITEM at this level";
|
|
print " bar - each item on this level becomes a graph bar";
|
|
print " group - items on this level become groups of bars";
|
|
print "\n";
|
|
print "json_file is a file containing json data in the following format:\n"
|
|
print ' {';
|
|
print ' "conf": {';
|
|
print ' "order_l1": [';
|
|
print ' "level1_label1",';
|
|
print ' "level1_label2",';
|
|
print ' ...';
|
|
print ' ],';
|
|
print ' "order_l2": [';
|
|
print ' "level2_label1",';
|
|
print ' "level2_label2",';
|
|
print ' ...';
|
|
print ' ],';
|
|
print ' "order_l3": [';
|
|
print ' "level3_label1",';
|
|
print ' "level3_label2",';
|
|
print ' ...';
|
|
print ' ]';
|
|
print ' },';
|
|
print ' "stats": {';
|
|
print ' "level1_label1": {';
|
|
print ' "level2_label1": {';
|
|
print ' "level3_label1": [val1, val2, val3],';
|
|
print ' "level3_label2": [val1, val2, val3],';
|
|
print ' ...';
|
|
print ' },';
|
|
print ' "level2_label2": {';
|
|
print ' ...';
|
|
print ' },';
|
|
print ' },';
|
|
print ' "level1_label2": {';
|
|
print ' ...';
|
|
print ' },';
|
|
print ' ...';
|
|
print ' },';
|
|
print ' }';
|
|
sys.exit(2)
|
|
|
|
def error(msg):
|
|
print msg
|
|
sys.exit(1)
|
|
|
|
|
|
#colors = ['#ff0000', '#0863e9', '#00f200', '#ffa100',
|
|
# '#800000', '#805100', '#013075', '#007900']
|
|
colors = ['#ff0000', '#00ff00', '#0000ff',
|
|
'#dddd00', '#dd00dd', '#00dddd',
|
|
'#dd6622', '#dd2266', '#66dd22',
|
|
'#8844dd', '#44dd88', '#4488dd']
|
|
|
|
if len(sys.argv) < 5:
|
|
usage()
|
|
|
|
filename = sys.argv[1]
|
|
L1 = sys.argv[2]
|
|
L2 = sys.argv[3]
|
|
L3 = sys.argv[4]
|
|
if len(sys.argv) > 5:
|
|
legendHeight = float(sys.argv[5])
|
|
else:
|
|
legendHeight = 0.75
|
|
|
|
# Load the JSON data from the file
|
|
data = json.loads(file(filename).read())
|
|
conf = data['conf']
|
|
stats = data['stats']
|
|
|
|
# Sanity check data hierarchy
|
|
if len(conf['order_l1']) != len(stats.keys()):
|
|
error("conf.order_l1 does not match stats level 1")
|
|
for l1 in stats.keys():
|
|
if len(conf['order_l2']) != len(stats[l1].keys()):
|
|
error("conf.order_l2 does not match stats level 2 for %s" % l1)
|
|
if conf['order_l1'].count(l1) < 1:
|
|
error("%s not found in conf.order_l1" % l1)
|
|
for l2 in stats[l1].keys():
|
|
if len(conf['order_l3']) != len(stats[l1][l2].keys()):
|
|
error("conf.order_l3 does not match stats level 3")
|
|
if conf['order_l2'].count(l2) < 1:
|
|
error("%s not found in conf.order_l2" % l2)
|
|
for l3 in stats[l1][l2].keys():
|
|
if conf['order_l3'].count(l3) < 1:
|
|
error("%s not found in conf.order_l3" % l3)
|
|
|
|
#
|
|
# Generate the data based on the level specifications
|
|
#
|
|
bar_labels = None
|
|
group_labels = None
|
|
bar_vals = []
|
|
bar_sdvs = []
|
|
if L3.startswith("select="):
|
|
select_label = l3 = L3.split("=")[1]
|
|
bar_labels = conf['order_l1']
|
|
group_labels = conf['order_l2']
|
|
bar_vals = [[0]*len(group_labels) for i in bar_labels]
|
|
bar_sdvs = [[0]*len(group_labels) for i in bar_labels]
|
|
for b in range(len(bar_labels)):
|
|
l1 = bar_labels[b]
|
|
for g in range(len(group_labels)):
|
|
l2 = group_labels[g]
|
|
bar_vals[b][g] = np.mean(stats[l1][l2][l3])
|
|
bar_sdvs[b][g] = np.std(stats[l1][l2][l3])
|
|
elif L2.startswith("select="):
|
|
select_label = l2 = L2.split("=")[1]
|
|
bar_labels = conf['order_l1']
|
|
group_labels = conf['order_l3']
|
|
bar_vals = [[0]*len(group_labels) for i in bar_labels]
|
|
bar_sdvs = [[0]*len(group_labels) for i in bar_labels]
|
|
for b in range(len(bar_labels)):
|
|
l1 = bar_labels[b]
|
|
for g in range(len(group_labels)):
|
|
l3 = group_labels[g]
|
|
bar_vals[b][g] = np.mean(stats[l1][l2][l3])
|
|
bar_sdvs[b][g] = np.std(stats[l1][l2][l3])
|
|
elif L1.startswith("select="):
|
|
select_label = l1 = L1.split("=")[1]
|
|
bar_labels = conf['order_l2']
|
|
group_labels = conf['order_l3']
|
|
bar_vals = [[0]*len(group_labels) for i in bar_labels]
|
|
bar_sdvs = [[0]*len(group_labels) for i in bar_labels]
|
|
for b in range(len(bar_labels)):
|
|
l2 = bar_labels[b]
|
|
for g in range(len(group_labels)):
|
|
l3 = group_labels[g]
|
|
bar_vals[b][g] = np.mean(stats[l1][l2][l3])
|
|
bar_sdvs[b][g] = np.std(stats[l1][l2][l3])
|
|
else:
|
|
usage()
|
|
|
|
# If group is before bar then flip (zip) the data
|
|
if [L1, L2, L3].index("group") < [L1, L2, L3].index("bar"):
|
|
bar_labels, group_labels = group_labels, bar_labels
|
|
bar_vals = zip(*bar_vals)
|
|
bar_sdvs = zip(*bar_sdvs)
|
|
|
|
print "bar_vals:", bar_vals
|
|
|
|
#
|
|
# Now render the bar graph
|
|
#
|
|
ind = np.arange(len(group_labels)) # the x locations for the groups
|
|
width = 0.8 * (1.0/len(bar_labels)) # the width of the bars
|
|
|
|
fig = plt.figure(figsize=(10,6), dpi=80)
|
|
plot = fig.add_subplot(1, 1, 1)
|
|
|
|
rects = []
|
|
for i in range(len(bar_vals)):
|
|
rects.append(plot.bar(ind+width*i, bar_vals[i], width, color=colors[i],
|
|
yerr=bar_sdvs[i], align='center'))
|
|
|
|
# add some
|
|
plot.set_ylabel('Milliseconds (less is better)')
|
|
plot.set_title("Javascript array test: %s" % select_label)
|
|
plot.set_xticks(ind+width)
|
|
plot.set_xticklabels( group_labels )
|
|
|
|
fontP = FontProperties()
|
|
fontP.set_size('small')
|
|
plot.legend( [r[0] for r in rects], bar_labels, prop=fontP,
|
|
loc = 'center right', bbox_to_anchor = (1.0, legendHeight))
|
|
|
|
def autolabel(rects):
|
|
# attach some text labels
|
|
for rect in rects:
|
|
height = rect.get_height()
|
|
if np.isnan(height):
|
|
height = 0.0
|
|
plot.text(rect.get_x()+rect.get_width()/2., height+20, '%d'%int(height),
|
|
ha='center', va='bottom', size='7')
|
|
|
|
for rect in rects:
|
|
autolabel(rect)
|
|
|
|
# Adjust axis sizes
|
|
axis = list(plot.axis())
|
|
axis[0] = -width # Make sure left side has enough for bar
|
|
#axis[1] = axis[1] * 1.20 # Add 20% to the right to make sure it fits
|
|
axis[2] = 0 # Make y-axis start at 0
|
|
axis[3] = axis[3] * 1.10 # Add 10% to the top
|
|
plot.axis(axis)
|
|
|
|
plt.show()
|