#!/usr/bin/env python import defapp from plot import decode from util import load_csv_file, write_csv_file from math import ceil from numpy import amin, amax, mean, median, std, histogram, zeros from os.path import splitext, basename from optparse import make_option as o from gnuplot import gnuplot, FORMATS, Plot, label, curve options = [ # output options o('-f', '--format', action='store', dest='format', type='choice', choices=FORMATS, help='output format'), o(None, '--save-script', action='store_true', dest='save_script'), o('-p', '--prefix', action='store', dest='prefix'), # formatting options # These may or may not be supported by a particular experiment plotter. o(None, '--smooth', action='store_true', dest='smooth'), o(None, '--hist', action='store_true', dest='histogram'), ] defaults = { # output options 'format' : 'pdf', 'save_script' : False, 'prefix' : '', # formatting options 'histogram' : False, 'smooth' : False, 'binsize' : 0.1, } def get_stats_label(samples): avg = mean(samples) med = median(samples) dev = std(samples) max = amax(samples) min = amin(samples) return "min=%.2fms max=%.2fms avg=%.2fms median=%.2fms std=%.2fms" \ % (min, max, avg, med, dev) class VideoPlotter(defapp.App): def __init__(self): defapp.App.__init__(self, options, defaults, no_std_opts=True) self.tmpfiles = [] def make_plot(self, fname=None): p = Plot() p.output = "%s%s.%s" % (self.options.prefix, fname, self.options.format) p.format = self.options.format return p def setup_png(self, plot): # standard png options; usually correct; never tweaked for paper if self.options.format == 'png': plot.font_size = 'large' plot.size = (1024, 768) plot.xticks = (0, 1) plot.yticks = (0, 0.1) plot.default_style = "linespoints" return True else: return False def write(self, data, name, ext='data'): if self.options.save_script: fname = "%s.%s" % (name, ext) write_csv_file(fname, data) return fname else: tmp = write_csv_file(None, data) # keep a reference so that it isn't deleted self.tmpfiles.append(tmp) return tmp.name def load(self, datafile, name): data = load_csv_file(datafile) # make a copy without comments, etc. return (data, self.write(data, name)) def write_histogram(self, samples, name, labels=10): max = ceil(amax(samples)) bin_size = self.options.binsize num_bins = int(max / bin_size) (bins, edges) = histogram(samples, bins=num_bins, range=(self.options.binsize / 2, max + self.options.binsize / 2)) data = zeros((num_bins, 3)) cumulative = 0 for i in xrange(len(bins)): data[i, 0] = (edges[i] + edges[i + 1]) / 2.0 data[i, 1] = bins[i] cumulative += bins[i] data[i, 2] = cumulative label_rate = len(bins) / labels for_file = [] for i, row in enumerate(data): label = '%.2f' % row[0] if i % label_rate == 0 else '' for_file.append([row[0], row[1], row[2], label]) return (data, self.write(for_file, name, ext='hist')) def render(self, p): if self.options.save_script: p.gnuplot_save(p.output + '.plot') else: p.gnuplot_exec() def plot_vdecode(self, datafile, name, conf): (data, fname) = self.load(datafile, name) max_cost = amax(data[:,0]) if self.options.histogram: name += '_hist' p = self.make_plot(name) p.labels = [label(0.5, 0.9, get_stats_label(data[:,0]), coord=['graph', 'screen'], align='center')] if self.options.histogram: (data, fname) = self.write_histogram(data[:,0], name) p.setup_histogram(gap=1, boxwidth=1.0) p.title = "decoding costs; input=%s; host=%s" \ % (conf['file'], conf['host']) p.ylabel = "number of frames" p.xlabel = "decoding cost in milliseconds (bin size = %.2fms)" \ % self.options.binsize # p.xrange = (0, ceil(max_cost)) p.xticks = (0, 10) # p.yticks = (0, 1) p.yrange = (0, (ceil(amax(data[:,1]) / 100) * 100)) p.curves = [curve(histogram=fname, col=2, labels_col=4)] else: # plot raw samples p.title = "raw decoding cost; input=%s; host=%s" \ % (conf['file'], conf['host']) p.ylabel = "decoding cost (ms)" p.xlabel = "frame number" p.xrange = (0, len(data)) #p.xticks = (0, 100) p.yticks = (0, 1) p.yrange = (0, ceil(max_cost)) p.curves = [curve(fname=fname, xcol=2, ycol=1, title="decoding cost")] #### Styling. if not self.setup_png(p): p.rounded_caps = True p.font = 'Helvetica' p.font_size = '10' p.size = ('20cm', '10cm') p.monochrome = False p.dashed_lines = False p.key = 'off' p.default_style = 'points lw 1' if self.options.smooth: p.default_style += " smooth bezier" self.render(p) def plot_file(self, datafile): bname = basename(datafile) name, ext = splitext(bname) conf = decode(name) plotters = { 'vdecode' : self.plot_vdecode, } for plot_type in plotters: if plot_type in conf: try: plotters[plot_type](datafile, name, conf) except IOError as err: self.err("Skipped '%s' (%s)." % err) break else: self.err("Skipped '%s'; unkown experiment type." % bname) # release all tmp files self.tmpfiles = [] def default(self, _): for i, datafile in enumerate(self.args): self.out("[%d/%d] Processing %s ..." % (i + 1, len(self.args), datafile)) self.plot_file(datafile) if __name__ == "__main__": VideoPlotter().launch()