# Copyright Martin J. Bligh (mbligh@google.com), 2007 """ Class to draw gnuplot graphs for autotest performance analysis. Not that generic - specifically designed to to draw graphs of one type, but probably adaptable. """ import subprocess, sys, os from math import sqrt Popen = subprocess.Popen def avg_dev(values): if len(values) == 0: return (0,0) average = float(sum(values)) / len(values) sum_sq_dev = sum( [(x - average) ** 2 for x in values] ) std_dev = sqrt(sum_sq_dev / float(len(values))); return (average, std_dev); class gnuplot: def __init__(self, title, xlabel, ylabel, xsort = sorted, size = "1180,900", keytitle = None): self.title = title self.xlabel = xlabel self.ylabel = ylabel self.data_titles = [] self.datasets = [] self.xsort = xsort self.xvalues = set([]) self.size = size self.keytitle = keytitle def xtics(self): count = 1 tics = [] for label in self.xlabels: # prepend 2 blanks to work around gnuplot bug # in placing X axis legend over X tic labels tics.append('" %s" %d' % (label, count)) count += 1 return tics def add_dataset(self, title, labeled_values): """ Add a data line title: title of the dataset labeled_values: dictionary of lists { label : [value1, value2, ... ] , ... } """ if not labeled_values: raise "plotgraph:add_dataset - dataset was empty! %s" %\ title self.data_titles.append(title) data_points = {} for label in labeled_values: point = "%s %s" % avg_dev(labeled_values[label]) data_points[label] = point self.xvalues.add(label) self.datasets.append(data_points) def plot(self, cgi_header = False, output = None, test = None): if cgi_header: print "Content-type: image/png\n" sys.stdout.flush() if test: g = open(test, 'w') else: p = Popen("/usr/bin/gnuplot", stdin = subprocess.PIPE) g = p.stdin g.write('set terminal png size %s\n' % self.size) if self.keytitle: g.write('set key title "%s"\n' % self.keytitle) g.write('set key outside\n') # outside right else: g.write('set key below\n') g.write('set title "%s"\n' % self.title) g.write('set xlabel "%s"\n' % self.xlabel) g.write('set ylabel "%s"\n' % self.ylabel) if output: g.write('set output "%s"\n' % output) g.write('set style data yerrorlines\n') g.write('set grid\n') self.xlabels = self.xsort(list(self.xvalues)) g.write('set xrange [0.5:%f]\n' % (len(self.xvalues)+0.5)) g.write('set xtics rotate (%s)\n' % ','.join(self.xtics())) plot_lines = ['"-" title "%s"' % t for t in self.data_titles] g.write('plot ' + ', '.join(plot_lines) + '\n') for dataset in self.datasets: count = 1 for label in self.xlabels: if label in dataset: data = dataset[label] g.write("%d %s\n" % (count, str(data))) count += 1 sys.stdout.flush() g.write('e\n') g.close() if not test: sts = os.waitpid(p.pid, 0)