Home | History | Annotate | Download | only in tko
      1 # Copyright Martin J. Bligh (mbligh (at] google.com), 2007
      2 
      3 """
      4 Class to draw gnuplot graphs for autotest performance analysis.
      5 Not that generic - specifically designed to to draw graphs of one type,
      6 but probably adaptable.
      7 """
      8 
      9 import subprocess, sys, os
     10 from math import sqrt
     11 Popen = subprocess.Popen
     12 
     13 def avg_dev(values):
     14     if len(values) == 0:
     15         return (0,0)
     16     average = float(sum(values)) / len(values)
     17     sum_sq_dev = sum( [(x - average) ** 2 for x in values] )
     18     std_dev = sqrt(sum_sq_dev / float(len(values)));
     19     return (average, std_dev);
     20 
     21 
     22 class gnuplot:
     23     def __init__(self, title, xlabel, ylabel, xsort = sorted, size = "1180,900", keytitle = None):
     24         self.title = title
     25         self.xlabel = xlabel
     26         self.ylabel = ylabel
     27         self.data_titles = []
     28         self.datasets = []
     29         self.xsort = xsort
     30         self.xvalues = set([])
     31         self.size = size
     32         self.keytitle = keytitle
     33 
     34     def xtics(self):
     35         count = 1
     36         tics = []
     37         for label in self.xlabels:
     38             # prepend 2 blanks to work around gnuplot bug
     39             #  in placing X axis legend over X tic labels
     40             tics.append('"  %s" %d' % (label, count))
     41             count += 1
     42         return tics
     43 
     44 
     45     def add_dataset(self, title, labeled_values):
     46         """
     47         Add a data line
     48 
     49         title: title of the dataset
     50         labeled_values: dictionary of lists
     51                         { label : [value1, value2, ... ] , ... }
     52         """
     53         if not labeled_values:
     54             raise "plotgraph:add_dataset - dataset was empty! %s" %\
     55                                                             title
     56         self.data_titles.append(title)
     57         data_points = {}
     58         for label in labeled_values:
     59             point = "%s %s" % avg_dev(labeled_values[label])
     60             data_points[label] = point
     61             self.xvalues.add(label)
     62         self.datasets.append(data_points)
     63 
     64 
     65     def plot(self, cgi_header = False, output = None, test = None):
     66         if cgi_header:
     67             print "Content-type: image/png\n"
     68             sys.stdout.flush()
     69         if test:
     70             g = open(test, 'w')
     71         else:
     72             p = Popen("/usr/bin/gnuplot", stdin = subprocess.PIPE)
     73             g = p.stdin
     74         g.write('set terminal png size %s\n' % self.size)
     75         if self.keytitle:
     76             g.write('set key title "%s"\n' % self.keytitle)
     77             g.write('set key outside\n')  # outside right
     78         else:
     79             g.write('set key below\n')
     80         g.write('set title "%s"\n' % self.title)
     81         g.write('set xlabel "%s"\n' % self.xlabel)
     82         g.write('set ylabel "%s"\n' % self.ylabel)
     83         if output:
     84             g.write('set output "%s"\n' % output)
     85         g.write('set style data yerrorlines\n')
     86         g.write('set grid\n')
     87 
     88         self.xlabels = self.xsort(list(self.xvalues))
     89 
     90         g.write('set xrange [0.5:%f]\n' % (len(self.xvalues)+0.5))
     91         g.write('set xtics rotate (%s)\n' % ','.join(self.xtics()))
     92 
     93         plot_lines = ['"-" title "%s"' % t for t in self.data_titles]
     94         g.write('plot ' + ', '.join(plot_lines) + '\n')
     95 
     96         for dataset in self.datasets:
     97             count = 1
     98             for label in self.xlabels:
     99                 if label in dataset:
    100                     data = dataset[label]
    101                     g.write("%d %s\n" % (count, str(data)))
    102                 count += 1
    103             sys.stdout.flush()
    104             g.write('e\n')
    105 
    106         g.close()
    107         if not test:
    108             sts = os.waitpid(p.pid, 0)
    109