def plot_by_variable(details): '''Plot each .csv files under @plot_node as a line on a shared plot.''' builder = ColMapBuilder() config_nodes = [] # Decode file names into configuration dicts for line_path, line_node in details.node.children.iteritems(): encoded = line_path[:line_path.index(".csv")] try: line_config = ColMap.decode(encoded) except: line_config = {'name': encoded} for k, v in line_config.iteritems(): builder.try_add(k, v) config_nodes += [(line_config, line_node)] col_map = builder.build() style_map = make_styler(col_map) figure = plot.figure() axes = figure.add_subplot(111) # Create a line for each file node and its configuration for line_config, line_node in config_nodes: style = style_map.get_style(line_config) values = sorted(line_node.values, key=lambda tup: tup[0]) xvalues, yvalues = zip(*values) plot.plot(xvalues, yvalues, style.fmt()) axes.set_title(details.title) lines, labels = zip(*style_map.get_key()) axes.legend( tuple(lines), tuple(labels), prop={'size': 10}, # This code places the legend slightly to the right of the plot bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.0) axes.set_ylabel(details.value) axes.set_xlabel(details.variable) axes.set_xlim(0, axes.get_xlim()[1]) axes.set_ylim(0, axes.get_ylim()[1]) plot.savefig( details.out, format=OUT_FORMAT, # Using 'tight' causes savefig to rescale the image for non-plot # artists, which in our case is just the legend bbox_inches='tight') return True
def main(): opts, args = parse_args() exp_dirs = get_dirs(args) # Load experiment parameters into a ColMap builder = ColMapBuilder() exps = load_exps(exp_dirs, builder, opts.force) # Don't track changes in ignored parameters if opts.ignore: for param in opts.ignore.split(","): builder.try_remove(param) # Always average multiple trials builder.try_remove(PARAMS['trial']) # Only need this for feather-trace parsing builder.try_remove(PARAMS['cycles']) col_map = builder.build() table = TupleTable(col_map) fill_table(table, exps, opts) if not table: sys.stderr.write("Found no data to parse!") sys.exit(1) write_output(table, opts)
def plot_by_variable(details): '''Plot each .csv files under @plot_node as a line on a shared plot.''' builder = ColMapBuilder() config_nodes = [] # Decode file names into configuration dicts for line_path, line_node in details.node.children.iteritems(): encoded = line_path[:line_path.index(".csv")] try: line_config = ColMap.decode(encoded) except: line_config = {'name': encoded} for k, v in line_config.iteritems(): builder.try_add(k, v) config_nodes += [(line_config, line_node)] col_map = builder.build() style_map = make_styler(col_map) figure = plot.figure() axes = figure.add_subplot(111) # Create a line for each file node and its configuration for line_config, line_node in config_nodes: style = style_map.get_style(line_config) values = sorted(line_node.values, key=lambda tup: tup[0]) xvalues, yvalues = zip(*values) plot.plot(xvalues, yvalues, style.fmt()) axes.set_title(details.title) lines, labels = zip(*style_map.get_key()) axes.legend(tuple(lines), tuple(labels), prop={'size':10}, # This code places the legend slightly to the right of the plot bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.0) axes.set_ylabel(details.value) axes.set_xlabel(details.variable) axes.set_xlim(0, axes.get_xlim()[1]) axes.set_ylim(0, axes.get_ylim()[1]) plot.savefig(details.out, format=OUT_FORMAT, # Using 'tight' causes savefig to rescale the image for non-plot # artists, which in our case is just the legend bbox_inches='tight') return True
def plot_by_variable(details): '''Plot each .csv files under @plot_node as a line on a shared plot.''' builder = ColMapBuilder() config_nodes = [] # Generate mapping of (column)=>(line property to vary) for consistently # formatted plots for line_path, line_node in details.node.children.iteritems(): encoded = line_path[:line_path.index(".csv")] try: line_config = ColMap.decode(encoded) except: line_config = {'name': encoded} for k, v in line_config.iteritems(): builder.try_add(k, v) config_nodes += [(line_config, line_node)] col_map = builder.build() style_map = StyleMap(col_map.columns(), col_map.get_values()) figure = plot.figure() axes = figure.add_subplot(111) # Create a line for each file node and its configuration for line_config, line_node in config_nodes: # Create line style to match this configuration style = style_map.get_style(line_config) values = sorted(line_node.values, key=lambda tup: tup[0]) xvalues, yvalues = zip(*values) plot.plot(xvalues, yvalues, style.fmt()) axes.set_title(details.title) lines, labels = zip(*style_map.get_key()) axes.legend(tuple(lines), tuple(labels), prop={'size':10}) axes.set_ylabel(details.value) axes.set_xlabel(details.variable) axes.set_xlim(0, axes.get_xlim()[1] + 1) axes.set_ylim(0, axes.get_ylim()[1] + 1) plot.savefig(details.out, format=OUT_FORMAT) return True
def create_exps(self, out_dir, force, trials): '''Create experiments for all possible combinations of params in @out_dir. Overwrite existing files if @force is True.''' builder = ColMapBuilder() # Track changing values so only relevant parameters are included # in directory names for dp in DesignPointGenerator(self.params): for k, v in dp.iteritems(): builder.try_add(k, v) col_map = builder.build() for dp in DesignPointGenerator(self.params): for trial in xrange(trials): # Create directory name from relevant parameters dir_leaf = "sched=%s_%s" % (self.scheduler, col_map.encode(dp)) dir_leaf = dir_leaf.strip('_') # If there are none dir_leaf += ("_trial=%s" % trial) if trials > 1 else "" dir_path = "%s/%s" % (out_dir, dir_leaf.strip('_')) if os.path.exists(dir_path): if force: sh.rmtree(dir_path) else: print("Skipping existing experiment: '%s'" % dir_path) continue os.mkdir(dir_path) if trials > 1: dp[PARAMS['trial']] = trial self.out_dir = dir_path self._create_exp(dict(dp)) del(self.out_dir) if PARAMS['trial'] in dp: del dp[PARAMS['trial']]
def create_exps(self, out_dir, force, trials): '''Create experiments for all possible combinations of params in @out_dir. Overwrite existing files if @force is True.''' builder = ColMapBuilder() # Track changing values so only relevant parameters are included # in directory names for dp in DesignPointGenerator(self.params): for k, v in dp.iteritems(): builder.try_add(k, v) col_map = builder.build() for dp in DesignPointGenerator(self.params): for trial in xrange(trials): # Create directory name from relevant parameters dir_leaf = "sched=%s_%s" % (self.scheduler, col_map.encode(dp)) dir_leaf = dir_leaf.strip('_') # If there are none dir_leaf += ("_trial=%s" % trial) if trials > 1 else "" dir_path = "%s/%s" % (out_dir, dir_leaf.strip('_')) if os.path.exists(dir_path): if force: sh.rmtree(dir_path) else: print("Skipping existing experiment: '%s'" % dir_path) continue os.mkdir(dir_path) if trials > 1: dp[PARAMS['trial']] = trial self.out_dir = dir_path self._create_exp(dict(dp)) del (self.out_dir) if PARAMS['trial'] in dp: del dp[PARAMS['trial']]
def write_collapsed_csvs(table, opts): sys.stderr.write("Collapse option specified. " "Only one numeric column at a time will be plotted.\n" "The values of others will be averaged. " "This is dangerous and can hide important trends!\n") original_map = table.get_col_map() builder = ColMapBuilder() numeric_cols = [] # Add only nonnumeric fields to builder for column in original_map.columns(): numeric = True for v in original_map.get_values()[column]: try: float(v) except ValueError: numeric = False builder.try_add(column, v) if numeric: numeric_cols += [column] for num_column in numeric_cols: # Only going to consider a single number column at a time for num_value in original_map.get_values()[column]: builder.try_add(num_column, num_value) next_map = builder.build() next_table = TupleTable(next_map) # Re-sort data into new table using this new key for mapped_key, points in table: kv = original_map.get_kv(mapped_key) next_table[kv] += points write_csvs(next_table, opts.out) builder.try_remove(num_column)
def main(): opts, args = parse_args() args = args or [os.getcwd()] # Load exp parameters into a ColMap builder = ColMapBuilder() exps = load_exps(args, builder, opts.force) # Don't track changes in ignored parameters if opts.ignore: for param in opts.ignore.split(","): builder.try_remove(param) # Always average multiple trials builder.try_remove(conf.PARAMS['trial']) col_map = builder.build() result_table = TupleTable(col_map) sys.stderr.write("Parsing data...\n") procs = min(len(exps), max(cpu_count()/2, 1)) pool = Pool(processes=procs) pool_args = zip(exps, [opts.force]*len(exps)) enum = pool.imap_unordered(parse_exp, pool_args, 1) try: for i, (exp, result) in enumerate(enum): if opts.verbose: print(result) else: sys.stderr.write('\r {0:.2%}'.format(float(i)/len(exps))) result_table[exp.params] += [result] pool.close() except: pool.terminate() traceback.print_exc() raise Exception("Failed parsing!") finally: pool.join() sys.stderr.write('\n') if opts.force and os.path.exists(opts.out): sh.rmtree(opts.out) reduced_table = result_table.reduce() sys.stderr.write("Writing result...\n") if opts.write_map: # Write summarized results into map reduced_table.write_map(opts.out) else: # Write out csv directories for all variable params dir_map = reduced_table.to_dir_map() # No csvs to write, assume user meant to print out data if dir_map.is_empty(): if not opts.verbose: sys.stderr.write("Too little data to make csv files.\n") for key, exp in result_table: for e in exp: print(e) else: dir_map.write(opts.out)