普通文本  |  109行  |  3.44 KB

# 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)