json2graph.py 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. #!/usr/bin/env python
  2. '''
  3. Use matplotlib to generate performance charts
  4. Copyright 2011 Joel Martin
  5. Licensed under MPL-2.0 (see docs/LICENSE.MPL-2.0)
  6. '''
  7. # a bar plot with errorbars
  8. import sys, json, pprint
  9. import numpy as np
  10. import matplotlib.pyplot as plt
  11. from matplotlib.font_manager import FontProperties
  12. def usage():
  13. print "%s json_file level1 level2 level3 [legend_height]\n\n" % sys.argv[0]
  14. print "Description:\n"
  15. print "level1, level2, and level3 are one each of the following:\n";
  16. print " select=ITEM - select only ITEM at this level";
  17. print " bar - each item on this level becomes a graph bar";
  18. print " group - items on this level become groups of bars";
  19. print "\n";
  20. print "json_file is a file containing json data in the following format:\n"
  21. print ' {';
  22. print ' "conf": {';
  23. print ' "order_l1": [';
  24. print ' "level1_label1",';
  25. print ' "level1_label2",';
  26. print ' ...';
  27. print ' ],';
  28. print ' "order_l2": [';
  29. print ' "level2_label1",';
  30. print ' "level2_label2",';
  31. print ' ...';
  32. print ' ],';
  33. print ' "order_l3": [';
  34. print ' "level3_label1",';
  35. print ' "level3_label2",';
  36. print ' ...';
  37. print ' ]';
  38. print ' },';
  39. print ' "stats": {';
  40. print ' "level1_label1": {';
  41. print ' "level2_label1": {';
  42. print ' "level3_label1": [val1, val2, val3],';
  43. print ' "level3_label2": [val1, val2, val3],';
  44. print ' ...';
  45. print ' },';
  46. print ' "level2_label2": {';
  47. print ' ...';
  48. print ' },';
  49. print ' },';
  50. print ' "level1_label2": {';
  51. print ' ...';
  52. print ' },';
  53. print ' ...';
  54. print ' },';
  55. print ' }';
  56. sys.exit(2)
  57. def error(msg):
  58. print msg
  59. sys.exit(1)
  60. #colors = ['#ff0000', '#0863e9', '#00f200', '#ffa100',
  61. # '#800000', '#805100', '#013075', '#007900']
  62. colors = ['#ff0000', '#00ff00', '#0000ff',
  63. '#dddd00', '#dd00dd', '#00dddd',
  64. '#dd6622', '#dd2266', '#66dd22',
  65. '#8844dd', '#44dd88', '#4488dd']
  66. if len(sys.argv) < 5:
  67. usage()
  68. filename = sys.argv[1]
  69. L1 = sys.argv[2]
  70. L2 = sys.argv[3]
  71. L3 = sys.argv[4]
  72. if len(sys.argv) > 5:
  73. legendHeight = float(sys.argv[5])
  74. else:
  75. legendHeight = 0.75
  76. # Load the JSON data from the file
  77. data = json.loads(file(filename).read())
  78. conf = data['conf']
  79. stats = data['stats']
  80. # Sanity check data hierarchy
  81. if len(conf['order_l1']) != len(stats.keys()):
  82. error("conf.order_l1 does not match stats level 1")
  83. for l1 in stats.keys():
  84. if len(conf['order_l2']) != len(stats[l1].keys()):
  85. error("conf.order_l2 does not match stats level 2 for %s" % l1)
  86. if conf['order_l1'].count(l1) < 1:
  87. error("%s not found in conf.order_l1" % l1)
  88. for l2 in stats[l1].keys():
  89. if len(conf['order_l3']) != len(stats[l1][l2].keys()):
  90. error("conf.order_l3 does not match stats level 3")
  91. if conf['order_l2'].count(l2) < 1:
  92. error("%s not found in conf.order_l2" % l2)
  93. for l3 in stats[l1][l2].keys():
  94. if conf['order_l3'].count(l3) < 1:
  95. error("%s not found in conf.order_l3" % l3)
  96. #
  97. # Generate the data based on the level specifications
  98. #
  99. bar_labels = None
  100. group_labels = None
  101. bar_vals = []
  102. bar_sdvs = []
  103. if L3.startswith("select="):
  104. select_label = l3 = L3.split("=")[1]
  105. bar_labels = conf['order_l1']
  106. group_labels = conf['order_l2']
  107. bar_vals = [[0]*len(group_labels) for i in bar_labels]
  108. bar_sdvs = [[0]*len(group_labels) for i in bar_labels]
  109. for b in range(len(bar_labels)):
  110. l1 = bar_labels[b]
  111. for g in range(len(group_labels)):
  112. l2 = group_labels[g]
  113. bar_vals[b][g] = np.mean(stats[l1][l2][l3])
  114. bar_sdvs[b][g] = np.std(stats[l1][l2][l3])
  115. elif L2.startswith("select="):
  116. select_label = l2 = L2.split("=")[1]
  117. bar_labels = conf['order_l1']
  118. group_labels = conf['order_l3']
  119. bar_vals = [[0]*len(group_labels) for i in bar_labels]
  120. bar_sdvs = [[0]*len(group_labels) for i in bar_labels]
  121. for b in range(len(bar_labels)):
  122. l1 = bar_labels[b]
  123. for g in range(len(group_labels)):
  124. l3 = group_labels[g]
  125. bar_vals[b][g] = np.mean(stats[l1][l2][l3])
  126. bar_sdvs[b][g] = np.std(stats[l1][l2][l3])
  127. elif L1.startswith("select="):
  128. select_label = l1 = L1.split("=")[1]
  129. bar_labels = conf['order_l2']
  130. group_labels = conf['order_l3']
  131. bar_vals = [[0]*len(group_labels) for i in bar_labels]
  132. bar_sdvs = [[0]*len(group_labels) for i in bar_labels]
  133. for b in range(len(bar_labels)):
  134. l2 = bar_labels[b]
  135. for g in range(len(group_labels)):
  136. l3 = group_labels[g]
  137. bar_vals[b][g] = np.mean(stats[l1][l2][l3])
  138. bar_sdvs[b][g] = np.std(stats[l1][l2][l3])
  139. else:
  140. usage()
  141. # If group is before bar then flip (zip) the data
  142. if [L1, L2, L3].index("group") < [L1, L2, L3].index("bar"):
  143. bar_labels, group_labels = group_labels, bar_labels
  144. bar_vals = zip(*bar_vals)
  145. bar_sdvs = zip(*bar_sdvs)
  146. print "bar_vals:", bar_vals
  147. #
  148. # Now render the bar graph
  149. #
  150. ind = np.arange(len(group_labels)) # the x locations for the groups
  151. width = 0.8 * (1.0/len(bar_labels)) # the width of the bars
  152. fig = plt.figure(figsize=(10,6), dpi=80)
  153. plot = fig.add_subplot(1, 1, 1)
  154. rects = []
  155. for i in range(len(bar_vals)):
  156. rects.append(plot.bar(ind+width*i, bar_vals[i], width, color=colors[i],
  157. yerr=bar_sdvs[i], align='center'))
  158. # add some
  159. plot.set_ylabel('Milliseconds (less is better)')
  160. plot.set_title("Javascript array test: %s" % select_label)
  161. plot.set_xticks(ind+width)
  162. plot.set_xticklabels( group_labels )
  163. fontP = FontProperties()
  164. fontP.set_size('small')
  165. plot.legend( [r[0] for r in rects], bar_labels, prop=fontP,
  166. loc = 'center right', bbox_to_anchor = (1.0, legendHeight))
  167. def autolabel(rects):
  168. # attach some text labels
  169. for rect in rects:
  170. height = rect.get_height()
  171. if np.isnan(height):
  172. height = 0.0
  173. plot.text(rect.get_x()+rect.get_width()/2., height+20, '%d'%int(height),
  174. ha='center', va='bottom', size='7')
  175. for rect in rects:
  176. autolabel(rect)
  177. # Adjust axis sizes
  178. axis = list(plot.axis())
  179. axis[0] = -width # Make sure left side has enough for bar
  180. #axis[1] = axis[1] * 1.20 # Add 20% to the right to make sure it fits
  181. axis[2] = 0 # Make y-axis start at 0
  182. axis[3] = axis[3] * 1.10 # Add 10% to the top
  183. plot.axis(axis)
  184. plt.show()