plot.py (4192B)
1 #!/usr/bin/env python3 2 # See LICENSE file for copyright and license details. 3 4 5 # Invoke using `env XKCD_STYLE=` to for more a comical plot style. 6 7 # Invoke using `env PER_BIT=` to divide all time values by the number 8 # of bits that where processed. This applies to 2-dimensional data only. 9 10 # Invoke using `env VIOLIN_STYLE=` to draw violin plots rather than 11 # box plots. This applies to multisample 1-dimensional data only. 12 # If used, used `env SHOW_MEAN=` will show that mean value in place 13 # of the median value. 14 15 # For multisample 1-dimensional, if `env VIOLIN_STYLE=` is not used 16 # `env NOTCH_STYLE=`, `env PATCH_ARTIST`, and `env SHOW_MEAN` may be 17 # applied. 18 19 20 import sys, os 21 import matplotlib.pyplot as plot 22 23 xkcdstyle = 'XKCD_STYLE' in os.environ 24 if xkcdstyle: 25 plot.xkcd() 26 fig = plot.figure() 27 28 xint = lambda x : (float(x) if '.' in x else int(x)) 29 30 multiple = 1 31 smultiple = '' 32 33 multiples = [1] * len(sys.argv[1:]) 34 smultiples = [''] * len(sys.argv[1:]) 35 paths = [None] * len(sys.argv[1:]) 36 37 i = 0 38 for arg in sys.argv[1:]: 39 if arg.startswith('*'): 40 multiples[i] = float(arg[1:]) 41 smultiples[i] = ' * ' + arg[1:] 42 else: 43 paths[i] = arg 44 i += 1 45 46 multiples = multiples[:i] 47 smultiples = smultiples[:i] 48 paths = paths[:i] 49 50 xpoints = [None] * i 51 ypoints = [None] * i 52 values = [None] * i 53 labels = [None] * i 54 55 for i, path in enumerate(paths): 56 with open(path, 'rb') as file: 57 lines = file.read() 58 lines = lines.decode('utf-8', 'strict').split('\n') 59 labels[i], dim, values[i] = lines[0] + smultiples[i], int(lines[1]), lines[2:] 60 if dim > 1: 61 xpoints[i], values[i] = values[i][0], values[i][1:] 62 xpoints[i] = [int(x) for x in xpoints[i].split(' ')] 63 xpoints[i][1] += 1 64 xpoints[i] = list(range(*xpoints[i])) 65 if dim > 2: 66 ypoints[i], values[i] = values[i][0], values[i][1:] 67 ypoints[i] = [int(x) for x in ypoints[i].split(' ')] 68 ypoints[i][1] += 1 69 ypoints[i] = list(range(*ypoints[i])) 70 values[i] = [xint(v) * multiples[i] for v in values[i] if v != ''] 71 if dim == 2: 72 if 'PER_BIT' in os.environ: 73 values[i] = [y / x for y, x in zip(values[i], xpoints[i])] 74 75 data = [[[i], (values[i], xpoints[i], ypoints[i])] for i in range(len(values))] 76 data.sort(key = lambda x : x[1]) 77 merged, data = [data[0]], data[1:] 78 for ([i], d) in data: 79 if d == merged[-1][1]: 80 merged[-1][0].append(i) 81 else: 82 merged.append(([i], d)) 83 84 xpoints = [xpoints[i[0]] for (i, _) in merged] 85 ypoints = [ypoints[i[0]] for (i, _) in merged] 86 values = [values[i[0]] for (i, _) in merged] 87 labels = [' & '.join(labels[j] for j in i) for (i, _) in merged] 88 89 vmin = min(min(min(v) for v in values), 0) 90 vmax = max(max(max(v) for v in values), 0) 91 92 if dim == 1: 93 plot.ylabel('time') 94 if len(values[0]) == 1: 95 plot.bar(range(len(values)), 96 [vs[0] for vs in values], 97 align = 'center', 98 orientation = 'vertical', 99 tick_label = labels) 100 labels = None 101 elif 'VIOLIN_STYLE' in os.environ: 102 plot.violinplot(values, 103 vert = True, 104 showmeans = 'SHOW_MEAN' in os.environ, 105 showmedians = 'SHOW_MEAN' not in os.environ, 106 showextrema = True) 107 else: 108 plot.boxplot(values, 109 vert = True, 110 notch = 'NOTCH_STYLE' in os.environ, 111 patch_artist = 'PATCH_ARTIST' in os.environ) 112 if 'SHOW_MEAN' in os.environ: 113 for i in range(len(values)): 114 mean = sum(values[i]) / len(values[i]) 115 plot.plot([i + 0.75, i + 1.25], [mean, mean]); 116 if labels is not None: 117 plot.setp(fig.axes, 118 xticks = [x + 1 for x in range(len(values))], 119 xticklabels = labels) 120 elif dim == 2: 121 for i in range(len(values)): 122 plot.plot(xpoints[i], values[i], label = labels[i]) 123 plot.legend(loc = 'best') 124 plot.xlabel('bits') 125 plot.ylabel('time') 126 elif dim == 3: 127 pass 128 129 plot.ylim((vmin * 1.1, vmax * 1.1)) 130 131 if not xkcdstyle: 132 plot.grid(True) 133 plot.show()