In [1]:
import matplotlib
import matplotlib.pyplot as plt
%matplotlib inline
from collections import OrderedDict
In [2]:
class Line2DController(object):
    arg_pos = ['xdata', 'ydata', 'linewidth', 'linestyle', 'color', 'marker', 'markersize',
               'markeredgewidth', 'markeredgecolor', 'markerfacecolor', 'markerfacecoloralt',
               'fillstyle', 'antialiased', 'dash_capstyle', 'solid_capstyle', 'dash_joinstyle',
               'pickradius', 'drawstyle', 'markevery']
    defaults = dict(
        linewidth=None,
        linestyle=None,
        color=None,
        marker=None,
        markersize=None,
        markeredgewidth=None,
        markeredgecolor=None,
        markerfacecolor=None,
        markerfacecoloralt=u'none',
        fillstyle=u'full',
        antialiased=None,
        dash_capstyle=None,
        solid_capstyle=None,
        dash_joinstyle=None,
        solid_joinstyle=None,
        pickradius=5,
        drawstyle=None,
        markevery=None
    )
    def __init__(self, ax, *args, **kwargs):
        for key, val in self.get_args_mapping(args).items():
            setattr(self, key, val)
        for key, val in kwargs.items():
            if not hasattr(self, key):
                setattr(self, key, val)
        for key, val in self.defaults.items():
            if not hasattr(self, key): # make sure it wasn't set already
                setattr(self, key, val)
        self.ax = ax
        self.line = matplotlib.lines.Line2D(*args, **kwargs)
        ax.add_line(self.line)
        ax.relim()
        ax.autoscale_view()
        
    def redraw(self):
        kwargs = self.get_attributes()
        self.ax.lines.remove(self.line)
        self.line = matplotlib.lines.Line2D(**kwargs)
        self.ax.add_line(self.line)
        ax.relim()
        ax.autoscale_view()
        
    def get_args_mapping(self, args):
        d = {}
        for iii, arg in enumerate(args):
            d[self.arg_pos[iii]] = arg
        return d

    def get_attributes(self):
        d = {}
        for key in self.defaults:
            d[key] = getattr(self, key)
        d['xdata'] = self.xdata
        d['ydata'] = self.ydata
        return d
    
    def __setitem__(self, key, val):
        if key not in set.union(set(self.arg_pos), set(self.defaults)):
            raise Exception("don't do that...")
        else:
            setattr(self, key, val)
        self.redraw()
    
    def to_json(self):
        d = self.get_attributes()
        return d
        
In [3]:
fig, ax = plt.subplots()
lc1 = Line2DController(ax, [1,2,3], [2,1,2])
In [4]:
lc2 = Line2DController(ax, **lc1.to_json())  # obviously, we need to work out the axes reference...
In [5]:
# this behavior is key, we want to be able to just set attributes with the controller
# this will allow simple eventual instantiation with `**kwargs`
lc1['color'] = 'r'
lc1['xdata'] = [2, 3, 4]
lc1['ydata'] = [10, 3, 6]
lc1['marker'] = 'o'
lc1['markeredgewidth'] = 10
lc1['linewidth'] = 10
fig
Out[5]:
In [6]:
lc1.to_json()
Out[6]:
{'antialiased': None,
 'color': 'r',
 'dash_capstyle': None,
 'dash_joinstyle': None,
 'drawstyle': None,
 'fillstyle': u'full',
 'linestyle': None,
 'linewidth': 10,
 'marker': 'o',
 'markeredgecolor': None,
 'markeredgewidth': 10,
 'markerfacecolor': None,
 'markerfacecoloralt': u'none',
 'markersize': None,
 'markevery': None,
 'pickradius': 5,
 'solid_capstyle': None,
 'solid_joinstyle': None,
 'xdata': [2, 3, 4],
 'ydata': [10, 3, 6]}
In [7]:
lc2.to_json()
Out[7]:
{'antialiased': None,
 'color': None,
 'dash_capstyle': None,
 'dash_joinstyle': None,
 'drawstyle': None,
 'fillstyle': u'full',
 'linestyle': None,
 'linewidth': None,
 'marker': None,
 'markeredgecolor': None,
 'markeredgewidth': None,
 'markerfacecolor': None,
 'markerfacecoloralt': u'none',
 'markersize': None,
 'markevery': None,
 'pickradius': 5,
 'solid_capstyle': None,
 'solid_joinstyle': None,
 'xdata': [1, 2, 3],
 'ydata': [2, 1, 2]}