#!/usr/bin/env python

import os
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
import numpy as np

"""Represents the graph of a mathematical function.

When defining a graph, subclass this class and provide an x and y numpy array."""
class Graph(object):

    """Draw the graph to a matplotlib figure."""
    def draw_to(self, figure):
        figure.suptitle(self.title)
        axes = figure.gca()

        if isinstance(self.y, Parameterized):
            for (y, label) in self.y:
                axes.plot(self.x, y, label=label)
            axes.legend()
        else:
            axes.plot(self.x, self.y)

    """Draw the graph in a GUI frontend through pyplot."""
    def show(self):
        figure = plt.figure()
        self.draw_to(figure)
        plt.show()

    """Return the path where the graph will be saved by save()."""
    def path(self, dir):
        fn = reduce(lambda val, name: val or getattr(self, name, None),
            ("filename", "title"), None) or self.__class__.__name__

        if not fn.lower().endswith(".svg"):
            fn += ".svg"

        return os.path.join(dir, fn)

    """Save the graph to the file system."""
    def save(self, dir):
        path = self.path(dir)
        print("Saving graph to %s" %path)

        self.draw_to(plt.figure())
        plt.savefig(path)

"""A parameterized dependent variable.

Use to graph multiple slight variations of the same function together."""
class Parameterized(object):
    def __init__(self, name, template, values):
        self.name = name
        self.template = template
        self.values = values

    def __iter__(self):
        self.index = 0
        return self

    def next(self):
        try:
            value = self.values[self.index]
        except IndexError:
            raise StopIteration

        self.index += 1
        return self.template(value), "%s = %s" %(self.name, value)

if __name__ == "__main__":
    def sine_graph():
        g = Graph()
        g.x = np.arange(0.0, 10.0, 0.01)
        g.y = Parameterized("A", lambda A: A * np.sin(g.x), (1, 2, 3))
        g.title = "Sine wave"

        return g

    sine_graph().save(".")

@@ -26,16 +26,33 @@
 port os%0A
+import functools%0A
 import m
@@ -78,63 +78,8 @@
  plt
-%0Afrom matplotlib.lines import Line2D%0Aimport numpy as np
 %0A%0A%22%22
@@ -313,16 +313,33 @@
 igure):%0A
+        try:%0A    
         
@@ -366,16 +366,65 @@
 .title)%0A
+        except AttributeError:%0A            pass%0A%0A
         
@@ -919,44 +919,29 @@
     
-fn = reduce(lambda val, name: val or
+try:%0A            fn =
  get
@@ -955,88 +955,152 @@
 lf, 
+%22file
 name
+%22
 , None)
-,%0A            (%22filename%22, %22title%22), None) or self.__class__.__name__
+ or self.recipe.__name__%0A        except AttributeError:%0A            raise AttributeError(%22Graph must have filename or recipe.%22)
 %0A%0A  
@@ -1990,34 +1990,398 @@
 e)%0A%0A
-if __name__ == %22__main__%22:
+recipes = %5B%5D%0A%0Adef recipe(func):%0A    @functools.wraps(func)%0A    def wrapper():%0A        graph = func()%0A        graph.recipe = wrapper%0A        return graph%0A%0A    recipes.append(wrapper)%0A    return wrapper%0A%0Adef save_all(dir=None):%0A    if dir is None:%0A        dir = os.getcwd()%0A%0A    for recipe in recipes:%0A        recipe().save(dir)%0A%0Aif __name__ == %22__main__%22:%0A    import numpy as np%0A%0A    @recipe
 %0A   
@@ -2589,26 +2589,14 @@
    s
-ine_graph().save(%22.%22
+ave_all(
 )%0A

Use recipe decorator to discover graphs to save