aboutsummaryrefslogtreecommitdiffstats
path: root/plot_exps.py
diff options
context:
space:
mode:
Diffstat (limited to 'plot_exps.py')
-rwxr-xr-xplot_exps.py154
1 files changed, 58 insertions, 96 deletions
diff --git a/plot_exps.py b/plot_exps.py
index 39529bd..bb6a707 100755
--- a/plot_exps.py
+++ b/plot_exps.py
@@ -1,15 +1,16 @@
1#!/usr/bin/env python 1#!/usr/bin/env python
2from __future__ import print_function 2from __future__ import print_function
3 3
4import matplotlib.pyplot as plot
4import os 5import os
5import shutil as sh 6import shutil as sh
6import sys 7import sys
8from collections import namedtuple
7from optparse import OptionParser 9from optparse import OptionParser
10from parse.col_map import ColMap
8from parse.dir_map import DirMap 11from parse.dir_map import DirMap
9from parse.tuple_table import ReducedTupleTable 12from parse.tuple_table import ReducedTupleTable
10from parse.col_map import ColMap 13from plot.style import StyleMap
11from collections import namedtuple,defaultdict
12import matplotlib.pyplot as plot
13 14
14def parse_args(): 15def parse_args():
15 parser = OptionParser("usage: %prog [options] [csv_dir]...") 16 parser = OptionParser("usage: %prog [options] [csv_dir]...")
@@ -21,15 +22,16 @@ def parse_args():
21 22
22 return parser.parse_args() 23 return parser.parse_args()
23 24
24
25ExpDetails = namedtuple('ExpDetails', ['variable', 'value', 'title', 'out']) 25ExpDetails = namedtuple('ExpDetails', ['variable', 'value', 'title', 'out'])
26OUT_FORMAT = 'pdf' 26OUT_FORMAT = 'pdf'
27 27
28def get_details(path): 28def get_details(path, out_dir):
29 '''Decode a @path into details about a single experiment.'''
29 out = "_".join(path) if path else "plot" 30 out = "_".join(path) if path else "plot"
31 out = "%s/%s.%s" % (out_dir, out, OUT_FORMAT)
30 32
31 value = path.pop() if path else None 33 value = path.pop(0) if path else None
32 variable = path.pop() if path else None 34 variable = path.pop(0) if path else None
33 35
34 title = value.capitalize() if value else "" 36 title = value.capitalize() if value else ""
35 title += " by %s" % variable if variable else "" 37 title += " by %s" % variable if variable else ""
@@ -37,105 +39,70 @@ def get_details(path):
37 39
38 return ExpDetails(variable, value, title, out) 40 return ExpDetails(variable, value, title, out)
39 41
42def plot_by_variable(plot_node, col_map, details):
43 '''Plot each .csv files under @plot_node as a line on a shared plot.'''
40 44
45 # Generate mapping of (column)=>(line property to vary) for consistently
46 # formatted plots
47 columns = list(col_map.columns())
48 if details.variable and details.variable in columns:
49 columns.remove(details.variable)
50 style_map = StyleMap(columns, col_map.get_values())
41 51
42class StyleMap(object): 52 figure = plot.figure()
43 COLORS = list('bgrcmyk') 53 axes = figure.add_subplot(111)
44 LINES = ['-', ':', '--']
45 MARKERS = list('.,ov^<>1234sp*hH+xDd|_')
46 ORDER = [MARKERS, COLORS, LINES]
47 DEFAULT = ["k", "-", "k"]
48
49 def __init__(self, col_list, col_values):
50 self.prop_map = dict(zip(col_list, StyleMap.ORDER))
51
52 # Store 1 style per value
53 self.value_map = defaultdict(dict)
54 for column, styles in self.prop_map.iteritems():
55 value_styles = self.value_map[column]
56 for value in sorted(col_values[column]):
57 value_styles[value] = styles.pop(0)
58 styles += [value_styles[value]]
59
60 def get_style(self, kv):
61 style = ''
62 for k,v in kv.iteritems():
63 if k in self.value_map:
64 style += self.value_map[k][v]
65 return style
66
67 def get_key(self):
68 key = []
69 for column, properties in self.prop_map.iteritems():
70 idx = StyleMap.ORDER.index(properties)
71 prop_string = StyleMap.DEFAULT[idx] + "%s"
72 for value, prop in self.value_map[column].iteritems():
73 style = plot.plot([],[], prop_string%prop)[0]
74 key += [(style, "%s:%s" % (column, value))]
75 return sorted(key, key=lambda x:x[1])
76
77def plot_by_variable(dir_map, col_map, out_dir, force):
78 num_plots = 0
79 id = 0
80 for _,_ in dir_map.leafs(1):
81 num_plots += 1
82 sys.stderr.write("Plotting by variable...")
83
84 for plot_path, plot_node in dir_map.leafs(1):
85 id += 1
86 details = get_details(plot_path)
87 out_fname = "%s/%s.%s" % (out_dir, details.out, OUT_FORMAT)
88 if os.path.exists(out_fname) and not force:
89 continue
90
91 # Kinda bad...
92 first_csv = plot_node.children.keys()[0]
93 first_config = ColMap.decode(first_csv[:first_csv.index('.csv')])
94 columns = filter(lambda c: c in first_config, col_map.columns())
95
96 style_map = StyleMap(columns, col_map.get_values())
97
98 figure = plot.figure()
99 axes = figure.add_subplot(111)
100 54
101 for line_path, line_node in plot_node.children.iteritems(): 55 # Create a line for each file node
102 encoded = line_path[:line_path.index(".csv")] 56 for line_path, line_node in plot_node.children.iteritems():
103 config = ColMap.decode(encoded) 57 # Create line style to match this configuration
104 style = style_map.get_style(config) 58 encoded = line_path[:line_path.index(".csv")]
59 config = ColMap.decode(encoded)
60 style = style_map.get_style(config)
105 61
106 values = sorted(line_node.values, key=lambda tup: tup[0]) 62 values = sorted(line_node.values, key=lambda tup: tup[0])
107 xvalues, yvalues = zip(*values) 63 xvalues, yvalues = zip(*values)
108 64
109 plot.plot(xvalues, yvalues, style) 65 plot.plot(xvalues, yvalues, style.fmt())
110 66
111 lines, labels = zip(*style_map.get_key()) 67 axes.set_title(details.title)
112 68
113 axes.legend(tuple(lines), tuple(labels), prop={'size':10}) 69 lines, labels = zip(*style_map.get_key())
114 axes.set_ylabel(details.value) 70 axes.legend(tuple(lines), tuple(labels), prop={'size':10})
115 axes.set_xlabel(details.variable)
116 axes.set_xlim(0, axes.get_xlim()[1] + 1)
117 axes.set_ylim(0, axes.get_ylim()[1] + 1)
118 71
119 axes.set_title(details.title) 72 axes.set_ylabel(details.value)
73 axes.set_xlabel(details.variable)
74 axes.set_xlim(0, axes.get_xlim()[1] + 1)
75 axes.set_ylim(0, axes.get_ylim()[1] + 1)
120 76
121 plot.savefig(out_fname, format=OUT_FORMAT) 77 plot.savefig(details.out, format=OUT_FORMAT)
122 78
123 sys.stderr.write('\r {0:.2%}'.format(float(id)/num_plots)) 79def plot_dir(data_dir, out_dir, force):
124 sys.stderr.write('\n') 80 sys.stderr.write("Reading data...\n")
125
126def plot_exp(data_dir, out_dir, force):
127 print("Reading data...")
128 dir_map = DirMap.read(data_dir) 81 dir_map = DirMap.read(data_dir)
129 print("Sorting configs...") 82
83 sys.stderr.write("Creating column map...\n")
130 tuple_table = ReducedTupleTable.from_dir_map(dir_map) 84 tuple_table = ReducedTupleTable.from_dir_map(dir_map)
131 col_map = tuple_table.get_col_map() 85 col_map = tuple_table.get_col_map()
132 86
133 if not os.path.exists(out_dir): 87 if not os.path.exists(out_dir):
134 os.mkdir(out_dir) 88 os.mkdir(out_dir)
135 89
136 print("Plotting data...") 90 sys.stderr.write("Plotting...\n")
137 plot_by_variable(dir_map, col_map, out_dir, force) 91
138 # plot_by_config(tuple_table, out_dir) 92 # Count total plots for % counter
93 num_plots = len([x for x in dir_map.leafs(1)])
94 plot_num = 0
95
96 for plot_path, plot_node in dir_map.leafs(1):
97 details = get_details(plot_path, out_dir)
98
99 if force or not os.path.exists(details.out):
100 plot_by_variable(plot_node, col_map, details)
101
102 plot_num += 1
103
104 sys.stderr.write('\r {0:.2%}'.format(float(plot_num)/num_plots))
105 sys.stderr.write('\n')
139 106
140def main(): 107def main():
141 opts, args = parse_args() 108 opts, args = parse_args()
@@ -146,13 +113,8 @@ def main():
146 if not os.path.exists(opts.out_dir): 113 if not os.path.exists(opts.out_dir):
147 os.mkdir(opts.out_dir) 114 os.mkdir(opts.out_dir)
148 115
149 for exp in args: 116 for dir in args:
150 name = os.path.split(exp)[1] 117 plot_dir(dir, opts.out_dir, opts.force)
151 if exp != os.getcwd():
152 out_dir = "%s/%s" % (opts.out_dir, name)
153 else:
154 out_dir = os.getcwd()
155 plot_exp(exp, out_dir, opts.force)
156 118
157if __name__ == '__main__': 119if __name__ == '__main__':
158 main() 120 main()