diff options
-rwxr-xr-x | vplot.py | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/vplot.py b/vplot.py new file mode 100755 index 0000000..71344c6 --- /dev/null +++ b/vplot.py | |||
@@ -0,0 +1,156 @@ | |||
1 | #!/usr/bin/env python | ||
2 | import defapp | ||
3 | |||
4 | from plot import decode | ||
5 | from util import load_csv_file, write_csv_file | ||
6 | |||
7 | from math import ceil | ||
8 | |||
9 | from numpy import amin, amax, mean, median, std, histogram | ||
10 | |||
11 | from os.path import splitext, basename | ||
12 | from optparse import make_option as o | ||
13 | |||
14 | from gnuplot import gnuplot, FORMATS, Plot, label, curve | ||
15 | |||
16 | options = [ | ||
17 | # output options | ||
18 | o('-f', '--format', action='store', dest='format', type='choice', | ||
19 | choices=FORMATS, help='output format'), | ||
20 | o(None, '--save-script', action='store_true', dest='save_script'), | ||
21 | o('-p', '--prefix', action='store', dest='prefix'), | ||
22 | |||
23 | # formatting options | ||
24 | # These may or may not be supported by a particular experiment plotter. | ||
25 | o(None, '--smooth', action='store_true', dest='smooth'), | ||
26 | ] | ||
27 | |||
28 | defaults = { | ||
29 | # output options | ||
30 | 'format' : 'pdf', | ||
31 | 'save_script' : False, | ||
32 | 'prefix' : '', | ||
33 | |||
34 | # formatting options | ||
35 | 'alternate' : False, | ||
36 | } | ||
37 | |||
38 | |||
39 | class VideoPlotter(defapp.App): | ||
40 | def __init__(self): | ||
41 | defapp.App.__init__(self, options, defaults, no_std_opts=True) | ||
42 | self.tmpfiles = [] | ||
43 | |||
44 | def make_plot(self, fname=None): | ||
45 | p = Plot() | ||
46 | p.output = "%s%s.%s" % (self.options.prefix, fname, self.options.format) | ||
47 | p.format = self.options.format | ||
48 | return p | ||
49 | |||
50 | def setup_png(self, plot): | ||
51 | # standard png options; usually correct; never tweaked for paper | ||
52 | if self.options.format == 'png': | ||
53 | plot.font_size = 'large' | ||
54 | plot.size = (1024, 768) | ||
55 | plot.xticks = (0, 1) | ||
56 | plot.yticks = (0, 0.1) | ||
57 | plot.default_style = "linespoints" | ||
58 | return True | ||
59 | else: | ||
60 | return False | ||
61 | |||
62 | def load(self, datafile, name): | ||
63 | data = load_csv_file(datafile) | ||
64 | # make a copy without comments, etc. | ||
65 | if self.options.save_script: | ||
66 | fname = "%s.data" % name | ||
67 | write_csv_file(fname, data) | ||
68 | return (data, fname) | ||
69 | else: | ||
70 | tmp = write_csv_file(None, data) | ||
71 | # keep a reference so that it isn't deleted | ||
72 | self.tmpfiles.append(tmp) | ||
73 | return (data, tmp.name) | ||
74 | |||
75 | def render(self, p): | ||
76 | if self.options.save_script: | ||
77 | p.gnuplot_save(p.output + '.plot') | ||
78 | else: | ||
79 | p.gnuplot_exec() | ||
80 | |||
81 | def plot_vdecode(self, datafile, name, conf): | ||
82 | (data, fname) = self.load(datafile, name) | ||
83 | |||
84 | decode_times = data[:,0] | ||
85 | |||
86 | avg = mean(decode_times) | ||
87 | med = median(decode_times) | ||
88 | dev = std(decode_times) | ||
89 | max = amax(decode_times) | ||
90 | min = amin(decode_times) | ||
91 | |||
92 | stats_label = "min=%.2fms max=%.2fms avg=%.2fms median=%.2fms std=%.2fms" \ | ||
93 | % (min, max, avg, med, dev) | ||
94 | |||
95 | p = self.make_plot(name) | ||
96 | |||
97 | p.title = "raw decoding cost; input=%s; host=%s" \ | ||
98 | % (conf['file'], conf['host']) | ||
99 | |||
100 | p.ylabel = "decoding cost (ms)" | ||
101 | p.xlabel = "frame number" | ||
102 | p.xrange = (0, len(data)) | ||
103 | #p.xticks = (0, 100) | ||
104 | p.yticks = (0, 1) | ||
105 | p.yrange = (0, ceil(max)) | ||
106 | |||
107 | p.curves = [curve(fname=fname, xcol=2, ycol=1, title="decoding cost")] | ||
108 | p.labels = [label(0.5, 0.9, stats_label, coord=['graph', 'screen'], align='center')] | ||
109 | |||
110 | #### Styling. | ||
111 | |||
112 | if not self.setup_png(p): | ||
113 | p.rounded_caps = True | ||
114 | p.font = 'Helvetica' | ||
115 | |||
116 | p.font_size = '10' | ||
117 | p.size = ('20cm', '10cm') | ||
118 | p.monochrome = False | ||
119 | p.dashed_lines = False | ||
120 | p.key = 'off' | ||
121 | p.default_style = 'points lw 1' | ||
122 | |||
123 | if self.options.smooth: | ||
124 | p.default_style += " smooth bezier" | ||
125 | |||
126 | self.render(p) | ||
127 | |||
128 | |||
129 | def plot_file(self, datafile): | ||
130 | bname = basename(datafile) | ||
131 | name, ext = splitext(bname) | ||
132 | conf = decode(name) | ||
133 | plotters = { | ||
134 | 'vdecode' : self.plot_vdecode, | ||
135 | } | ||
136 | |||
137 | for plot_type in plotters: | ||
138 | if plot_type in conf: | ||
139 | try: | ||
140 | plotters[plot_type](datafile, name, conf) | ||
141 | except IOError as err: | ||
142 | self.err("Skipped '%s' (%s)." % err) | ||
143 | break | ||
144 | else: | ||
145 | self.err("Skipped '%s'; unkown experiment type." | ||
146 | % bname) | ||
147 | # release all tmp files | ||
148 | self.tmpfiles = [] | ||
149 | |||
150 | def default(self, _): | ||
151 | for i, datafile in enumerate(self.args): | ||
152 | self.out("[%d/%d] Processing %s ..." % (i + 1, len(self.args), datafile)) | ||
153 | self.plot_file(datafile) | ||
154 | |||
155 | if __name__ == "__main__": | ||
156 | VideoPlotter().launch() | ||