aboutsummaryrefslogtreecommitdiffstats
path: root/plot_exps.py
blob: bb6a707c7813d5aa2372460bfcfb898d58a5bafc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#!/usr/bin/env python
from __future__ import print_function

import matplotlib.pyplot as plot
import os
import shutil as sh
import sys
from collections import namedtuple
from optparse import OptionParser
from parse.col_map import ColMap
from parse.dir_map import DirMap
from parse.tuple_table import ReducedTupleTable
from plot.style import StyleMap

def parse_args():
    parser = OptionParser("usage: %prog [options] [csv_dir]...")

    parser.add_option('-o', '--out-dir', dest='out_dir',
                      help='directory for plot output', default='plot-data')
    parser.add_option('-f', '--force', action='store_true', default=False,
                      dest='force', help='overwrite existing data')

    return parser.parse_args()

ExpDetails = namedtuple('ExpDetails', ['variable', 'value', 'title', 'out'])
OUT_FORMAT = 'pdf'

def get_details(path, out_dir):
    '''Decode a @path into details about a single experiment.'''
    out = "_".join(path) if path else "plot"
    out = "%s/%s.%s" % (out_dir, out, OUT_FORMAT)

    value = path.pop(0) if path else None
    variable = path.pop(0) if path else None

    title  = value.capitalize() if value else ""
    title += " by %s" % variable if variable else ""
    title += " (%s)" % (", ".join(path)) if path else ""

    return ExpDetails(variable, value, title, out)

def plot_by_variable(plot_node, col_map, details):
    '''Plot each .csv files under @plot_node as a line on a shared plot.'''

    # Generate mapping of (column)=>(line property to vary) for consistently
    # formatted plots
    columns = list(col_map.columns())
    if details.variable and details.variable in columns:
        columns.remove(details.variable)
    style_map = StyleMap(columns, col_map.get_values())

    figure = plot.figure()
    axes = figure.add_subplot(111)

    # Create a line for each file node
    for line_path, line_node in plot_node.children.iteritems():
        # Create line style to match this configuration
        encoded = line_path[:line_path.index(".csv")]
        config  = ColMap.decode(encoded)
        style   = style_map.get_style(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)

def plot_dir(data_dir, out_dir, force):
    sys.stderr.write("Reading data...\n")
    dir_map = DirMap.read(data_dir)

    sys.stderr.write("Creating column map...\n")
    tuple_table = ReducedTupleTable.from_dir_map(dir_map)
    col_map = tuple_table.get_col_map()

    if not os.path.exists(out_dir):
        os.mkdir(out_dir)

    sys.stderr.write("Plotting...\n")

    # Count total plots for % counter
    num_plots = len([x for x in dir_map.leafs(1)])
    plot_num  = 0

    for plot_path, plot_node in dir_map.leafs(1):
        details = get_details(plot_path, out_dir)

        if force or not os.path.exists(details.out):
            plot_by_variable(plot_node, col_map, details)

        plot_num += 1

        sys.stderr.write('\r {0:.2%}'.format(float(plot_num)/num_plots))
        sys.stderr.write('\n')

def main():
    opts, args = parse_args()
    args = args or [os.getcwd()]

    if opts.force and os.path.exists(opts.out_dir):
        sh.rmtree(opts.out_dir)
    if not os.path.exists(opts.out_dir):
        os.mkdir(opts.out_dir)

    for dir in args:
        plot_dir(dir, opts.out_dir, opts.force)

if __name__ == '__main__':
    main()