>>>>> "Christopher" == Christopher Barker <[EMAIL PROTECTED]> writes:

    Christopher> This sounds like a job for properties! make
    Christopher> _transform a property, and code that gets and sets it
    Christopher> directly should still work. though People that were
    Christopher> accessing an underscored name directly should expect
    Christopher> this kind of problem.

The matplotlib artist kwarg properties act like python properties or
enthought traits, with some advantages and disadvantages over each
(mostly disadvantages, alas).  We've discussed migrating to one or
another over the years, but haven't bitten the bullet.  At each point
it's easier to extend the exiting implementation than refactor the
whole bit; the tyranny of small decisions.

Here are some of the pros and cons as I see them of enthought traits
vs python properties

   Pros:
   * compatibility with the rest of the enthought tool suite
   * built in observer pattern
   * automatic UI for wx users
   * performance is better than python properties last time I looked
   * matplotlib ships with enthought traits built in 

   Cons:
   * smaller user base than python properties may imply
     fewer 3rd party enhancements, less support, etc
   * we have to maintain our copy of enthought traits to keep it
     current and building or require an additional dependency

I spent some time working on matplotlib rc properties as enthought
traits as a precursor to porting matplotlib properties to traits.
Here is some example code showing how to define some representative rc
properties and construct a matplotlib artist using traits.  Because
matplotlib ships with enthought traits already, you can run this
script with just matplotlib.  Unfortunately, we do not ship the ex UI
component so you can't test that part.  I'm  a bit of a traits newbie
so there are probably better ways to do what I have done below.

import sys, os, re
import matplotlib.enthought.traits as traits
from matplotlib.cbook import is_string_like
from matplotlib.artist import Artist

doprint = True
flexible_true_trait = traits.Trait(
    True,  
    { 'true':  True, 't': True, 'yes': True, 'y': True, 'on':  True, True: True,
      'false': False, 'f': False, 'no':  False, 'n': False, 'off': False, 
False: False
                               } )
flexible_false_trait = traits.Trait( False, flexible_true_trait )

colors = {
    'c' : '#00bfbf',
    'b' : '#0000ff',
    'g' : '#008000',
    'k' : '#000000',
    'm' : '#bf00bf',
    'r' : '#ff0000',
    'w' : '#ffffff',
    'y' : '#bfbf00',
    'gold'                 : '#FFD700', 
    'peachpuff'            : '#FFDAB9', 
    'navajowhite'          : '#FFDEAD', 
    }

def hex2color(s):
    "Convert hex string (like html uses, eg, #efefef) to a r,g,b tuple"
    return tuple([int(n, 16)/255.0 for n in (s[1:3], s[3:5], s[5:7])])

class RGBA(traits.HasTraits):
    # r,g,b,a in the range 0-1 with default color 0,0,0,1 (black)
    r = traits.Range(0., 1., 0.)
    g = traits.Range(0., 1., 0.)
    b = traits.Range(0., 1., 0.)
    a = traits.Range(0., 1., 1.)
    def __init__(self, r=0., g=0., b=0., a=1.):
        self.r = r
        self.g = g
        self.b = b
        self.a = a
    def __repr__(self):
        return 'r,g,b,a = (%1.2f, %1.2f, %1.2f, %1.2f)'%\
               (self.r, self.g, self.b, self.a)

def tuple_to_rgba(ob, name, val):
    tup = [float(x) for x in val]
    if len(tup)==3:
        r,g,b = tup
        return RGBA(r,g,b)
    elif len(tup)==4:
        r,g,b,a = tup
        return RGBA(r,g,b,a)
    else:
        raise ValueError
tuple_to_rgba.info = 'a RGB or RGBA tuple of floats'

def hex_to_rgba(ob, name, val):
    rgx = re.compile('^#[0-9A-Fa-f]{6}$')

    if not is_string_like(val):
        raise TypeError
    if rgx.match(val) is None:
        raise ValueError
    r,g,b = hex2color(val)
    return RGBA(r,g,b,1.0)
hex_to_rgba.info = 'a hex color string'

def colorname_to_rgba(ob, name, val):
    hex = colors[val.lower()]
    r,g,b =  hex2color(hex)
    return RGBA(r,g,b,1.0)
colorname_to_rgba.info = 'a named color'

def float_to_rgba(ob, name, val):
    val = float(val)
    return RGBA(val, val, val, 1.)
float_to_rgba.info = 'a grayscale intensity'



Color = traits.Trait(RGBA(), float_to_rgba, colorname_to_rgba, RGBA,
              hex_to_rgba, tuple_to_rgba)

def file_exists(ob, name, val):
    fh = file(val, 'r')
    return val

def path_exists(ob, name, val):
    os.path.exists(val)
linestyles  = ('-', '--', '-.', ':', 'steps', 'None')
TICKLEFT, TICKRIGHT, TICKUP, TICKDOWN = range(4)
linemarkers = (None, '.', ',', 'o', '^', 'v', '<', '>', 's',
                  '+', 'x', 'd', 'D', '|', '_', 'h', 'H',
                  'p', '1', '2', '3', '4',
                  TICKLEFT,
                  TICKRIGHT,
                  TICKUP,
                  TICKDOWN,
                  'None'
               )

class LineRC(traits.HasTraits):
    linewidth       = traits.Float(0.5)           
    linestyle       = traits.Trait(*linestyles)
    color           = Color
    marker          = traits.Trait(*linemarkers)
    markerfacecolor = Color
    markeredgecolor = Color     
    markeredgewidth = traits.Float(0.5)
    markersize      = traits.Float(6)            
    antialiased     = flexible_true_trait         
    data_clipping   = flexible_false_trait      

class PatchRC(traits.HasTraits):
    linewidth       = traits.Float(1.0)           
    facecolor = Color
    edgecolor = Color     
    antialiased     = flexible_true_trait         

timezones = 'UTC', 'US/Central', 'ES/Eastern' # fixme: and many more
backends = ('GTKAgg', 'Cairo', 'FltkAgg', 'GD', 'GDK', 'GTK', 'Agg',
            'GTKCairo', 'Paint', 'PS', 'SVG', 'Template', 'TkAgg',
            'WX')

class RC(traits.HasTraits):
    backend = traits.Trait(*backends)
    numerix = traits.Trait('Numeric', 'numarray')
    interactive  = flexible_false_trait
    toolbar      = traits.Trait('toolbar2', 'classic', None)
    timezone     = traits.Trait(*timezones)
    lines        = traits.Trait(LineRC())
    patch        = traits.Trait(PatchRC())

rc = RC()
rc.lines.color = 'r'
if doprint:
    print 'RC'
    rc.print_traits()
    print 'RC lines'
    rc.lines.print_traits()
    print 'RC patches'
    rc.patch.print_traits()


class Patch(Artist, traits.HasTraits):
    linewidth = traits.Float(0.5)
    facecolor = Color
    fc = facecolor
    edgecolor = Color
    fill = flexible_true_trait
    def __init__(self,
                 edgecolor=None,   
                 facecolor=None,
                 linewidth=None,
                 antialiased = None, 
                 fill=1,
                 **kwargs
                 ):
        Artist.__init__(self)

        if edgecolor is None: edgecolor = rc.patch.edgecolor
        if facecolor is None: facecolor = rc.patch.facecolor
        if linewidth is None: linewidth = rc.patch.linewidth
        if antialiased is None: antialiased = rc.patch.antialiased

        self.edgecolor = edgecolor
        self.facecolor = facecolor
        self.linewidth = linewidth
        self.antialiased = antialiased        
        self.fill = fill

    
p = Patch()
p.facecolor = '#bfbf00'
p.edgecolor = 'gold'
p.facecolor = (1,.5,.5,.25)
p.facecolor = 0.25
p.fill = 'f'
print 'p.facecolor', type(p.facecolor), p.facecolor
print 'p.fill', type(p.fill), p.fill
if p.fill_: print 'fill'
else: print 'no fill'
if doprint:
    print
    print 'Patch'
    p.print_traits()



JDH

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users

Reply via email to