|
| 1 | +# Here is some example code showing how to define some representative |
| 2 | +# rc properties and construct a matplotlib artist using traits. |
| 3 | +# Because matplotlib ships with enthought traits already, you can run |
| 4 | +# this script with just matplotlib. Unfortunately, we do not ship the |
| 5 | +# ex UI component so you can't test that part. I'm a bit of a traits |
| 6 | +# newbie so there are probably better ways to do what I have done |
| 7 | +# below. |
| 8 | + |
| 9 | +import sys, os, re |
| 10 | +import matplotlib.enthought.traits as traits |
| 11 | +from matplotlib.cbook import is_string_like |
| 12 | +from matplotlib.artist import Artist |
| 13 | + |
| 14 | +doprint = True |
| 15 | +flexible_true_trait = traits.Trait( |
| 16 | + True, |
| 17 | + { 'true': True, 't': True, 'yes': True, 'y': True, 'on': True, True: True, |
| 18 | + 'false': False, 'f': False, 'no': False, 'n': False, 'off': False, False: False |
| 19 | + } ) |
| 20 | +flexible_false_trait = traits.Trait( False, flexible_true_trait ) |
| 21 | + |
| 22 | +colors = { |
| 23 | + 'c' : '#00bfbf', |
| 24 | + 'b' : '#0000ff', |
| 25 | + 'g' : '#008000', |
| 26 | + 'k' : '#000000', |
| 27 | + 'm' : '#bf00bf', |
| 28 | + 'r' : '#ff0000', |
| 29 | + 'w' : '#ffffff', |
| 30 | + 'y' : '#bfbf00', |
| 31 | + 'gold' : '#FFD700', |
| 32 | + 'peachpuff' : '#FFDAB9', |
| 33 | + 'navajowhite' : '#FFDEAD', |
| 34 | + } |
| 35 | + |
| 36 | +def hex2color(s): |
| 37 | + "Convert hex string (like html uses, eg, #efefef) to a r,g,b tuple" |
| 38 | + return tuple([int(n, 16)/255.0 for n in (s[1:3], s[3:5], s[5:7])]) |
| 39 | + |
| 40 | +class RGBA(traits.HasTraits): |
| 41 | + # r,g,b,a in the range 0-1 with default color 0,0,0,1 (black) |
| 42 | + r = traits.Range(0., 1., 0.) |
| 43 | + g = traits.Range(0., 1., 0.) |
| 44 | + b = traits.Range(0., 1., 0.) |
| 45 | + a = traits.Range(0., 1., 1.) |
| 46 | + def __init__(self, r=0., g=0., b=0., a=1.): |
| 47 | + self.r = r |
| 48 | + self.g = g |
| 49 | + self.b = b |
| 50 | + self.a = a |
| 51 | + def __repr__(self): |
| 52 | + return 'r,g,b,a = (%1.2f, %1.2f, %1.2f, %1.2f)'%\ |
| 53 | + (self.r, self.g, self.b, self.a) |
| 54 | + |
| 55 | +def tuple_to_rgba(ob, name, val): |
| 56 | + tup = [float(x) for x in val] |
| 57 | + if len(tup)==3: |
| 58 | + r,g,b = tup |
| 59 | + return RGBA(r,g,b) |
| 60 | + elif len(tup)==4: |
| 61 | + r,g,b,a = tup |
| 62 | + return RGBA(r,g,b,a) |
| 63 | + else: |
| 64 | + raise ValueError |
| 65 | +tuple_to_rgba.info = 'a RGB or RGBA tuple of floats' |
| 66 | + |
| 67 | +def hex_to_rgba(ob, name, val): |
| 68 | + rgx = re.compile('^#[0-9A-Fa-f]{6}$') |
| 69 | + |
| 70 | + if not is_string_like(val): |
| 71 | + raise TypeError |
| 72 | + if rgx.match(val) is None: |
| 73 | + raise ValueError |
| 74 | + r,g,b = hex2color(val) |
| 75 | + return RGBA(r,g,b,1.0) |
| 76 | +hex_to_rgba.info = 'a hex color string' |
| 77 | + |
| 78 | +def colorname_to_rgba(ob, name, val): |
| 79 | + hex = colors[val.lower()] |
| 80 | + r,g,b = hex2color(hex) |
| 81 | + return RGBA(r,g,b,1.0) |
| 82 | +colorname_to_rgba.info = 'a named color' |
| 83 | + |
| 84 | +def float_to_rgba(ob, name, val): |
| 85 | + val = float(val) |
| 86 | + return RGBA(val, val, val, 1.) |
| 87 | +float_to_rgba.info = 'a grayscale intensity' |
| 88 | + |
| 89 | + |
| 90 | + |
| 91 | +Color = traits.Trait(RGBA(), float_to_rgba, colorname_to_rgba, RGBA, |
| 92 | + hex_to_rgba, tuple_to_rgba) |
| 93 | + |
| 94 | +def file_exists(ob, name, val): |
| 95 | + fh = file(val, 'r') |
| 96 | + return val |
| 97 | + |
| 98 | +def path_exists(ob, name, val): |
| 99 | + os.path.exists(val) |
| 100 | +linestyles = ('-', '--', '-.', ':', 'steps', 'None') |
| 101 | +TICKLEFT, TICKRIGHT, TICKUP, TICKDOWN = range(4) |
| 102 | +linemarkers = (None, '.', ',', 'o', '^', 'v', '<', '>', 's', |
| 103 | + '+', 'x', 'd', 'D', '|', '_', 'h', 'H', |
| 104 | + 'p', '1', '2', '3', '4', |
| 105 | + TICKLEFT, |
| 106 | + TICKRIGHT, |
| 107 | + TICKUP, |
| 108 | + TICKDOWN, |
| 109 | + 'None' |
| 110 | + ) |
| 111 | + |
| 112 | +class LineRC(traits.HasTraits): |
| 113 | + linewidth = traits.Float(0.5) |
| 114 | + linestyle = traits.Trait(*linestyles) |
| 115 | + color = Color |
| 116 | + marker = traits.Trait(*linemarkers) |
| 117 | + markerfacecolor = Color |
| 118 | + markeredgecolor = Color |
| 119 | + markeredgewidth = traits.Float(0.5) |
| 120 | + markersize = traits.Float(6) |
| 121 | + antialiased = flexible_true_trait |
| 122 | + data_clipping = flexible_false_trait |
| 123 | + |
| 124 | +class PatchRC(traits.HasTraits): |
| 125 | + linewidth = traits.Float(1.0) |
| 126 | + facecolor = Color |
| 127 | + edgecolor = Color |
| 128 | + antialiased = flexible_true_trait |
| 129 | + |
| 130 | +timezones = 'UTC', 'US/Central', 'ES/Eastern' # fixme: and many more |
| 131 | +backends = ('GTKAgg', 'Cairo', 'FltkAgg', 'GD', 'GDK', 'GTK', 'Agg', |
| 132 | + 'GTKCairo', 'Paint', 'PS', 'SVG', 'Template', 'TkAgg', |
| 133 | + 'WX') |
| 134 | + |
| 135 | +class RC(traits.HasTraits): |
| 136 | + backend = traits.Trait(*backends) |
| 137 | + numerix = traits.Trait('Numeric', 'numarray') |
| 138 | + interactive = flexible_false_trait |
| 139 | + toolbar = traits.Trait('toolbar2', 'classic', None) |
| 140 | + timezone = traits.Trait(*timezones) |
| 141 | + lines = traits.Trait(LineRC()) |
| 142 | + patch = traits.Trait(PatchRC()) |
| 143 | + |
| 144 | +rc = RC() |
| 145 | +rc.lines.color = 'r' |
| 146 | +if doprint: |
| 147 | + print 'RC' |
| 148 | + rc.print_traits() |
| 149 | + print 'RC lines' |
| 150 | + rc.lines.print_traits() |
| 151 | + print 'RC patches' |
| 152 | + rc.patch.print_traits() |
| 153 | + |
| 154 | + |
| 155 | +class Patch(Artist, traits.HasTraits): |
| 156 | + linewidth = traits.Float(0.5) |
| 157 | + facecolor = Color |
| 158 | + fc = facecolor |
| 159 | + edgecolor = Color |
| 160 | + fill = flexible_true_trait |
| 161 | + def __init__(self, |
| 162 | + edgecolor=None, |
| 163 | + facecolor=None, |
| 164 | + linewidth=None, |
| 165 | + antialiased = None, |
| 166 | + fill=1, |
| 167 | + **kwargs |
| 168 | + ): |
| 169 | + Artist.__init__(self) |
| 170 | + |
| 171 | + if edgecolor is None: edgecolor = rc.patch.edgecolor |
| 172 | + if facecolor is None: facecolor = rc.patch.facecolor |
| 173 | + if linewidth is None: linewidth = rc.patch.linewidth |
| 174 | + if antialiased is None: antialiased = rc.patch.antialiased |
| 175 | + |
| 176 | + self.edgecolor = edgecolor |
| 177 | + self.facecolor = facecolor |
| 178 | + self.linewidth = linewidth |
| 179 | + self.antialiased = antialiased |
| 180 | + self.fill = fill |
| 181 | + |
| 182 | + |
| 183 | +p = Patch() |
| 184 | +p.facecolor = '#bfbf00' |
| 185 | +p.edgecolor = 'gold' |
| 186 | +p.facecolor = (1,.5,.5,.25) |
| 187 | +p.facecolor = 0.25 |
| 188 | +p.fill = 'f' |
| 189 | +print 'p.facecolor', type(p.facecolor), p.facecolor |
| 190 | +print 'p.fill', type(p.fill), p.fill |
| 191 | +if p.fill_: print 'fill' |
| 192 | +else: print 'no fill' |
| 193 | +if doprint: |
| 194 | + print |
| 195 | + print 'Patch' |
| 196 | + p.print_traits() |
| 197 | + |
| 198 | + |
| 199 | + |
0 commit comments