SourceForge logo
SourceForge logo
Menu

matplotlib-checkins

Revision: 3581
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3581&view=rev
Author: jdh2358
Date: 2007年07月19日 20:36:59 -0700 (2007年7月19日)
Log Message:
-----------
added mpl like line and rect artists to sketch
Modified Paths:
--------------
 trunk/matplotlib/mpl1/mpl1.py
Modified: trunk/matplotlib/mpl1/mpl1.py
===================================================================
--- trunk/matplotlib/mpl1/mpl1.py	2007年07月20日 02:10:43 UTC (rev 3580)
+++ trunk/matplotlib/mpl1/mpl1.py	2007年07月20日 03:36:59 UTC (rev 3581)
@@ -252,7 +252,7 @@
 raise NotImplementedError
 
 
-mtraits.Model = traits.Trait(Identity(), Polar())
+mtraits.Model = traits.Trait(None, Identity, Polar)
 
 
 
@@ -265,12 +265,12 @@
 MOVETO, LINETO, CLOSEPOLY = range(3)
 
 strokecolor = mtraits.Color('black')
- fillcolor = mtraits.Color('blue')
- alpha = mtraits.Alpha(1.0)
- linewidth = mtraits.LineWidth(1.0)
+ fillcolor = mtraits.Color('blue')
+ alpha = mtraits.Alpha(1.0)
+ linewidth = mtraits.LineWidth(1.0)
 antialiased = mtraits.FlexibleTrueTrait()
- pathdata = mtraits.PathData()
- affine = mtraits.Affine()
+ pathdata = mtraits.PathData()
+ affine = mtraits.Affine()
 
 def __init__(self):
 
@@ -279,11 +279,10 @@
 # instances, which is not what I want
 self.strokecolor = 'black'
 self.fillcolor = 'blue'
- self.pathdata = (npy.array([0,0], npy.uint8), # codes
- npy.array([[0,0], [0,0]])) # verts
 self.affine = affine_identity()
- 
- 
+ self.pathdata = (npy.array([0,0], npy.uint8), # codes
+ npy.array([[0,0], [0,0]])) # verts
+ 
 mtraits.Path = traits.Trait(Path())
 
 class AggPath(Path):
@@ -350,10 +349,10 @@
 return agg.rgba8(*rgba)
 
 class Markers(traits.HasTraits):
- verts = mtraits.Verts() # locations to draw the markers at
- path = mtraits.Path() # marker path in points
+ verts = mtraits.Verts() # locations to draw the markers at
+ path = mtraits.Path() # marker path in points
 affine = mtraits.Affine() # transformation for the verts
- x = traits.Float(1.0)
+ x = traits.Float(1.0)
 
 def __init__(self):
 # this is a quick workaround to prevent sharing obs; see Path
@@ -405,10 +404,10 @@
 artistID = IDGenerator()
 
 class Artist(traits.HasTraits):
- zorder = traits.Float(1.0)
- alpha = mtraits.Alpha(1.0)
+ zorder = traits.Float(1.0)
+ alpha = mtraits.Alpha(1.0)
 visible = mtraits.FlexibleTrueTrait()
- affine = mtraits.Affine()
+ affine = mtraits.Affine()
 
 def __init__(self):
 self.artistid = artistID()
@@ -439,8 +438,8 @@
 path = mtraits.Path()
 markers = mtraits.Markers()
 X = mtraits.Verts()
- model = mtraits.Model(Identity())
-
+ model = mtraits.Model
+ zorder = traits.Float(2.0)
 
 def __init__(self):
 """
@@ -449,6 +448,19 @@
 """
 Artist.__init__(self)
 
+ # this is potentially a big problem because you have to know
+ # which attrs may be shared and hence have to be initialized
+ # and which ones don't. Eg, if you comment out the self.path
+ # init, the code breaks
+ self.color = 'blue'
+ self.markerfacecolor = 'blue'
+ self.markeredgecolor = 'black'
+ self.path = Path()
+ self.markers = Markers()
+ self.X = npy.array([[0,1], [0,1]], npy.float_)
+ self.model = Identity()
+ #self.model = None # switch comments with above to reveal bug 
+ 
 self.sync_trait('linewidth', self.path, 'linewidth', mutual=False)
 self.sync_trait('color', self.path, 'strokecolor', mutual=False)
 self.sync_trait('markerfacecolor', self.markers.path, 'fillcolor', mutual=False)
@@ -494,11 +506,15 @@
 codes = Path.LINETO*npy.ones(N, dtype=npy.uint8)
 codes[0] = Path.MOVETO
 
- modelx = self.model(newx)
+ # todo, having touble setting Model to default to Identity so
+ # allowing None as a hack workaround
+ if self.model is not None:
+ modelx = self.model(newx)
+ else:
+ modelx = newx
 self.path.pathdata = codes, modelx
 self.markers.verts = modelx
 
-
 def _markersize_changed(self, oldX, newX):
 self._refresh_markers()
 
@@ -526,25 +542,27 @@
 facecolor = mtraits.Color('Yellow')
 edgecolor = mtraits.Color('Black')
 edgewidth = mtraits.LineWidth(1.0)
- lbwh = traits.Array('d', (4,), [0,0,1,1])
- path = mtraits.Path()
- 
+ lbwh = traits.Array('d', (4,), [0,0,1,1])
+ path = mtraits.Path()
+ zorder = traits.Float(1.0)
+
 def __init__(self):
+ Artist.__init__(self)
 self.facecolor = 'yellow'
 self.edgecolor = 'black'
 self.edgewidth = 1.0
 self.lbwh = 0,0,1,1
 self.path = Path()
 
- self.sync_trait('facecolor', self, 'fillcolor', True)
- self.sync_trait('edgecolor', self, 'strokecolor', True)
- self.sync_trait('edgewidth', self, 'linewidth', True)
- self.sync_trait('affine', self.markers)
+ self.sync_trait('facecolor', self.path, 'fillcolor', mutual=False)
+ self.sync_trait('edgecolor', self.path, 'strokecolor', mutual=False)
+ self.sync_trait('edgewidth', self.path, 'linewidth', mutual=False)
+ self.sync_trait('affine', self.path, mutual=False)
 
 self.pathid = primitiveID()
- 
+
+
 def _lbwh_changed(self, old, new):
- print 'lbwh changed'
 l,b,w,h = new
 t = b+h
 r = l+w
@@ -567,7 +585,6 @@
 raise RuntimeError('First call set_renderer')
 
 if not self.visible: return
-
 self.renderer.render_path(self.pathid)
 
 class Figure:
@@ -593,11 +610,11 @@
 
 
 class AxesCoords(traits.HasTraits):
- xviewlim = mtraits.Interval()
- yviewlim = mtraits.Interval()
+ xviewlim = mtraits.Interval()
+ yviewlim = mtraits.Interval()
 affineview = mtraits.Affine()
 affineaxes = mtraits.Affine() 
- affine = mtraits.Affine() 
+ affine = mtraits.Affine() 
 
 def __init__(self):
 self.xviewlim = npy.array([0., 1.])
@@ -630,7 +647,7 @@
 self.affine = npy.dot(self.affineaxes, self.affineview)
 
 
-x1 = npy.arange(0, 10., 0.1)
+x1 = npy.arange(0, 10., 0.05)
 x2 = npy.arange(0, 10., 0.1)
 y1 = npy.cos(2*npy.pi*x1)
 y2 = 10*npy.exp(-x1)
@@ -646,26 +663,26 @@
 line1.X = npy.array([x1,y1]).T
 
 line1.setp(color='blue', linewidth=2.0, marker='s', markersize=5.0,
- markerfacecolor='green', markeredgewidth=0.5)
+ markerfacecolor='green', markeredgewidth=0.5)
 coords1.sync_trait('affine', line1, mutual=False)
 
 fig.artistd[line1.artistid] = line1
 
+
 rect1 = Rectangle()
 rect1.lbwh = [0,0,1,1]
 rect1.facecolor = 'white'
 fig.artistd[rect1.artistid] = rect1
+coords1.sync_trait('affineaxes', rect1, 'affine', mutual=False)
 
 
-#coords1.sync_trait('affineaxes', rect1, 'affine')
-
 # update the view limits, all the affines should be automagically updated
 coords1.xviewlim = 0, 10
 coords1.yviewlim = -1.1, 1.1
 
 
-if 0:
- # the axes rectangle
+
+if 1:
 axrect2 = [0.55, 0.55, 0.4, 0.4]
 coords2 = AxesCoords()
 coords2.affineaxes = affine_axes(axrect2)
@@ -673,16 +690,22 @@
 
 r = npy.arange(0.0, 1.0, 0.01)
 theta = r*4*npy.pi
+ 
+ line2 = Line()
+ line2.model = Polar()
+ line2.setp(color='#ee8d18', linewidth=2.0)
+ line2.X = npy.array([r, theta]).T
+ coords2.sync_trait('affine', line2, mutual=False)
 
- line2 = Line(r, theta, model=Polar(), color='#ee8d18', linewidth=2.0)
- rect2 = Rectangle([0,0,1,1], facecolor='#d5de9c')
- coords2.sync_trait('affine', line2, mutual=False)
+ rect2 = Rectangle()
+ rect2.lbwh = [0,0,1,1]
+ rect2.facecolor = '#d5de9c'
 coords2.sync_trait('affineaxes', rect2, 'affine', mutual=False)
 
- fig.add_path(rect2)
- fig.add_path(line2)
+ fig.artistd[line2.artistid] = line2
+ fig.artistd[rect2.artistid] = rect2 
 
- # update the view limits, all the affines should be automagically updated
+
 coords2.xviewlim = -1.1, 1.1
 coords2.yviewlim = -1.1, 1.1
 
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 3587
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3587&view=rev
Author: jdh2358
Date: 2007年07月20日 06:46:20 -0700 (2007年7月20日)
Log Message:
-----------
traits cleanup
Modified Paths:
--------------
 trunk/matplotlib/mpl1/mpl1.py
Modified: trunk/matplotlib/mpl1/mpl1.py
===================================================================
--- trunk/matplotlib/mpl1/mpl1.py	2007年07月20日 13:44:10 UTC (rev 3586)
+++ trunk/matplotlib/mpl1/mpl1.py	2007年07月20日 13:46:20 UTC (rev 3587)
@@ -1,3 +1,22 @@
+"""
+Install instructions for traits 2.0
+
+ # blow away old enthought
+ rm -rf ~/dev/lib/python2.4/site-packages/enthought.*
+
+ # get easy_install, if necessary
+ wget http://peak.telecommunity.com/dist/ez_setup.py
+ sudo python sez_setup.py
+
+ sudo easy_install -f http://code.enthought.com/enstaller/eggs/source/unstable "enthought.etsconfig < 3.0a" "enthought.util <3.0a" "enthought.debug <3.0a"
+
+ svn co https://svn.enthought.com/svn/enthought/branches/enthought.traits_2.0 enthought_traits
+
+ cd enthought_traits/
+ sudo python setup.py install 
+
+"""
+
 # see install instructions for enthrought traits2 in mtraits
 import enthought.traits.api as traits
 
@@ -7,6 +26,22 @@
 
 
 class ColorHandler(traits.TraitHandler):
+ """
+ This is a clever little traits mechanism -- users can specify the
+ color as any mpl color, and the traited object will keep the
+ original color, but will add a new attribute with a '_' postfix
+ which is the color rgba tuple.
+
+ Eg
+
+ class C(HasTraits):
+ fillcolor = traits.Trait('black', ColorHandler())
+
+ c = C()
+ c.fillcolor = 'red'
+ print c.fillcolor
+ print c.fillcolor_ # 
+ """
 is_mapped = True
 
 def post_setattr(self, object, name, value):
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 3591
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3591&view=rev
Author: jdh2358
Date: 2007年07月20日 08:17:37 -0700 (2007年7月20日)
Log Message:
-----------
affines are first class objects
Modified Paths:
--------------
 trunk/matplotlib/mpl1/mpl1.py
Modified: trunk/matplotlib/mpl1/mpl1.py
===================================================================
--- trunk/matplotlib/mpl1/mpl1.py	2007年07月20日 14:19:48 UTC (rev 3590)
+++ trunk/matplotlib/mpl1/mpl1.py	2007年07月20日 15:17:37 UTC (rev 3591)
@@ -22,9 +22,89 @@
 
 from matplotlib import agg
 from matplotlib import colors as mcolors
+from matplotlib import cbook
 import numpy as npy
 
+is_string_like = cbook.is_string_like
 
+
+
+class Affine(traits.HasTraits):
+ """
+ An affine 3x3 matrix that supports matrix multiplication with
+ other Affine instances or numpy arrays.
+
+ a = Affine()
+ a.translate = 10,20
+ a.scale = 20, 40
+
+ Be careful not to do *inplace* operations on the array components
+ or the update callbacks will not be triggered, eg DO NOT 
+
+ a.translate += 10, 20
+
+ rather DO
+
+ a.translate_delta(10, 20)
+ """
+ data = traits.Array('d', (3,3), npy.array([[1,0,0],[0,1,0],[0,0,1]], npy.float_))
+
+ translate = traits.Array('d', (2,), [0,0])
+ scale = traits.Array('d', (2,), [0,0])
+ vec6 = traits.Array('d', (6,), [1,0,0,1,0,0])
+
+ def translate_delta(self, tx, ty):
+ oldtx, oldty = self.translate
+ self.translate = oldtx + tx, oldty + ty
+ 
+ def _translate_changed(self, old, new):
+ #print 'translate change', new
+ tx, ty = new
+ self.data[0][-1] = tx
+ self.data[1][-1] = ty
+ self.vec6[-2:] = tx, ty
+ 
+ def _vec6_changed(self, old, new):
+ #print 'vec6 change', new
+ sx, b, c, sy, tx, ty = new
+ self.data[0] = sx, b, tx
+ self.data[1] = c, sy, ty
+ self.translate = tx, ty
+ self.scale = sx, sy
+ 
+ def _scale_changed(self, old, new):
+ #print 'scale change', new
+ sx, sy = new
+ self.data[0][0] = sx
+ self.data[1][1] = sy
+
+
+ def _data_changed(self, old, new):
+ #print 'data change', new
+
+ sx, b, tx = self.data[0]
+ c, sy, ty = self.data[1]
+
+ self.translate = tx, ty
+ self.scale = sx, sy
+ self.vec6 = sx, b, c, sy, tx, ty
+ 
+ 
+ def __mul__(self, other):
+ if isinstance(other, Affine):
+ new = Affine()
+ new.data = npy.dot(self.data, other.data)
+ return new
+ elif isinstance(other, npy.ndarray):
+ return npy.dot(self.data, other)
+ raise TypeError('Do not know how to multiply Affine by %s'%type(other))
+ 
+
+ def __repr__(self):
+ 
+ return 'AFFINE:\n%s'%self.data
+
+ 
 class ColorHandler(traits.TraitHandler):
 """
 This is a clever little traits mechanism -- users can specify the
@@ -39,8 +119,8 @@
 
 c = C()
 c.fillcolor = 'red'
- print c.fillcolor
- print c.fillcolor_ # 
+ print c.fillcolor # prints red
+ print c.fillcolor_ # print (1,0,0,1)
 """
 is_mapped = True
 
@@ -49,9 +129,9 @@
 
 def mapped_value(self, value ):
 if value is None: return None
+ if is_string_like(value): value = value.lower()
 return mcolors.colorConverter.to_rgba(value)
- 
- 
+ 
 def validate(self, object, name, value):
 try:
 self.mapped_value(value)
@@ -68,8 +148,9 @@
 
 class MTraitsNamespace:
 DPI = traits.Float(72.)
- Affine = traits.Array('d', (3,3), npy.array([[1,0,0],[0,1,0],[0,0,1]], npy.float_))
+
 Alpha = traits.Range(0., 1., 0.)
+ Affine = traits.Trait(Affine())
 AntiAliased = traits.true
 Codes = traits.Array('b', value=npy.array([0,0], dtype=npy.uint8))
 Color = traits.Trait('black', ColorHandler())
@@ -82,54 +163,39 @@
 'p', '1', '2', '3', '4')
 MarkerSize = traits.Float(6)
 Verts = traits.Array('d', value=npy.array([[0,0],[0,0]], npy.float_))
- PathData = traits.Tuple(Codes, Verts)
+ PathData = traits.Tuple(Codes(), Verts())
 Visible = traits.true
 
 
 mtraits = MTraitsNamespace()
 
 
-def affine_axes(rect):
- 'make an affine for a typical l,b,w,h axes rectangle'
- l,b,w,h = rect
- return npy.array([[w, 0, l], [0, h, b], [0, 0, 1]], dtype=npy.float_)
+ 
+ 
+ 
 
-def affine_identity():
- return npy.array([[1,0,0],
- [0,1,0],
- [0,0,1]],
- dtype=npy.float_)
 
-def affine_translation(tx, ty):
- return npy.array([[1,0,tx],
- [0,1,ty],
- [0,0,1]],
- dtype=npy.float_)
+class Renderer(traits.HasTraits):
+ dpi = mtraits.DPI
+ size = traits.Tuple(traits.Int(600), traits.Int(400))
 
-def affine_rotation(theta):
- a = npy.cos(theta)
- b = -npy.sin(theta)
- c = npy.sin(theta)
- d = npy.cos(theta)
- 
- return npy.array([[a,b,0],
- [c,d,0],
- [0,0,1]],
- dtype=npy.float_)
+ affinerenderer = mtraits.Affine
 
+ def __init__(self, size=(600,400)):
 
-class Renderer(traits.HasTraits):
- dpi = traits.Float(72.)
- 
- def __init__(self, width, height):
- self.width, self.height = width, height
+ self.pathd = dict() # path id -> Path instance
+ self.markersd = dict() # path id -> Markers instance
 
+ self._size_changed(None, size)
+ 
+ def _size_changed(self, old, new):
+ width, height = new
+
 # almost all renderers assume 0,0 is left, upper, so we'll flip y here by default
- self.affinerenderer = npy.array(
- [[width, 0, 0], [0, -height, height], [0, 0, 1]], dtype=npy.float_)
- self.pathd = dict() # dict mapping path id -> Path instance
- self.markersd = dict() # dict mapping path id -> Markers instance
+ self.affinerenderer.translate = 0, height
+ self.affinerenderer.scale = width, -height
 
+ 
 
 def add_path(self, pathid, path):
 self.pathd[pathid] = path
@@ -156,9 +222,11 @@
 blue = agg.rgba8(0,0,255,255)
 black = agg.rgba8(0,0,0,0)
 
- def __init__(self, width, height):
- Renderer.__init__(self, width, height)
- 
+
+ def _size_changed(self, old, new):
+ Renderer._size_changed(self, old, new)
+
+ width, height = self.size
 stride = width*4
 self.buf = buf = agg.buffer(width, height, stride)
 
@@ -198,13 +266,11 @@
 render_scanlines = agg.render_scanlines_bin_rgba
 
 
- affine = npy.dot(self.affinerenderer, path.affine)
+ affine = self.affinerenderer * path.affine
 #print 'display affine:\n', self.affinerenderer
 #print 'path affine:\n', path.affine
 #print 'product affine:\n', affine
- a, b, tx = affine[0]
- c, d, ty = affine[1]
- aggaffine = agg.trans_affine(a,b,c,d,tx,ty)
+ aggaffine = agg.trans_affine(*affine.vec6)
 transpath = agg.conv_transform_path(path.agg_path, aggaffine)
 
 if path.fillcolor is not None:
@@ -235,13 +301,14 @@
 
 
 
- affineverts = npy.dot(self.affinerenderer, markers.affine)
+ affineverts = self.affinerenderer * markers.affine
 
 Nmarkers = markers.verts.shape[0]
 Locs = npy.ones((3, Nmarkers))
 Locs[0] = markers.verts[:,0]
 Locs[1] = markers.verts[:,1] 
- Locs = npy.dot(affineverts, Locs)
+
+ Locs = affineverts * Locs
 
 
 dpiscale = self.dpi/72. # for some reason this is broken 
@@ -280,7 +347,8 @@
 # we'll cheat a little and use pylab for display
 
 X = npy.fromstring(self.buf.to_string(), npy.uint8)
- X.shape = self.height, self.width, 4
+ width, height = self.size
+ X.shape = height, width, 4
 if 1:
 import pylab
 fig = pylab.figure()
@@ -353,22 +421,17 @@
 alpha = mtraits.Alpha(1.0)
 linewidth = mtraits.LineWidth(1.0)
 antialiased = mtraits.AntiAliased
- pathdata = mtraits.PathData()
- affine = mtraits.Affine()
+ pathdata = mtraits.PathData
+ affine = mtraits.Affine
 
 def __init__(self):
 
 # this is a quick workaround to deal with the problem that
 # traits inited at the class level are shared between
 # instances, which is not what I want
- self.strokecolor = 'black'
- self.fillcolor = 'blue'
- self.affine = affine_identity()
 self.pathdata = (npy.array([0,0], npy.uint8), # codes
 npy.array([[0,0], [0,0]])) # verts
 
-mtraits.Path = traits.Trait(Path())
-
 class AggPath(Path):
 
 def __init__(self, path):
@@ -432,20 +495,17 @@
 rgba = [int(255*c) for c in color]
 return agg.rgba8(*rgba)
 
+
+mtraits.Path = traits.Instance(Path, ())
 class Markers(traits.HasTraits):
- verts = mtraits.Verts() # locations to draw the markers at
- path = mtraits.Path() # marker path in points
- affine = mtraits.Affine() # transformation for the verts
+ verts = mtraits.Verts # locations to draw the markers at
+ path = mtraits.Path # marker path in points
+ affine = mtraits.Affine # transformation for the verts
 x = traits.Float(1.0)
 
- def __init__(self):
- # this is a quick workaround to prevent sharing obs; see Path
- self.verts = npy.array([[0,0], [0,0]], npy.float_)
- self.path = Path()
- self.affine = affine_identity()
 
 
-mtraits.Markers = traits.Trait(Markers())
+mtraits.Markers = traits.Instance(Markers, ())
 # coordinates:
 #
 # artist model : a possibly nonlinear transformation (Func instance)
@@ -491,12 +551,12 @@
 zorder = traits.Float(1.0)
 alpha = mtraits.Alpha()
 visible = mtraits.Visible()
- affine = mtraits.Affine()
+ affine = mtraits.Affine
 
 def __init__(self):
 self.artistid = artistID()
 self.renderer = None
- self.affine = affine_identity()
+
 
 def set_renderer(self, renderer):
 self.renderer = renderer
@@ -519,9 +579,9 @@
 markeredgecolor = mtraits.Color('black')
 markeredgewidth = mtraits.LineWidth(0.5)
 markersize = mtraits.MarkerSize(6.0)
- path = mtraits.Path()
- markers = mtraits.Markers()
- X = mtraits.Verts()
+ path = mtraits.Path
+ markers = mtraits.Markers
+ X = mtraits.Verts
 model = mtraits.Model
 zorder = traits.Float(2.0)
 
@@ -536,14 +596,7 @@
 # which attrs may be shared and hence have to be initialized
 # and which ones don't. Eg, if you comment out the self.path
 # init, the code breaks
- self.color = 'blue'
- self.markerfacecolor = 'blue'
- self.markeredgecolor = 'black'
- self.path = Path()
- self.markers = Markers()
- self.X = npy.array([[0,1], [0,1]], npy.float_)
- self.model = Identity()
- #self.model = None # switch comments with above to reveal bug 
+
 
 self.sync_trait('linewidth', self.path, 'linewidth', mutual=False)
 self.sync_trait('color', self.path, 'strokecolor', mutual=False)
@@ -623,20 +676,16 @@
 
 
 class Rectangle(Artist):
- facecolor = mtraits.Color('Yellow')
- edgecolor = mtraits.Color('Black')
+ facecolor = mtraits.Color('yellow')
+ edgecolor = mtraits.Color('black')
 edgewidth = mtraits.LineWidth(1.0)
 lbwh = traits.Array('d', (4,), [0,0,1,1])
- path = mtraits.Path()
+ path = mtraits.Path
 zorder = traits.Float(1.0)
 
 def __init__(self):
 Artist.__init__(self)
- self.facecolor = 'yellow'
- self.edgecolor = 'black'
- self.edgewidth = 1.0
- self.lbwh = 0,0,1,1
- self.path = Path()
+
 
 self.sync_trait('facecolor', self.path, 'fillcolor', mutual=False)
 self.sync_trait('edgecolor', self.path, 'strokecolor', mutual=False)
@@ -694,41 +743,34 @@
 
 
 class AxesCoords(traits.HasTraits):
- xviewlim = mtraits.Interval()
- yviewlim = mtraits.Interval()
- affineview = mtraits.Affine()
- affineaxes = mtraits.Affine() 
- affine = mtraits.Affine() 
-
- def __init__(self):
- self.xviewlim = npy.array([0., 1.])
- self.yviewlim = npy.array([0., 1.])
- self.affineview = affine_identity()
- self.affineaxes = affine_identity()
- self.affine = affine_identity() 
+ xviewlim = mtraits.Interval
+ yviewlim = mtraits.Interval
+ affineview = mtraits.Affine
+ affineaxes = mtraits.Affine 
+ affine = mtraits.Affine 
 
 def _affineview_changed(self, old, new):
- self.affine = npy.dot(self.affineaxes, new)
+ self.affine = self.affineaxes * new
 
 def _affineaxes_changed(self, old, new):
- self.affine = npy.dot(new, self.affineview)
+ self.affine = new * self.affineview
 
 def _xviewlim_changed(self, old, new):
 
 xmin, xmax = new
 scale = 1./(xmax-xmin)
 tx = -xmin*scale
- self.affineview[0][0] = scale
- self.affineview[0][-1] = tx
- self.affine = npy.dot(self.affineaxes, self.affineview)
+ self.affineview.data[0][0] = scale
+ self.affineview.data[0][-1] = tx
+ self.affine = self.affineaxes * self.affineview
 
 def _yviewlim_changed(self, old, new):
 ymin, ymax = new
 scale = 1./(ymax-ymin)
 ty = -ymin*scale
- self.affineview[1][1] = scale
- self.affineview[1][-1] = ty
- self.affine = npy.dot(self.affineaxes, self.affineview)
+ self.affineview.data[1][1] = scale
+ self.affineview.data[1][-1] = ty
+ self.affine = self.affineaxes * self.affineview
 
 
 x1 = npy.arange(0, 10., 0.05)
@@ -737,9 +779,10 @@
 y2 = 10*npy.exp(-x1)
 
 # the axes rectangle
-axrect1 = [0.1, 0.1, 0.4, 0.4]
 coords1 = AxesCoords()
-coords1.affineaxes = affine_axes(axrect1)
+coords1.affineaxes = Affine()
+coords1.affineaxes.scale = 0.4, 0.4
+coords1.affineaxes.translate = 0.1, 0.1
 
 fig = Figure()
 
@@ -767,11 +810,12 @@
 
 
 if 1:
- axrect2 = [0.55, 0.55, 0.4, 0.4]
 coords2 = AxesCoords()
- coords2.affineaxes = affine_axes(axrect2)
+ coords2.affineaxes = Affine()
+ coords2.affineaxes.scale = 0.4, 0.4
+ coords2.affineaxes.translate = 0.55, 0.55
+ 
 
-
 r = npy.arange(0.0, 1.0, 0.01)
 theta = r*4*npy.pi
 
@@ -796,7 +840,7 @@
 
 
 if 1:
- renderer = RendererAgg(600,400)
+ renderer = RendererAgg()
 fig.set_renderer(renderer)
 fig.draw()
 renderer.show()
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 3599
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3599&view=rev
Author: jdh2358
Date: 2007年07月20日 16:45:24 -0700 (2007年7月20日)
Log Message:
-----------
refactored affines abd artists
Modified Paths:
--------------
 trunk/matplotlib/mpl1/mpl1.py
Modified: trunk/matplotlib/mpl1/mpl1.py
===================================================================
--- trunk/matplotlib/mpl1/mpl1.py	2007年07月20日 23:11:17 UTC (rev 3598)
+++ trunk/matplotlib/mpl1/mpl1.py	2007年07月20日 23:45:24 UTC (rev 3599)
@@ -46,50 +46,187 @@
 rather DO
 
 a.translate_delta(10, 20)
+
+ Multiplication works as expected:
+
+ a1 = Affine()
+ a1.scale = 10, 20
+ a2 = Affine()
+ a2.scale = 4, 5
+ print a1*a2
+
+ x = numpy.random(3, 10)
+ print a1*x
+
+ All of the translate, scale, xlim, ylim and vec6 properties are
+ simply views into the data matrix, and are updated by reference
 """
- data = traits.Array('d', (3,3), npy.array([[1,0,0],[0,1,0],[0,0,1]], npy.float_))
+ # connect to the data_modified event if you want a callback
+ data = traits.Array('d', (3,3))
 
- translate = traits.Array('d', (2,), [0,0])
- scale = traits.Array('d', (2,), [0,0])
- vec6 = traits.Array('d', (6,), [1,0,0,1,0,0])
+ translate = traits.Property(traits.Array('d', (2,)))
+ scale = traits.Property(traits.Array('d', (2,))) 
+ vec6 = traits.Property(traits.Array('d', (6,)))
 
- def translate_delta(self, tx, ty):
- oldtx, oldty = self.translate
- self.translate = oldtx + tx, oldty + ty
+ xlim = traits.Property(traits.Array('d', (2,)))
+ ylim = traits.Property(traits.Array('d', (2,))) 
+
+ #data_modified = traits.Event 
+
+ def _data_default(self):
+ return npy.array([[1,0,0],[0,1,0],[0,0,1]], npy.float_)
+
+
+ def _get_xlim(self):
+ sx, b, tx = self.data[0]
+
+ return self._get_lim(sx, tx)
+
+ def _set_xlim(self, xlim):
+ xmin, xmax = xlim
+
+ oldsx, oldb, oldtx = self.data[0]
 
- def _translate_changed(self, old, new):
- #print 'translate change', new
- tx, ty = new
- self.data[0][-1] = tx
- self.data[1][-1] = ty
- self.vec6[-2:] = tx, ty
- 
- def _vec6_changed(self, old, new):
- #print 'vec6 change', new
- sx, b, c, sy, tx, ty = new
- self.data[0] = sx, b, tx
- self.data[1] = c, sy, ty
- self.translate = tx, ty
- self.scale = sx, sy
+ sx = 1./(xmax-xmin)
+ tx = -xmin*sx
+
+ forward = oldsx!=sx or oldtx!=tx
+ if forward:
+ old = self.data.copy()
+ self.data[0][0] = sx
+ self.data[0][-1] = tx
+ self._data_changed(old, self.data)
+
+ def _get_ylim(self):
+ c, sy, ty = self.data[1]
+
+ return self._get_lim(sy, ty)
+
+ def _set_ylim(self, ylim):
+ ymin, ymax = ylim
+
+ oldc, oldsy, oldty = self.data[1]
 
- def _scale_changed(self, old, new):
- #print 'scale change', new
- sx, sy = new
- self.data[0][0] = sx
- self.data[1][1] = sy
+ sy = 1./(ymax-ymin)
+ ty = -ymin*sy
 
+ forward = oldsy!=sy or oldty!=ty
+ if forward:
+ old = self.data.copy()
+ self.data[1][1] = sy
+ self.data[1][-1] = ty
+ self._data_changed(old, self.data)
+ 
 
+ def _get_translate(self):
+ return [self.data[0][-1], self.data[1][-1]]
+
+ def _set_translate(self, s):
+ oldtx = self.data[0][-1]
+ oldty = self.data[1][-1] 
+ 
+ tx, ty = s
+
+ forward = tx!=oldtx or ty!=oldty
+ if forward:
+ old = self.data.copy()
+ self.data[0][-1] = tx
+ self.data[1][-1] = ty
+ self._data_changed(old, self.data)
+
+ def _get_scale(self):
+ return [self.data[0][0], self.data[1][1]]
+
+ def _set_scale(self, s):
+ oldsx = self.data[0][0]
+ oldsy = self.data[1][1] 
+ 
+ sx, sy = s
+
+ forward = sx!=oldsx or sy!=oldsy
+ if forward:
+ old = self.data.copy()
+ self.data[0][0] = sx
+ self.data[1][1] = sy
+ self._data_changed(old, self.data)
+ 
+ def _get_vec6(self):
+ a,b,tx = self.data[0]
+ c,d,ty = self.data[1]
+ return [a,b,c,d,tx,ty]
+
+ def _set_vec6(self, v):
+ a,b,c,d,tx,ty = v
+
+ olda, oldb, oldtx = self.data[0]
+ oldc, oldd, oldty = self.data[1]
+
+ forward = a!=olda or b!=oldb or c!=oldc or d!=oldd or tx!=oldtx or ty!=oldty
+ if forward:
+ old = self.data.copy()
+ self.data[0] = a,b,tx
+ self.data[1] = c,d,ty
+ self._data_changed(old, self.data)
+ 
+
+ def _get_lim(self, s, t):
+ lmin = -t/s
+ lmax = 1./s + lmin
+ return lmin, lmax
+ 
 def _data_changed(self, old, new):
- #print 'data change', new
+ # Make it known if the translate changed
+ oldtx, oldty = old[0][-1], old[1][-1]
+ tx, ty = new[0][-1], new[1][-1]
 
- sx, b, tx = self.data[0]
- c, sy, ty = self.data[1]
+ oldsx, oldsy = old[0][0], old[1][1]
+ sx, sy = new[0][0], new[1][1]
 
- self.translate = tx, ty
- self.scale = sx, sy
- self.vec6 = sx, b, c, sy, tx, ty
+
+ oldb, oldc = old[0][1], old[1][0]
+ b, c = new[0][1], new[1][0]
+
+ tchanged = False
+ schanged = False
+ vchanged = False
+
+ tchanged = oldtx!=tx or oldty!=ty
+ schanged = oldsx!=sx or oldsy!=sy
+ vchanged = tchanged or schanged or b!=oldb or c!=oldc
+ xchanged = oldtx!=tx or oldsx!=sx
+ ychanged = oldty!=ty or oldsy!=sy 
 
+ if tchanged:
+ self.trait_property_changed('translate', [oldtx, oldty], [tx, ty])
+
+ if schanged:
+ self.trait_property_changed('scale', [oldsx, oldsy], [sx, sy])
+
+ if xchanged:
+ oldxmin, oldxmax = self._get_lim(oldsx, oldtx)
+ xmin, xmax = self._get_lim(sx, tx) 
+ self.trait_property_changed('xlim', [oldxmin, oldxmax], [xmin, xmax])
+
+ if ychanged:
+ oldymin, oldymax = self._get_lim(oldsy, oldty)
+ ymin, ymax = self._get_lim(sy, ty) 
+ self.trait_property_changed('ylim', [oldymin, oldymax], [ymin, ymax])
+
+ if vchanged:
+ self.trait_property_changed(
+ 'vec6',
+ [oldsx, oldb, oldc, oldsy, oldtx, oldty],
+ [sx, b, c, sy, tx, ty])
+ 
+ if tchanged or schanged or vchanged:
+ #self._data_modified = True 
+ self.trait_property_changed('data_modified', old, new)
+
 
+ def follow(self, othervec6):
+ self.vec6 = othervec6
+
+ 
 def __mul__(self, other):
 if isinstance(other, Affine):
 new = Affine()
@@ -101,9 +238,10 @@
 
 
 def __repr__(self):
- 
- return 'AFFINE:\n%s'%self.data
+ return 'AFFINE: %s'%', '.join([str(val) for val in self.vec6])
+ #return 'AFFINE:\n%s'%self.data
 
+
 
 class ColorHandler(traits.TraitHandler):
 """
@@ -169,17 +307,11 @@
 
 mtraits = MTraitsNamespace()
 
- 
- 
- 
- 
-
-
 class Renderer(traits.HasTraits):
 dpi = mtraits.DPI
 size = traits.Tuple(traits.Int(600), traits.Int(400))
 
- affinerenderer = mtraits.Affine
+ adisplay = traits.Instance(Affine, ()) 
 
 def __init__(self, size=(600,400)):
 
@@ -192,12 +324,15 @@
 width, height = new
 
 # almost all renderers assume 0,0 is left, upper, so we'll flip y here by default
- self.affinerenderer.translate = 0, height
- self.affinerenderer.scale = width, -height
+ self.adisplay.translate = 0, height
+ self.adisplay.scale = width, -height
 
 
 
 def add_path(self, pathid, path):
+ # todo, we could use a traits dict here
+ if not isinstance(path, Path):
+ raise TypeError('add_path takes an ID and a Path instance')
 self.pathd[pathid] = path
 
 def remove_path(self, pathid):
@@ -205,6 +340,9 @@
 del self.pathd[pathid]
 
 def add_markers(self, markersid, markers):
+ # todo, we could use a traits dict here
+ if not isinstance(markers, Markers):
+ raise TypeError('add_markers takes an ID and a Markers instance')
 self.markersd[markersid] = markers
 
 def remove_markers(self, markersid):
@@ -266,8 +404,8 @@
 render_scanlines = agg.render_scanlines_bin_rgba
 
 
- affine = self.affinerenderer * path.affine
- #print 'display affine:\n', self.affinerenderer
+ affine = self.adisplay * path.affine
+ #print 'display affine:\n', self.adisplay
 #print 'path affine:\n', path.affine
 #print 'product affine:\n', affine
 aggaffine = agg.trans_affine(*affine.vec6)
@@ -301,7 +439,7 @@
 
 
 
- affineverts = self.affinerenderer * markers.affine
+ affineverts = self.adisplay * markers.affine
 
 Nmarkers = markers.verts.shape[0]
 Locs = npy.ones((3, Nmarkers))
@@ -422,7 +560,7 @@
 linewidth = mtraits.LineWidth(1.0)
 antialiased = mtraits.AntiAliased
 pathdata = mtraits.PathData
- affine = mtraits.Affine
+ affine = traits.Instance(Affine, ())
 
 def __init__(self):
 
@@ -451,8 +589,11 @@
 path.sync_trait('linewidth', self, mutual=False)
 path.sync_trait('antialiased', self, mutual=False)
 path.sync_trait('pathdata', self, mutual=False)
- path.sync_trait('affine', self, mutual=False)
 
+ path.on_trait_change(self.affine.follow, 'vec6')
+
+
+
 # hmm, I would have thought these would be called by the attr
 # setting above
 self._pathdata_changed(None, self.pathdata)
@@ -500,10 +641,10 @@
 class Markers(traits.HasTraits):
 verts = mtraits.Verts # locations to draw the markers at
 path = mtraits.Path # marker path in points
- affine = mtraits.Affine # transformation for the verts
- x = traits.Float(1.0)
+ affine = traits.Instance(Affine, ()) # transformation for the verts
 
 
+
 
 mtraits.Markers = traits.Instance(Markers, ())
 # coordinates:
@@ -512,16 +653,16 @@
 # to a separable cartesian coordinate, eg for polar is takes r,
 # theta -> r*cos(theta), r*sin(theta)
 #
-# AxesCoords.affineview : an affine 3x3 matrix that takes model output and
+# AxesCoords.adata : an affine 3x3 matrix that takes model output and
 # transforms it to axes 0,1. We are kind of stuck with the
 # mpl/matlab convention that 0,0 is the bottom left of the axes,
 # even though it contradicts pretty much every GUI layout in the
 # world
 #
-# AxesCoords.affineaxes: an affine 3x3 that transforms an axesview into figure
+# AxesCoords.aview: an affine 3x3 that transforms an axesview into figure
 # 0,1 
 #
-# Renderer.affinerenderer : takes an affine 3x3 and puts figure view into display. 0,
+# Renderer.adisplay : takes an affine 3x3 and puts figure view into display. 0,
 # 0 is left, top, which is the typical coordinate system of most
 # graphics formats
 
@@ -551,22 +692,77 @@
 zorder = traits.Float(1.0)
 alpha = mtraits.Alpha()
 visible = mtraits.Visible()
- affine = mtraits.Affine
+
+ adata = traits.Instance(Affine, ()) # the data affine
+ aview = traits.Instance(Affine, ()) # the view affine
 
+ affine = traits.Instance(Affine, ()) # the product of the data and view affine
+
+ renderer = traits.Trait(None, Renderer)
+
+ 
 def __init__(self):
 self.artistid = artistID()
- self.renderer = None
+ self.artistd = dict()
 
- 
- def set_renderer(self, renderer):
- self.renderer = renderer
+ # track affine as the product of the view and the data affines
+ # -- this should be a property, but I had trouble making a
+ # property on my custom class affine so this is a workaround
+ def product(ignore):
+ # modify in place
+ self.affine.follow((self.aview * self.adata).vec6)
+ product(None) # force an affine product updated
+ self.adata.on_trait_change(product, 'vec6')
+ self.aview.on_trait_change(product, 'vec6') 
 
+
+ def _get_affine(self):
+ return self.aview * self.adata
+ 
+ def add_artist(self, artist, followdata=True, followview=True): 
+ # this is a very interesting change from matplotlib -- every
+ # artist acts as a container that can hold other artists, and
+ # respects zorder drawing internally. This makes zordering
+ # much more flexibel
+ self.artistd[artist.artistid] = artist
+ artist.renderer = self.renderer
+
+ artist.followdata = followdata
+ artist.followview = followview
+ if followdata:
+ # set the data affines to be the same
+ artist.adata.follow(self.adata.vec6)
+ self.adata.on_trait_change(artist.adata.follow, 'vec6')
+
+ if followview:
+ # set the view affines to be the same
+ artist.aview.follow(self.aview.vec6)
+ self.aview.on_trait_change(artist.aview.follow, 'vec6')
+
+
+ self.sync_trait('renderer', artist, mutual=False)
+
+ def remove_artist(self, artist):
+
+ if artist.followview:
+ self.aview.on_trait_change(artist.aview.follow, 'vec6', remove=True)
+ del artist.followview
+ 
+ if artist.followdata:
+ self.adata.on_trait_change(artist.adata.follow, 'vec6', remove=True)
+ del artist.followdata
+
+ self.sync_trait('renderer', artist, remove=True)
+ del self.artistd[artist.artistid] 
+
 def draw(self):
- pass
+ if self.renderer is None or not self.visible: return
 
- def setp(self, **kwargs):
- for k, v in kwargs.items():
- setattr(self, k, v)
+ dsu = [(artist.zorder, artist.artistid, artist) for artist in self.artistd.values()]
+ dsu.sort()
+ for zorder, artistid, artist in dsu:
+ artist.draw()
+
 
 class Line(Artist):
 
@@ -603,9 +799,16 @@
 self.sync_trait('markerfacecolor', self.markers.path, 'fillcolor', mutual=False)
 self.sync_trait('markeredgecolor', self.markers.path, 'strokecolor', mutual=False)
 self.sync_trait('markeredgewidth', self.markers.path, 'linewidth', mutual=False) 
- self.sync_trait('affine', self.markers, mutual=False)
- self.sync_trait('affine', self.path, mutual=False)
 
+ # sync up the markers affine
+ self.markers.affine.follow(self.affine.vec6)
+ self.affine.on_trait_change(self.markers.affine.follow, 'vec6')
+
+ # sync up the path affine
+ self.path.affine.follow(self.affine.vec6)
+ self.affine.on_trait_change(self.path.affine.follow, 'vec6')
+ 
+
 self.path.fillcolor = None
 
 self.pathid = primitiveID()
@@ -616,39 +819,44 @@
 } 
 
 def draw(self):
- if self.renderer is None:
- raise RuntimeError('First call set_renderer')
 
- if not self.visible: return
+ if self.renderer is None or not self.visible: return
+ Artist.draw(self)
 
-
 if self.linestyle is not None:
 self.renderer.render_path(self.pathid)
 if self.marker is not None:
 self.renderer.render_markers(self.markerid) 
 
 
- def set_renderer(self, renderer):
- if self.renderer is not None:
- self.renderer.remove_path(self.pathid)
- self.renderer.remove_markers(self.markerid)
+ def _renderer_changed(self, old, new):
+ if old is not None:
+ old.remove_path(self.pathid)
+ old.remove_markers(self.markerid)
 
- renderer.add_path(self.pathid, self.path)
- renderer.add_markers(self.markerid, self.markers) 
+ if new is not None:
+ new.add_path(self.pathid, self.path)
+ new.add_markers(self.markerid, self.markers) 
 
- Artist.set_renderer(self, renderer)
 
- def _X_changed(self, old, newx):
- N = newx.shape[0]
+ def _model_changed(self, old, new):
+ self._update_data()
+
+ def _X_changed(self, old, new):
+ self._update_data()
+ 
+ def _update_data(self):
+ N = self.X.shape[0]
 codes = Path.LINETO*npy.ones(N, dtype=npy.uint8)
 codes[0] = Path.MOVETO
 
 # todo, having touble setting Model to default to Identity so
 # allowing None as a hack workaround
+ #print 'X changed', self.model
 if self.model is not None:
- modelx = self.model(newx)
+ modelx = self.model(self.X)
 else:
- modelx = newx
+ modelx = self.X
 self.path.pathdata = codes, modelx
 self.markers.verts = modelx
 
@@ -674,6 +882,7 @@
 
 self.markers.path.pathdata = codes, verts
 
+mtraits.Line = traits.Instance(Line, ())
 
 class Rectangle(Artist):
 facecolor = mtraits.Color('yellow')
@@ -690,11 +899,15 @@
 self.sync_trait('facecolor', self.path, 'fillcolor', mutual=False)
 self.sync_trait('edgecolor', self.path, 'strokecolor', mutual=False)
 self.sync_trait('edgewidth', self.path, 'linewidth', mutual=False)
- self.sync_trait('affine', self.path, mutual=False)
 
 self.pathid = primitiveID()
+ # sync up the path affine
+ self.path.affine.follow(self.affine.vec6)
+ self.affine.on_trait_change(self.path.affine.follow, 'vec6')
 
 
+
+
 def _lbwh_changed(self, old, new):
 l,b,w,h = new
 t = b+h
@@ -706,141 +919,127 @@
 
 self.path.pathdata = codes, verts
 
- def set_renderer(self, renderer):
- if self.renderer is not None:
- self.renderer.remove_path(self.pathid)
+ def _renderer_changed(self, old, new):
+ if old is not None:
+ old.remove_path(self.pathid)
 
- renderer.add_path(self.pathid, self.path)
- Artist.set_renderer(self, renderer)
+ if new is not None:
+ new.add_path(self.pathid, self.path)
 
 def draw(self):
- if self.renderer is None:
- raise RuntimeError('First call set_renderer')
-
- if not self.visible: return
+ if self.renderer is None or not self.visible: return
+ Artist.draw(self)
 self.renderer.render_path(self.pathid)
- 
-class Figure:
- def __init__(self):
- self.renderer = None
- self.artistd = dict()
 
- def draw(self):
- if self.renderer is None:
- raise RuntimeError('call set_renderer renderer first')
 
- dsu = [(artist.zorder, artist.artistid, artist) for artist in self.artistd.values()]
- dsu.sort()
- for zorder, artistid, artist in dsu:
- artist.draw()
- 
- def set_renderer(self, renderer):
- self.renderer = renderer
+mtraits.Rectangle = traits.Instance(Rectangle, ()) 
 
- for artist in self.artistd.values():
- artist.set_renderer(renderer)
+class Figure(Artist):
+ pass
+
+
+
+class Axes(Artist):
+ zorder = traits.Float(0.5)
 
+ xtickmarkers = mtraits.Markers
+ xaxisline = mtraits.Line
+ xticklocs = traits.Array('d')
+ xaxislocy = traits.Float(0.) # the y location of the x-axis
 
+ ytickmarkers = mtraits.Markers
+ yaxisline = mtraits.Line
+ yticklocs = traits.Array('d')
+ yaxislocx = traits.Float(0.) # the x location of the y-axis
 
-class AxesCoords(traits.HasTraits):
- xviewlim = mtraits.Interval
- yviewlim = mtraits.Interval
- affineview = mtraits.Affine
- affineaxes = mtraits.Affine 
- affine = mtraits.Affine 
- 
- def _affineview_changed(self, old, new):
- self.affine = self.affineaxes * new
+ def __init__(self):
+ Artist.__init__(self)
+ self.xtickmarkersid = primitiveID()
 
- def _affineaxes_changed(self, old, new):
- self.affine = new * self.affineview
- 
- def _xviewlim_changed(self, old, new):
+ self.xtickmarkers.affine.follow(self.adata.vec6)
+ self.adata.on_trait_change(self.xtickmarkers.affine.follow, 'vec6')
 
- xmin, xmax = new
- scale = 1./(xmax-xmin)
- tx = -xmin*scale
- self.affineview.data[0][0] = scale
- self.affineview.data[0][-1] = tx
- self.affine = self.affineaxes * self.affineview
+ def _xticklocs_changed(self, old, new):
+ self._update_xtick_markers()
+
+ def _xaxislocy_changed(self, old, new):
+ self._update_xtick_markers()
 
- def _yviewlim_changed(self, old, new):
- ymin, ymax = new
- scale = 1./(ymax-ymin)
- ty = -ymin*scale
- self.affineview.data[1][1] = scale
- self.affineview.data[1][-1] = ty
- self.affine = self.affineaxes * self.affineview
- 
+ def _update_xtick_markers(self):
+ verts = self.xaxislocy*npy.ones(len(new))
+ verts[:,1] = new
+ self.xtickmarkers.verts = verts
 
+
+ def _renderer_changed(self, old, new):
+ if old is not None:
+ old.remove_markers(self.xtickmarkersid)
+
+ if new is not None:
+ new.add_markers(self.xtickmarkersid, self.xtickmarkers) 
+
+ def draw(self):
+ if self.renderer is None or not self.visible: return
+ #print 'Axes data affine:\n', self.adata
+ #print 'Axes view affine :\n', self.aview
+ #print 'Axes affine :\n', self.affine 
+ Artist.draw(self)
+ self.renderer.render_markers(self.xtickmarkersid)
+
 x1 = npy.arange(0, 10., 0.05)
 x2 = npy.arange(0, 10., 0.1)
 y1 = npy.cos(2*npy.pi*x1)
 y2 = 10*npy.exp(-x1)
 
-# the axes rectangle
-coords1 = AxesCoords()
-coords1.affineaxes = Affine()
-coords1.affineaxes.scale = 0.4, 0.4
-coords1.affineaxes.translate = 0.1, 0.1
-
 fig = Figure()
+axes = Axes()
 
-line1 = Line()
-line1.X = npy.array([x1,y1]).T
+axes.aview.scale = 0.4, 0.4
+axes.aview.translate = 0.1, 0.1
 
-line1.setp(color='blue', linewidth=2.0, marker='s', markersize=5.0,
- markerfacecolor='green', markeredgewidth=0.5)
-coords1.sync_trait('affine', line1, mutual=False)
+fig.add_artist(axes, followdata=False, followview=False)
 
-fig.artistd[line1.artistid] = line1
+line1 = Line().set(X=npy.array([x1,y1]).T,
+ color='blue', linewidth=2.0, marker='s', markersize=5.0,
+ markerfacecolor='green', markeredgewidth=0.5)
 
 
-rect1 = Rectangle()
-rect1.lbwh = [0,0,1,1]
-rect1.facecolor = 'white'
-fig.artistd[rect1.artistid] = rect1
-coords1.sync_trait('affineaxes', rect1, 'affine', mutual=False)
+axes.add_artist(line1)
 
 
+rect1 = Rectangle().set(lbwh=[0,0,1,1], facecolor='white')
+axes.add_artist(rect1, followdata=False)
+
+
+
 # update the view limits, all the affines should be automagically updated
-coords1.xviewlim = 0, 10
-coords1.yviewlim = -1.1, 1.1
+axes.adata.xlim = 0, 10
+axes.adata.ylim = -1.1, 1.1
 
 
+if 1:
+ axes2 = Axes()
 
-if 1:
- coords2 = AxesCoords()
- coords2.affineaxes = Affine()
- coords2.affineaxes.scale = 0.4, 0.4
- coords2.affineaxes.translate = 0.55, 0.55
+ axes2.aview.scale = 0.4, 0.4
+ axes2.aview.translate = 0.55, 0.55
 
+ fig.add_artist(axes2, followdata=False, followview=False)
 
 r = npy.arange(0.0, 1.0, 0.01)
 theta = r*4*npy.pi
 
- line2 = Line()
- line2.model = Polar()
- line2.setp(color='#ee8d18', linewidth=2.0)
- line2.X = npy.array([r, theta]).T
- coords2.sync_trait('affine', line2, mutual=False)
+ line2 = Line().set(X=npy.array([r, theta]).T, model=Polar(), color='#ee8d18', linewidth=2.0)
+ axes2.add_artist(line2)
 
- rect2 = Rectangle()
- rect2.lbwh = [0,0,1,1]
- rect2.facecolor = '#d5de9c'
- coords2.sync_trait('affineaxes', rect2, 'affine', mutual=False)
+ rect2 = Rectangle().set(lbwh=[0,0,1,1], facecolor='#d5de9c')
+ axes2.add_artist(rect2, followdata=False)
 
- fig.artistd[line2.artistid] = line2
- fig.artistd[rect2.artistid] = rect2 
+ axes2.adata.xlim = -1.1, 1.1
+ axes2.adata.ylim = -1.1, 1.1 
 
 
- coords2.xviewlim = -1.1, 1.1
- coords2.yviewlim = -1.1, 1.1
-
-
-
 if 1:
 renderer = RendererAgg()
- fig.set_renderer(renderer)
+ fig.renderer = renderer
 fig.draw()
 renderer.show()
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 3601
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3601&view=rev
Author: jdh2358
Date: 2007年07月20日 19:40:51 -0700 (2007年7月20日)
Log Message:
-----------
added axis artists
Modified Paths:
--------------
 trunk/matplotlib/mpl1/mpl1.py
Modified: trunk/matplotlib/mpl1/mpl1.py
===================================================================
--- trunk/matplotlib/mpl1/mpl1.py	2007年07月21日 01:51:44 UTC (rev 3600)
+++ trunk/matplotlib/mpl1/mpl1.py	2007年07月21日 02:40:51 UTC (rev 3601)
@@ -412,6 +412,7 @@
 transpath = agg.conv_transform_path(path.agg_path, aggaffine)
 
 if path.fillcolor is not None:
+ print 'render path', path.fillcolor, path.agg_fillcolor
 self.rasterizer.add_path(transpath)
 renderer.color_rgba8( path.agg_fillcolor )
 render_scanlines(self.rasterizer, scanline, renderer);
@@ -463,8 +464,9 @@
 
 
 for xv,yv,tmp in Locs.T:
- XY[:,0] = pathx + xv
- XY[:,1] = pathy + yv
+ XY[:,0] = (pathx + xv).astype(int) + 0.5
+ XY[:,1] = (pathy + yv).astype(int) + 0.5
+
 
 pathdata = pathcodes, XY
 aggpath = AggPath.make_agg_path(pathdata)
@@ -626,7 +628,7 @@
 self.agg_fillcolor = self.color_to_rgba8(newcolor)
 
 def _strokecolor__changed(self, oldcolor, newcolor): 
-
+ print 'stroke color changed', newcolor
 c = self.color_to_rgba8(newcolor)
 self.agg_strokecolor = c
 
@@ -725,8 +727,11 @@
 # respects zorder drawing internally. This makes zordering
 # much more flexibel
 self.artistd[artist.artistid] = artist
+
 artist.renderer = self.renderer
+ self.sync_trait('renderer', artist, mutual=False)
 
+
 artist.followdata = followdata
 artist.followview = followview
 if followdata:
@@ -740,7 +745,6 @@
 self.aview.on_trait_change(artist.aview.follow, 'vec6')
 
 
- self.sync_trait('renderer', artist, mutual=False)
 
 def remove_artist(self, artist):
 
@@ -761,6 +765,7 @@
 dsu = [(artist.zorder, artist.artistid, artist) for artist in self.artistd.values()]
 dsu.sort()
 for zorder, artistid, artist in dsu:
+ #print 'artist draw', self, artist, zorder
 artist.draw()
 
 
@@ -938,86 +943,198 @@
 pass
 
 
-
-class Axes(Artist):
- zorder = traits.Float(0.5)
+class Axis(Artist):
+ zorder = traits.Float(1.5)
+ tickmarkers = mtraits.Markers
+ linepath = mtraits.Path
+ linecolor = mtraits.Color('black')
+ linewidth = mtraits.LineWidth(1.0)
+ ticklocs = traits.Array('d')
+ ticksize = traits.Float(7.0)
+ ticklinewidth = mtraits.LineWidth(1.0)
+ tickcolor = mtraits.Color('black')
 
- xtickmarkers = mtraits.Markers
- xaxisline = mtraits.Line
- xticklocs = traits.Array('d')
- xaxislocy = traits.Float(0.) # the y location of the x-axis
-
- ytickmarkers = mtraits.Markers
- yaxisline = mtraits.Line
- yticklocs = traits.Array('d')
- yaxislocx = traits.Float(0.) # the x location of the y-axis
-
+ loc = traits.Float(0.) # the y location of the x-axis
+ tickoffset = traits.Float(-0.5) # -1 for outer, -0.5 for centered, 0 for inner
+ 
 def __init__(self):
 Artist.__init__(self)
- self.xtickmarkersid = primitiveID()
+ self.tickmarkersid = primitiveID()
+ self.linepathid = primitiveID()
 
- self.xtickmarkers.affine.follow(self.adata.vec6)
- self.adata.on_trait_change(self.xtickmarkers.affine.follow, 'vec6')
+ self.affine.on_trait_change(self._update_blended_affine, 'vec6')
+ self.tickmarkers.path.antialiased = False
+ self.linepath.antialiased = False 
 
- def _xticklocs_changed(self, old, new):
- self._update_xtick_markers()
+ self.sync_trait('linewidth', self.linepath, mutual=False)
+ self.sync_trait('linecolor', self.linepath, 'strokecolor', mutual=False)
+ self.sync_trait('ticklinewidth', self.tickmarkers.path, 'linewidth', mutual=False)
+ self.sync_trait('tickcolor', self.tickmarkers.path, 'strokecolor', mutual=False)
 
- def _xaxislocy_changed(self, old, new):
- self._update_xtick_markers()
+ # XXX, do we have to manually call these or will they get
+ # calle dautomagically in init
+ self._update_tick_path()
+ self._update_marker_locations()
+ self._update_blended_affine()
+ self._update_linepath()
+ 
+ def _ticklocs_changed(self, old, new):
+ self._update_marker_locations()
+
+ def _loc_changed(self, old, new):
+ self._update_blended_affine()
+ 
+ def _ticksize_changed(self, old, new):
+ self._update_tick_path()
+
+ def _tickoffset_changed(self, old, new):
+ self._update_tick_path(self)
+
+ def _update_blended_affine(self):
+ 'blend of xdata and y axis affine'
+ raise NotImplementedError
 
- def _update_xtick_markers(self):
- verts = self.xaxislocy*npy.ones(len(new))
- verts[:,1] = new
- self.xtickmarkers.verts = verts
+ def _update_marker_locations(self):
+ raise NotImplementedError
+ 
+ def _update_tick_path(self):
+ raise NotImplementedError
 
+ def _update_linepath(self):
+ raise NotImplementedError
 
 def _renderer_changed(self, old, new):
 if old is not None:
- old.remove_markers(self.xtickmarkersid)
+ old.remove_markers(self.tickmarkersid)
+ old.remove_path(self.linepathid) 
 
 if new is not None:
- new.add_markers(self.xtickmarkersid, self.xtickmarkers) 
+ new.add_markers(self.tickmarkersid, self.tickmarkers)
+ new.add_path(self.linepathid, self.linepath) 
 
 def draw(self):
 if self.renderer is None or not self.visible: return
- #print 'Axes data affine:\n', self.adata
- #print 'Axes view affine :\n', self.aview
- #print 'Axes affine :\n', self.affine 
 Artist.draw(self)
- self.renderer.render_markers(self.xtickmarkersid)
+ self.renderer.render_markers(self.tickmarkersid)
+ self.renderer.render_path(self.linepathid) 
 
-x1 = npy.arange(0, 10., 0.05)
-x2 = npy.arange(0, 10., 0.1)
-y1 = npy.cos(2*npy.pi*x1)
-y2 = 10*npy.exp(-x1)
+class XAxis(Axis):
 
-fig = Figure()
-axes = Axes()
+ def _update_blended_affine(self):
+ 'blend of xdata and y axis affine'
+ sx, b, tx = self.adata.data[0]
+ a = Affine()
+ a.vec6 = sx, b, 0, 1, tx, self.loc
+ self.tickmarkers.affine.vec6 = (self.aview * a).vec6
+ 
+ a = Affine()
+ a.translate = 0, self.loc
+ self.linepath.affine.vec6 = (self.aview * a).vec6 
 
-axes.aview.scale = 0.4, 0.4
-axes.aview.translate = 0.1, 0.1
+ def _update_marker_locations(self):
+ Nticks = len(self.ticklocs)
+ verts = self.loc*npy.ones((Nticks,2))
+ verts[:,0] = self.ticklocs
+ self.tickmarkers.verts = verts
 
-fig.add_artist(axes, followdata=False, followview=False)
+ def _update_tick_path(self):
+ codes = Path.MOVETO, Path.LINETO
+ verts = npy.array([[0., self.tickoffset], [0, self.tickoffset+1]])*self.ticksize
+ self.tickmarkers.path.pathdata = codes, verts 
 
-line1 = Line().set(X=npy.array([x1,y1]).T,
- color='blue', linewidth=2.0, marker='s', markersize=5.0,
- markerfacecolor='green', markeredgewidth=0.5)
+ def _update_linepath(self):
+ codes = Path.MOVETO, Path.LINETO
+ X = npy.array([[0, 1], [0, 0]], npy.float_).T
+ self.linepath.pathdata = codes, X
 
+class YAxis(Axis):
 
-axes.add_artist(line1)
 
+ def _update_blended_affine(self):
+ 'blend of xdata and y axis affine'
+ c, sy, ty = self.adata.data[1]
+ a = Affine()
+ a.vec6 = 1, 0, 0, sy, self.loc, ty
+ self.tickmarkers.affine.vec6 = (self.aview * a).vec6
+ 
+ a = Affine()
+ a.translate = self.loc, 0
+ self.linepath.affine.vec6 = (self.aview * a).vec6 
 
-rect1 = Rectangle().set(lbwh=[0,0,1,1], facecolor='white')
-axes.add_artist(rect1, followdata=False)
+ def _update_marker_locations(self):
+ Nticks = len(self.ticklocs)
+ verts = self.loc*npy.ones((Nticks,2))
+ verts[:,1] = self.ticklocs
+ self.tickmarkers.verts = verts
 
+ def _update_tick_path(self):
+ codes = Path.MOVETO, Path.LINETO
+ verts = npy.array([[self.tickoffset,0], [self.tickoffset+1,0]])*self.ticksize
+ self.tickmarkers.path.pathdata = codes, verts 
 
+ def _update_linepath(self):
+ codes = Path.MOVETO, Path.LINETO
+ X = npy.array([[0, 0], [0, 1]], npy.float_).T
+ self.linepath.pathdata = codes, X
 
-# update the view limits, all the affines should be automagically updated
-axes.adata.xlim = 0, 10
-axes.adata.ylim = -1.1, 1.1
 
+class Axes(Artist):
+ zorder = traits.Float(0.5)
+ 
 
-if 1:
+
+ ytickmarkers = mtraits.Markers
+ yaxisline = mtraits.Line
+ yticklocs = traits.Array('d')
+ yticksize = traits.Float(5.0)
+ yaxislocx = traits.Float(0.) # the x location of the y-axis
+
+ 
+
+
+def make_subplot_ll(fig):
+ x1 = npy.arange(0, 10., 0.05)
+ x2 = npy.arange(0, 10., 0.1)
+ y1 = npy.cos(2*npy.pi*x1)
+ y2 = 10*npy.exp(-x1)
+
+
+ axes = Axes()
+ fig.add_artist(axes, followdata=False, followview=False)
+
+ axes.aview.scale = 0.4, 0.4
+ axes.aview.translate = 0.1, 0.1
+
+ xaxis = XAxis()
+ axes.add_artist(xaxis)
+
+ yaxis = YAxis()
+ axes.add_artist(yaxis)
+
+ line1 = Line().set(X=npy.array([x1,y1]).T,
+ color='blue', linewidth=2.0, marker='s', markersize=5.0,
+ markerfacecolor='green', markeredgewidth=0.5)
+
+
+ axes.add_artist(line1)
+
+
+ rect1 = Rectangle().set(lbwh=[0,0,1,1], facecolor='white')
+ axes.add_artist(rect1, followdata=False)
+
+ # update the view limits, all the affines should be automagically updated
+ axes.adata.xlim = 0, 10
+ axes.adata.ylim = -1.1, 1.1
+ xaxis.ticklocs = npy.arange(0., 11., 1.)
+ xaxis.loc = -0.1
+ xaxis.linecolor = 'red'
+
+ yaxis.ticklocs = npy.arange(-1.0, 1.1, 0.2)
+ yaxis.loc = -0.1
+ yaxis.linecolor = 'blue'
+ yaxis.tickcolor = 'blue'
+
+def make_subplot_ur(fig):
 axes2 = Axes()
 
 axes2.aview.scale = 0.4, 0.4
@@ -1038,8 +1155,11 @@
 axes2.adata.ylim = -1.1, 1.1 
 
 
-if 1:
+if __name__=='__main__':
 renderer = RendererAgg()
+ fig = Figure()
 fig.renderer = renderer
+ make_subplot_ll(fig)
+ make_subplot_ur(fig)
 fig.draw()
 renderer.show()
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 3604
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3604&view=rev
Author: jdh2358
Date: 2007年07月22日 09:53:37 -0700 (2007年7月22日)
Log Message:
-----------
added (broken) axis support
Modified Paths:
--------------
 trunk/matplotlib/mpl1/mpl1.py
Modified: trunk/matplotlib/mpl1/mpl1.py
===================================================================
--- trunk/matplotlib/mpl1/mpl1.py	2007年07月21日 23:30:03 UTC (rev 3603)
+++ trunk/matplotlib/mpl1/mpl1.py	2007年07月22日 16:53:37 UTC (rev 3604)
@@ -8,17 +8,18 @@
 wget http://peak.telecommunity.com/dist/ez_setup.py
 sudo python sez_setup.py
 
- sudo easy_install -f http://code.enthought.com/enstaller/eggs/source/unstable "enthought.etsconfig < 3.0a" "enthought.util <3.0a" "enthought.debug <3.0a"
 
- svn co https://svn.enthought.com/svn/enthought/branches/enthought.traits_2.0 enthought_traits
-
- cd enthought_traits/
- sudo python setup.py install 
-
+ sudo rm -rf /usr/local/lib/python2.5/site-packages/enthought*
+ sudo easy_install \
+ -f http://code.enthought.com/enstaller/eggs/source/unstable \
+ "enthought.resource <3.0a" "enthought.traits < 3.0a"
+ 
 """
 
 # see install instructions for enthrought traits2 in mtraits
 import enthought.traits.api as traits
+from enthought.traits.api import HasTraits, Instance, Trait, Float, Int, \
+ Array, Tuple
 
 from matplotlib import agg
 from matplotlib import colors as mcolors
@@ -27,9 +28,10 @@
 
 is_string_like = cbook.is_string_like
 
+## begin core infrastructure
 
 
-class Affine(traits.HasTraits):
+class Affine(HasTraits):
 """
 An affine 3x3 matrix that supports matrix multiplication with
 other Affine instances or numpy arrays.
@@ -62,14 +64,14 @@
 simply views into the data matrix, and are updated by reference
 """
 # connect to the data_modified event if you want a callback
- data = traits.Array('d', (3,3))
+ data = Array('d', (3,3))
 
- translate = traits.Property(traits.Array('d', (2,)))
- scale = traits.Property(traits.Array('d', (2,))) 
- vec6 = traits.Property(traits.Array('d', (6,)))
+ translate = traits.Property(Array('d', (2,)))
+ scale = traits.Property(Array('d', (2,))) 
+ vec6 = traits.Property(Array('d', (6,)))
 
- xlim = traits.Property(traits.Array('d', (2,)))
- ylim = traits.Property(traits.Array('d', (2,))) 
+ xlim = traits.Property(Array('d', (2,)))
+ ylim = traits.Property(Array('d', (2,))) 
 
 #data_modified = traits.Event 
 
@@ -242,18 +244,18 @@
 #return 'AFFINE:\n%s'%self.data
 
 
-class Box(traits.HasTraits):
+class Box(HasTraits):
 # left, bottom, width, height
- bounds = traits.List
- left = traits.Property(traits.Float)
- bottom = traits.Property(traits.Float)
- width = traits.Property(traits.Float) 
- height = traits.Property(traits.Float) 
+ bounds = traits.Array('d', (4,))
+ left = traits.Property(Float)
+ bottom = traits.Property(Float)
+ width = traits.Property(Float) 
+ height = traits.Property(Float) 
 
- right = traits.Property(traits.Float) # read only
- top = traits.Property(traits.Float) # read only
+ right = traits.Property(Float) # read only
+ top = traits.Property(Float) # read only
 
- def ___bounds_default(self):
+ def _bounds_default(self):
 return [0.0, 0.0, 1.0, 1.0]
 
 def _get_left(self):
@@ -295,7 +297,7 @@
 return self.bottom + self.height
 
 def _bounds_changed(self, old, new):
- print 'base bounds changed'
+ pass
 
 class ColorHandler(traits.TraitHandler):
 """
@@ -307,12 +309,12 @@
 Eg
 
 class C(HasTraits):
- fillcolor = traits.Trait('black', ColorHandler())
+ facecolor = Trait('black', ColorHandler())
 
 c = C()
- c.fillcolor = 'red'
- print c.fillcolor # prints red
- print c.fillcolor_ # print (1,0,0,1)
+ c.facecolor = 'red'
+ print c.facecolor # prints red
+ print c.facecolor_ # print (1,0,0,1)
 """
 is_mapped = True
 
@@ -338,40 +340,98 @@
 name like 'orange', a hex color like '#efefef', a grayscale intensity
 like '0.5', or an RGBA tuple (1,0,0,1)"""
 
+
+ 
+
+
 class MTraitsNamespace:
- DPI = traits.Float(72.)
+ DPI = Float(72.)
 
 Alpha = traits.Range(0., 1., 0.)
- Affine = traits.Trait(Affine())
+ Affine = Trait(Affine())
 AntiAliased = traits.true
- Codes = traits.Array('b', value=npy.array([0,0], dtype=npy.uint8))
- Color = traits.Trait('black', ColorHandler())
- DPI = traits.Float(72.)
- Interval = traits.Array('d', (2,), npy.array([0.0, 1.0], npy.float_))
- LineStyle = traits.Trait('-', '--', '-.', ':', 'steps', None)
- LineWidth = traits.Float(1.0)
- Marker = traits.Trait(None, '.', ',', 'o', '^', 'v', '<', '>', 's',
+ Color = Trait('black', ColorHandler())
+ DPI = Float(72.)
+ Interval = Array('d', (2,), npy.array([0.0, 1.0], npy.float_))
+ LineStyle = Trait('-', '--', '-.', ':', 'steps', None)
+ LineWidth = Float(1.0)
+ Marker = Trait(None, '.', ',', 'o', '^', 'v', '<', '>', 's',
 '+', 'x', 'd', 'D', '|', '_', 'h', 'H',
 'p', '1', '2', '3', '4')
- MarkerSize = traits.Float(6)
- Verts = traits.Array('d', value=npy.array([[0,0],[0,0]], npy.float_))
- PathData = traits.Tuple(Codes(), Verts())
+ MarkerSize = Float(6)
 Visible = traits.true
 
 
 mtraits = MTraitsNamespace()
 
-class Renderer(traits.HasTraits):
- dpi = mtraits.DPI
- size = traits.Tuple(traits.Int(600), traits.Int(400))
+def Alias(name):
+ return Property(lambda obj: getattr(obj, name),
+ lambda obj, val: setattr(obj, name, val))
 
- adisplay = traits.Instance(Affine, ()) 
 
- def __init__(self, size=(600,400)):
+class IDGenerator:
+ def __init__(self):
+ self._id = 0
 
- self.pathd = dict() # path id -> Path instance
- self.markersd = dict() # path id -> Markers instance
+ def __call__(self):
+ _id = self._id
+ self._id += 1
+ return _id
 
+
+
+
+## begin backend API
+MOVETO, LINETO, CLOSEPOLY = range(3)
+class PathPrimitive(HasTraits):
+ """
+ The path is an object that talks to the backends, and is an
+ intermediary between the high level path artists like Line and
+ Polygon, and the backend renderer
+ """
+
+ 
+ color = mtraits.Color('black')
+ facecolor = mtraits.Color('blue')
+ alpha = mtraits.Alpha(1.0)
+ linewidth = mtraits.LineWidth(1.0)
+ antialiased = mtraits.AntiAliased
+ pathdata =Tuple(Array('b'), Array('d'))
+ affine = Instance(Affine, ())
+
+ def _pathdata_default(self):
+ return (npy.array([0,0], dtype=npy.uint8),
+ npy.array([[0,0],[0,0]], npy.float_))
+ 
+ def _pathdata_changed(self, old, new):
+ codes, xy = new
+
+ if len(xy.shape)!=2:
+ raise ValueError('xy in path data must be Nx2')
+ Ncodes = len(codes)
+ Nxy = xy.shape[0]
+ if Ncodes!=Nxy:
+ raise ValueError('codes and xy must have equal rows')
+
+class MarkerPrimitive(HasTraits):
+ locs = Array('d')
+ path = Instance(PathPrimitive, ()) # marker path in points
+ affine = Instance(Affine, ()) # transformation for the verts
+
+ def _locs_default(self):
+ return npy.array([[0,0],[0,0]], npy.float_)
+
+class Renderer(HasTraits):
+ dpi = mtraits.DPI
+ size = traits.Tuple(Int(600), Int(400))
+
+ adisplay = Instance(Affine, ()) 
+ pathd = traits.Dict(Int, PathPrimitive)
+ markerd = traits.Dict(Int, MarkerPrimitive)
+ 
+ def __init__(self, size=(600,400)):
+ self.pathd = dict()
+ self.markerd = dict()
 self._size_changed(None, size)
 
 def _size_changed(self, old, new):
@@ -383,37 +443,83 @@
 
 
 
- def add_path(self, pathid, path):
- # todo, we could use a traits dict here
- if not isinstance(path, Path):
- raise TypeError('add_path takes an ID and a Path instance')
- self.pathd[pathid] = path
+ def render_path(self, pathid):
+ pass
+ 
 
- def remove_path(self, pathid):
- if pathid in self.pathd:
- del self.pathd[pathid]
+ def new_path_primitive(self):
+ """
+ return a PathPrimitive (or derived); these instances will be
+ added and removed later through add_path and remove path
+ """
+ return PathPrimitive()
 
- def add_markers(self, markersid, markers):
- # todo, we could use a traits dict here
- if not isinstance(markers, Markers):
- raise TypeError('add_markers takes an ID and a Markers instance')
- self.markersd[markersid] = markers
+ def new_marker_primitive(self):
+ """
+ return a MarkerPrimitive (or derived); these instances will be
+ added and removed later through add_maker and remove_marker
+ """
+ return MarkerPrimitive()
+ 
 
- def remove_markers(self, markersid):
- if markersid in self.markersd:
- del self.markersd[markersid]
+## begin backend agg 
+class PathPrimitiveAgg(PathPrimitive):
 
- def render_path(self, pathid):
- pass
- 
+ def __init__(self):
+ self._pathdata_changed(None, self.pathdata)
+ self._facecolor_changed(None, self.facecolor)
+ self._color_changed(None, self.color) 
 
+ 
+ @staticmethod
+ def make_agg_path(pathdata):
+ agg_path = agg.path_storage()
 
+ codes, xy = pathdata
+
+ Ncodes = len(codes)
+
+ for i in range(Ncodes):
+ x, y = xy[i]
+ code = codes[i]
+ if code==MOVETO:
+ agg_path.move_to(x, y)
+ elif code==LINETO:
+ agg_path.line_to(x, y) 
+ elif code==CLOSEPOLY:
+ agg_path.close_polygon()
+ return agg_path
+
+ def _pathdata_changed(self, olddata, newdata): 
+ self.agg_path = PathPrimitiveAgg.make_agg_path(newdata)
+
+ 
+ def _facecolor_changed(self, oldcolor, newcolor): 
+ self.agg_facecolor = self.color_to_rgba8(self.facecolor_)
+
+ def _color_changed(self, oldcolor, newcolor): 
+ #print 'stroke color changed', newcolor
+ c = self.color_to_rgba8(self.color_)
+ self.agg_color = c
+
+ def color_to_rgba8(self, color):
+ if color is None: return None
+ rgba = [int(255*c) for c in color]
+ return agg.rgba8(*rgba)
+
+class MarkerPrimitiveAgg(MarkerPrimitive):
+ path = Instance(PathPrimitiveAgg, ())
+
+
+
 class RendererAgg(Renderer):
 gray = agg.rgba8(128,128,128,255) 
 white = agg.rgba8(255,255,255,255)
 blue = agg.rgba8(0,0,255,255)
 black = agg.rgba8(0,0,0,0)
 
+ pathd = traits.Dict(Int, PathPrimitiveAgg)
+ markerd = traits.Dict(Int, MarkerPrimitiveAgg)
 
 def _size_changed(self, old, new):
 Renderer._size_changed(self, old, new)
@@ -440,9 +546,13 @@
 self.scanlinebin = agg.scanline_bin()
 
 
- def add_path(self, pathid, path):
- self.pathd[pathid] = AggPath(path)
+ def new_path_primitive(self):
+ 'return a PathPrimitive (or derived)'
+ return PathPrimitiveAgg()
 
+ def new_marker_primitive(self):
+ 'return a MarkerPrimitive (or derived)'
+ return MarkerPrimitiveAgg()
 
 def render_path(self, pathid):
 
@@ -465,23 +575,23 @@
 aggaffine = agg.trans_affine(*affine.vec6)
 transpath = agg.conv_transform_path(path.agg_path, aggaffine)
 
- if path.fillcolor is not None:
- #print 'render path', path.fillcolor, path.agg_fillcolor
+ if path.facecolor is not None:
+ #print 'render path', path.facecolor, path.agg_facecolor
 self.rasterizer.add_path(transpath)
- renderer.color_rgba8( path.agg_fillcolor )
+ renderer.color_rgba8( path.agg_facecolor )
 render_scanlines(self.rasterizer, scanline, renderer);
 
- if path.strokecolor is not None:
+ if path.color is not None:
 stroke = agg.conv_stroke_transpath(transpath)
 stroke.width(path.linewidth)
 self.rasterizer.add_path(stroke)
- renderer.color_rgba8( path.agg_strokecolor ) 
+ renderer.color_rgba8( path.agg_color ) 
 render_scanlines(self.rasterizer, scanline, renderer);
 
- def render_markers(self, markerid):
- markers = self.markersd[markerid]
+ def render_marker(self, markerid):
+ marker = self.markerd[markerid]
 
- path = AggPath(markers.path)
+ path = marker.path
 
 if path.antialiased:
 renderer = self.renderer
@@ -494,14 +604,14 @@
 
 
 
- affineverts = self.adisplay * markers.affine
+ affinelocs = self.adisplay * marker.affine
 
- Nmarkers = markers.verts.shape[0]
+ Nmarkers = marker.locs.shape[0]
 Locs = npy.ones((3, Nmarkers))
- Locs[0] = markers.verts[:,0]
- Locs[1] = markers.verts[:,1] 
+ Locs[0] = marker.locs[:,0]
+ Locs[1] = marker.locs[:,1] 
 
- Locs = affineverts * Locs
+ Locs = affinelocs * Locs
 
 
 dpiscale = self.dpi/72. # for some reason this is broken 
@@ -509,32 +619,34 @@
 # extension code using cached marker rasters as we now do in
 # _backend_agg
 
- pathcodes, pathverts = markers.path.pathdata
- pathx = dpiscale*pathverts[:,0] 
- pathy = dpiscale*pathverts[:,1]
 
+ pathcodes, pathxy = marker.path.pathdata
+
+ pathx = dpiscale*pathxy[:,0] 
+ pathy = dpiscale*pathxy[:,1]
+
 Npath = len(pathcodes)
 XY = npy.ones((Npath, 2))
 
 
+
 for xv,yv,tmp in Locs.T:
 XY[:,0] = (pathx + xv).astype(int) + 0.5
 XY[:,1] = (pathy + yv).astype(int) + 0.5
 
- 
 pathdata = pathcodes, XY
- aggpath = AggPath.make_agg_path(pathdata)
+ aggpath = PathPrimitiveAgg.make_agg_path(pathdata)
 
- if path.fillcolor is not None:
+ if path.facecolor is not None:
 self.rasterizer.add_path(aggpath)
- renderer.color_rgba8( path.agg_fillcolor )
+ renderer.color_rgba8( path.agg_facecolor )
 render_scanlines(self.rasterizer, scanline, renderer);
 
- if path.strokecolor is not None:
+ if path.color is not None:
 stroke = agg.conv_stroke_path(aggpath)
 stroke.width(path.linewidth)
 self.rasterizer.add_path(stroke)
- renderer.color_rgba8( path.agg_strokecolor ) 
+ renderer.color_rgba8( path.agg_color ) 
 render_scanlines(self.rasterizer, scanline, renderer);
 
 def show(self):
@@ -552,7 +664,7 @@
 pylab.show()
 
 
-class Func(traits.HasTraits):
+class Func(HasTraits):
 def __call__(self, X):
 'transform the numpy array with shape N,2'
 return X
@@ -598,111 +710,15 @@
 raise NotImplementedError
 
 
-mtraits.Model = traits.Instance(Func, ())
+mtraits.Model = Instance(Func, ())
 
 
 
-class Path(traits.HasTraits):
- """
- The path is an object that talks to the backends, and is an
- intermediary between the high level path artists like Line and
- Polygon, and the backend renderer
- """
- MOVETO, LINETO, CLOSEPOLY = range(3)
- 
- strokecolor = mtraits.Color('black')
- fillcolor = mtraits.Color('blue')
- alpha = mtraits.Alpha(1.0)
- linewidth = mtraits.LineWidth(1.0)
- antialiased = mtraits.AntiAliased
- pathdata = mtraits.PathData
- affine = traits.Instance(Affine, ())
 
- def __init__(self):
 
- # this is a quick workaround to deal with the problem that
- # traits inited at the class level are shared between
- # instances, which is not what I want
- self.pathdata = (npy.array([0,0], npy.uint8), # codes
- npy.array([[0,0], [0,0]])) # verts
- 
-class AggPath(Path):
 
- def __init__(self, path):
- self.strokecolor = path.strokecolor
- self.fillcolor = path.fillcolor
- self.alpha = path.alpha
- self.linewidth = path.linewidth
- self.antialiased = path.antialiased
 
- self.pathdata = path.pathdata
- self.affine = path.affine
-
- 
- path.sync_trait('strokecolor', self, mutual=False)
- path.sync_trait('fillcolor', self, mutual=False)
- path.sync_trait('alpha', self, mutual=False)
- path.sync_trait('linewidth', self, mutual=False)
- path.sync_trait('antialiased', self, mutual=False)
- path.sync_trait('pathdata', self, mutual=False)
-
- path.on_trait_change(self.affine.follow, 'vec6')
-
-
-
- # hmm, I would have thought these would be called by the attr
- # setting above
- self._pathdata_changed(None, self.pathdata)
- self._fillcolor__changed(None, self.fillcolor_)
- self._strokecolor__changed(None, self.strokecolor_) 
-
- 
- @staticmethod
- def make_agg_path(pathdata):
- MOVETO, LINETO, CLOSEPOLY = Path.MOVETO, Path.LINETO, Path.CLOSEPOLY
- agg_path = agg.path_storage()
- codes, verts = pathdata
- N = len(codes)
- for i in range(N):
- x, y = verts[i]
- code = codes[i]
- if code==MOVETO:
- agg_path.move_to(x, y)
- elif code==LINETO:
- agg_path.line_to(x, y) 
- elif code==CLOSEPOLY:
- agg_path.close_polygon()
- return agg_path
-
- def _pathdata_changed(self, olddata, newdata): 
- self.agg_path = AggPath.make_agg_path(newdata)
-
- 
- def _fillcolor__changed(self, oldcolor, newcolor): 
- self.agg_fillcolor = self.color_to_rgba8(newcolor)
-
- def _strokecolor__changed(self, oldcolor, newcolor): 
- #print 'stroke color changed', newcolor
- c = self.color_to_rgba8(newcolor)
- self.agg_strokecolor = c
-
-
- def color_to_rgba8(self, color):
- if color is None: return None
- rgba = [int(255*c) for c in color]
- return agg.rgba8(*rgba)
-
-
-mtraits.Path = traits.Instance(Path, ())
-class Markers(traits.HasTraits):
- verts = mtraits.Verts # locations to draw the markers at
- path = mtraits.Path # marker path in points
- affine = traits.Instance(Affine, ()) # transformation for the verts
-
-
-
- 
-mtraits.Markers = traits.Instance(Markers, ())
+## begin Artist layer
 # coordinates:
 #
 # artist model : a possibly nonlinear transformation (Func instance)
@@ -722,39 +738,20 @@
 # 0 is left, top, which is the typical coordinate system of most
 # graphics formats
 
-
-
-
-
-def Alias(name):
- return Property(lambda obj: getattr(obj, name),
- lambda obj, val: setattr(obj, name, val))
-
-
-class IDGenerator:
- def __init__(self):
- self._id = 0
-
- def __call__(self):
- _id = self._id
- self._id += 1
- return _id
-
-
 primitiveID = IDGenerator()
 artistID = IDGenerator()
 
-class Artist(traits.HasTraits):
- zorder = traits.Float(1.0)
+
+class Artist(HasTraits):
+ zorder = Float(1.0)
 alpha = mtraits.Alpha()
 visible = mtraits.Visible()
 
- adata = traits.Instance(Affine, ()) # the data affine
- aview = traits.Instance(Affine, ()) # the view affine
- 
- affine = traits.Instance(Affine, ()) # the product of the data and view affine
+ adata = Instance(Affine, ()) # the data affine
+ aview = Instance(Affine, ()) # the view affine
+ affine = Instance(Affine, ()) # the product of the data and view affine
 
- renderer = traits.Trait(None, Renderer)
+ renderer = Trait(None, Renderer)
 
 # every artist defines a string which is the name of the attr that
 # containers should put it into when added. Eg, an Axes is an
@@ -785,7 +782,7 @@
 
 class ArtistContainer(Artist):
 
- artistd = traits.Dict(traits.Int, Artist)
+ artistd = traits.Dict(Int, Artist)
 sequence = 'containers'
 def __init__(self):
 Artist.__init__(self)
@@ -842,182 +839,280 @@
 #print 'artist draw', self, artist, zorder
 artist.draw()
 
-class Line(Artist):
 
- linestyle = mtraits.LineStyle('-')
- antialiased = mtraits.AntiAliased()
- color = mtraits.Color('blue')
- linewidth = mtraits.LineWidth(1.0) 
- marker = mtraits.Marker(None)
- markerfacecolor = mtraits.Color('blue')
- markeredgecolor = mtraits.Color('black')
- markeredgewidth = mtraits.LineWidth(0.5)
- markersize = mtraits.MarkerSize(6.0)
- path = mtraits.Path
- markers = mtraits.Markers
- X = mtraits.Verts
- model = mtraits.Model
- zorder = traits.Float(2.0)
- sequence = 'lines'
+class Path(Artist):
+ """
+ An interface class between the higher level artists and the path
+ primitive that needs to talk to the renderers
+ """
+ _path = traits.Instance(PathPrimitive, ())
+ antialiased = mtraits.AntiAliased()
+ color = mtraits.Color('blue')
+ facecolor = mtraits.Color('yellow') 
+ linestyle = mtraits.LineStyle('-')
+ linewidth = mtraits.LineWidth(1.0) 
+ model = mtraits.Model
+ pathdata = traits.Tuple(Array('b'), Array('d'))
+ sequence = 'paths'
+ zorder = Float(1.0)
 
+ # why have an extra layer separating the PathPrimitive from the
+ # Path artist? The reasons are severalfold, but it is still not
+ # clear if this is the better solution. Doing it this way enables
+ # the backends to create their own derived primitves (eg
+ # RendererAgg creates PathPrimitiveAgg, and in that class sets up
+ # trait listeners to create agg colors and agg paths when the
+ # PathPrimitive traits change. Another reason is that it allows
+ # us to handle nonlinear transformation (the "model") at the top
+ # layer w/o making the backends understand them. The current
+ # design is create a mapping between backend primitives and
+ # primitive artists (Path, Text, Image, etc...) and all of the
+ # higher level Artists (Line, Polygon, Axis) will use the
+ # primitive artitsts. So only a few artists will need to know how
+ # to talk to the backend. The alternative is to make the backends
+ # track and understand the primitive artists themselves.
+
 def __init__(self):
 """
 The model is a function taking Nx2->Nx2. This is where the
 nonlinear transformation can be used
 """
 Artist.__init__(self)
+ self._pathid = primitiveID()
 
- # this is potentially a big problem because you have to know
- # which attrs may be shared and hence have to be initialized
- # and which ones don't. Eg, if you comment out the self.path
- # init, the code breaks
+ def _pathdata_default(self):
+ return (npy.array([0,0], dtype=npy.uint8),
+ npy.array([[0,0],[0,0]], npy.float_))
+ 
+ def _update_path(self):
+ 'sync the Path traits with the path primitive'
+ self.sync_trait('linewidth', self._path, mutual=False)
+ self.sync_trait('color', self._path, mutual=False)
+ self.sync_trait('facecolor', self._path, mutual=False)
+ self.sync_trait('antialiased', self._path, mutual=False)
 
- 
- self.sync_trait('linewidth', self.path, 'linewidth', mutual=False)
- self.sync_trait('color', self.path, 'strokecolor', mutual=False)
- self.sync_trait('markerfacecolor', self.markers.path, 'fillcolor', mutual=False)
- self.sync_trait('markeredgecolor', self.markers.path, 'strokecolor', mutual=False)
- self.sync_trait('markeredgewidth', self.markers.path, 'linewidth', mutual=False) 
+ # sync up the path affine
+ self._path.affine.follow(self.affine.vec6)
+ self.affine.on_trait_change(self._path.affine.follow, 'vec6')
+ self._update_pathdata()
 
- # sync up the markers affine
- self.markers.affine.follow(self.affine.vec6)
- self.affine.on_trait_change(self.markers.affine.follow, 'vec6')
+ def _update_pathdata(self):
+ #print 'PATH: update pathdata'
 
- # sync up the path affine
- self.path.affine.follow(self.affine.vec6)
- self.affine.on_trait_change(self.path.affine.follow, 'vec6')
- 
+ codes, xy = self.pathdata
 
- self.path.fillcolor = None
+ #print ' PATH: shapes', codes.shape, xy.shape
+ if self.model is not None:
+ xy = self.model(xy)
 
- self.pathid = primitiveID()
- self.markerid = primitiveID()
+ pathdata = codes, xy
 
- self.markerfuncd = {
- 's': self._markers_square,
- } 
-
+ self._path.pathdata = pathdata
+ 
 def draw(self):
-
 if self.renderer is None or not self.visible: return
 Artist.draw(self)
-
- if self.linestyle is not None:
- self.renderer.render_path(self.pathid)
- if self.marker is not None:
- self.renderer.render_markers(self.markerid) 
+ self.renderer.render_path(self._pathid)
 
 
 def _renderer_changed(self, old, new):
 if old is not None:
- old.remove_path(self.pathid)
- old.remove_markers(self.markerid)
+ del old.pathd[self._pathid]
+ 
+ if new is None: return 
 
- if new is not None:
- new.add_path(self.pathid, self.path)
- new.add_markers(self.markerid, self.markers) 
+ #print 'PATH renderer_changed; updating' 
+ self._path = renderer.new_path_primitive()
+ new.pathd[self._pathid] = self._path
+ self._update_path() 
+ 
+ def _model_changed(self, old, new):
+ self._update_pathdata()
 
+ def _pathdata_changed(self, old, new):
+ #print 'PATH: pathdata changed'
+ self._update_pathdata()
 
- def _model_changed(self, old, new):
- self._update_data()
 
- def _X_changed(self, old, new):
- self._update_data()
- 
- def _update_data(self):
- N = self.X.shape[0]
- codes = Path.LINETO*npy.ones(N, dtype=npy.uint8)
- codes[0] = Path.MOVETO
+class Marker(Artist):
+ """
+ An interface class between the higher level artists and the marker
+ primitive that needs to talk to the renderers
+ """
+ _marker = traits.Instance(MarkerPrimitive, ())
+ locs = Array('d')
+ path = Instance(Path, ()) 
+ model = mtraits.Model
+ sequence = 'markers'
+ size = Float(1.0) # size of the marker in points
 
- # todo, having touble setting Model to default to Identity so
- # allowing None as a hack workaround
- #print 'X changed', self.model
- if self.model is not None:
- modelx = self.model(self.X)
- else:
- modelx = self.X
- self.path.pathdata = codes, modelx
- self.markers.verts = modelx
+ def __init__(self):
+ """
+ The model is a function taking Nx2->Nx2. This is where the
+ nonlinear transformation can be used
+ """
+ Artist.__init__(self)
+ self._markerid = primitiveID()
 
- def _markersize_changed(self, oldX, newX):
- self._refresh_markers()
+ def _locs_default(self):
+ return npy.array([[0,1],[0,1]], npy.float_)
 
- def _marker_changed(self, oldX, newX):
- self._refresh_markers()
+ 
+ def _path_default(self):
+ bounds = npy.array([-0.5, -0.5, 1, 1])*self.size
+ return Rectangle().set(bounds=bounds)
 
+ def _path_changed(self, old, new):
+ if self.renderer is None:
+ # we can't sync up to the underlying path yet
+ return 
+ print 'MARKER _path_changed', self.path._path.pathdata, self._marker.path.pathdata
+ old.sync_trait('_path', self._marker, 'path', remove=True)
+ new.sync_trait('_path', self._marker, 'path', mutual=False)
 
- def _refresh_markers(self):
- if self.marker is not None:
- markerfunc = self.markerfuncd.get(self.marker)
- if markerfunc is not None: markerfunc()
 
+ def _update_marker(self):
+ 'sync the Marker traits with the marker primitive'
+ if self.renderer is None:
+ # we can't sync up to the underlying path yet
+ return 
 
- def _markers_square(self):
+ # sync up the marker affine
+ self.path.sync_trait('_path', self._marker, 'path', mutual=False)
+ self._marker.affine.follow(self.affine.vec6)
+ self.affine.on_trait_change(self._marker.affine.follow, 'vec6')
+ self._update_locs()
 
- verts = self.markersize*npy.array([[-0.5,-0.5], [-0.5,0.5], [0.5,0.5], [0.5,-0.5], [0,0]])
- codes = Path.LINETO*npy.ones(len(verts), dtype=npy.uint8)
- codes[0] = Path.MOVETO
- codes[-1] = Path.CLOSEPOLY
+ print 'MARKER _update_marker', self.path._path.pathdata, self._marker.path.pathdata
+
+ def _update_locs(self):
+ print 'MARKER: update markerdata'
+ xy = self.locs
+ if self.model is not None:
+ xy = self.model(xy)
+
+ self._marker.locs = xy
 
- self.markers.path.pathdata = codes, verts
+ def draw(self):
+ if self.renderer is None or not self.visible: return
+ Artist.draw(self)
+ self.renderer.render_marker(self._markerid)
+ 
 
-mtraits.Line = traits.Instance(Line, ())
+ def _renderer_changed(self, old, new):
+ # we must make sure the contained artist gets the callback
+ # first so we can update the path primitives properly
+ self.path._renderer_changed(old, new)
+ if old is not None:
+ del old.markerd[self._markerid]
+ 
+ if new is None: return 
 
-class Rectangle(Artist, Box):
- facecolor = mtraits.Color('yellow')
- edgecolor = mtraits.Color('black')
- edgewidth = mtraits.LineWidth(1.0)
- path = mtraits.Path
- zorder = traits.Float(1.0)
- sequence = 'rectangles'
+ print 'MARKER renderer_changed; updating' 
+ self._marker = renderer.new_marker_primitive()
+ new.markerd[self._markerid] = self._marker
+ self._update_marker() 
+ 
+ def _model_changed(self, old, new):
+ self._update_locs()
 
- def __init__(self):
- Artist.__init__(self)
- 
- self.sync_trait('facecolor', self.path, 'fillcolor', mutual=False)
- self.sync_trait('edgecolor', self.path, 'strokecolor', mutual=False)
- self.sync_trait('edgewidth', self.path, 'linewidth', mutual=False)
+ def _locs_changed(self, old, new):
+ if len(new.shape)!=2:
+ raise ValueError('new must be nx2 array')
+ self._update_locs()
 
- self.pathid = primitiveID()
- # sync up the path affine
- self.path.affine.follow(self.affine.vec6)
- self.affine.on_trait_change(self.path.affine.follow, 'vec6')
+class Line(Path):
+
+ XY = Array('d')
+ sequence = 'lines'
+
+ def _facecolor_default(self):
+ return None
+ 
+ def _XY_default(self):
+ return npy.array([[0,1],[0,1]], npy.float_)
+ 
+ def _XY_changed(self):
+ #print 'LINE: XY changed'
+ codes = npy.ones(len(self.XY), npy.uint8)
+ codes[0] = MOVETO
+ #print 'LINE shapes', codes.shape, self.XY.shape
+ self.pathdata = codes, self.XY
+
+ # XXX: to we need to push pathdata changed here or will it
+ # happen automagically
+
+
+class Polygon(Path):
+ zorder = Float(2.0)
+ vertices = Array('d')
+ sequence = 'polygons'
+
+ def _vertices_default(self):
+ return npy.array([[-1,0], [0,1], [1,0], [0,0]], npy.float_)
+
+ def _vertices_changed(self, old, new):
+ #print 'POLY: verts changed'
+ N = len(new)
 
- def _hidebounds_changed(self, old, new):
- Box._bounds_changed(self, old, new)
- print 'rectangle bounds changed'
+ codes = LINETO*npy.ones(N, npy.uint8)
+ codes[0] = MOVETO
+ codes[-1] = CLOSEPOLY
 
+ pathdata = codes, new
+ self.pathdata = pathdata
+ self._pathdata_changed(None, pathdata)
+ 
+class Rectangle(Polygon, Box):
+ sequence = 'rectangles'
+ def __init__(self):
+ Polygon.__init__(self)
+ self._bounds_changed(None, self.bounds)
+ 
 def _bounds_changed(self, old, new):
 Box._bounds_changed(self, old, new)
- print 'rectangle bounds changed'
+ #print 'RECT: bounds changed'
 l,b,w,h = new
 t = b+h
 r = l+w
- verts = npy.array([(l,b), (l,t), (r, t), (r, b), (0,0)], npy.float_)
- codes = Path.LINETO*npy.ones(5, npy.uint8)
- codes[0] = Path.MOVETO
- codes[-1] = Path.CLOSEPOLY
+ self.vertices = npy.array([(l,b), (l,t), (r, t), (r, b), (0,0)], npy.float_)
+ #XXX: do we need to otify traits change
+ self._vertices_changed(None, self.vertices)
 
- self.path.pathdata = codes, verts
+class RegularPolygon(Polygon):
+ center = Tuple(Float, Float) 
+ sides = Int(6)
+ radius = Float(1.0)
+ theta = Float(0.) # orientation in radians
+ sequence = 'rectangles'
 
- def _renderer_changed(self, old, new):
- if old is not None:
- old.remove_path(self.pathid)
+ def __init__(self):
+ self._update_vertices()
+ 
+ def _sides_changed(self, old, new):
+ self._update_verts()
 
- if new is not None:
- new.add_path(self.pathid, self.path)
+ def _theta_changed(self, old, new):
+ self._update_verts()
 
- def draw(self):
- if self.renderer is None or not self.visible: return
- Artist.draw(self)
- self.renderer.render_path(self.pathid)
+ def _radius_changed(self, old, new):
+ self._update_verts()
+ 
+ def _update_verts(self):
 
+ theta = 2*npy.pi/self.sides*npy.arange(self.sides) + self.theta
+ x, y = self.center
 
-mtraits.Rectangle = traits.Instance(Rectangle, ()) 
+ xy = npy.zeros((self.sides,2))
 
+ xy[:,0] = x + self.radius*npy.cos(theta)
+ xy[:,1] = y + self.radius*npy.sin(theta)
+
+ self.vertices = xy
+
 class Figure(ArtistContainer):
 
- rectangle = traits.Instance(Rectangle, ())
+ rectangle = Instance(Rectangle, ())
 sequence = None # figure is top level container
 def __init__(self):
 ArtistContainer.__init__(self)
@@ -1027,34 +1122,26 @@
 self.add_artist(self.rectangle)
 
 class Axis(ArtistContainer):
- zorder = traits.Float(1.5)
- tickmarkers = mtraits.Markers
- linepath = mtraits.Path
- linecolor = mtraits.Color('black')
- linewidth = mtraits.LineWidth(1.0)
- ticklocs = traits.Array('d')
- ticksize = traits.Float(5.0)
- ticklinewidth = mtraits.LineWidth(1.0)
- tickcolor = mtraits.Color('black')
+ zorder = Float(1.5)
+ tickmarker = Instance(Marker, ())
+ line = Instance(Line, ())
+ ticklocs = Array('d')
+ ticksize = Float(5.0)
+
 
- loc = traits.Float(0.) # the y location of the x-axis
- tickoffset = traits.Float(0) # -1 for outer, -0.5 for centered, 0 for inner
+ loc = Float(0.) # the y location of the x-axis
+ tickoffset = Float(0) # -1 for outer, -0.5 for centered, 0 for inner
 sequence = 'axes'
 
 def __init__(self):
 ArtistContainer.__init__(self)
- self.tickmarkersid = primitiveID()
- self.linepathid = primitiveID()
-
 self.affine.on_trait_change(self._update_blended_affine, 'vec6')
- self.tickmarkers.path.antialiased = False
- self.linepath.antialiased = False
- 
- self.sync_trait('linewidth', self.linepath, mutual=False)
- self.sync_trait('linecolor', self.linepath, 'strokecolor', mutual=False)
- self.sync_trait('ticklinewidth', self.tickmarkers.path, 'linewidth', mutual=False)
- self.sync_trait('tickcolor', self.tickmarkers.path, 'strokecolor', mutual=False)
+ self.tickmarker.antialiased = False
+ self.line.antialiased = False
 
+ self.add_artist(self.line, followdata=False)
+ self.add_artist(self.tickmarker, followdata=False)
+
 # XXX, do we have to manually call these or will they get
 # calle dautomagically in init
 self._update_tick_path()
@@ -1087,21 +1174,6 @@
 def _update_linepath(self):
 raise NotImplementedError
 
- def _renderer_changed(self, old, new):
- if old is not None:
- old.remove_markers(self.tickmarkersid)
- old.remove_path(self.linepathid) 
-
- if new is not None:
- new.add_markers(self.tickmarkersid, self.tickmarkers)
- new.add_path(self.linepathid, self.linepath) 
-
- def draw(self):
- if self.renderer is None or not self.visible: return
- Artist.draw(self)
- self.renderer.render_markers(self.tickmarkersid)
- self.renderer.render_path(self.linepathid) 
-
 class XAxis(Axis):
 sequence = 'xaxes'
 def _update_blended_affine(self):
@@ -1109,27 +1181,31 @@
 sx, b, tx = self.adata.data[0]
 a = Affine()
 a.vec6 = sx, b, 0, 1, tx, self.loc
- self.tickmarkers.affine.vec6 = (self.aview * a).vec6
+ self.tickmarker.affine.vec6 = (self.aview * a).vec6
 
 a = Affine()
 a.translate = 0, self.loc
- self.linepath.affine.vec6 = (self.aview * a).vec6 
+ self.line.affine.vec6 = (self.aview * a).vec6 
 
 def _update_marker_locations(self):
 Nticks = len(self.ticklocs)
- verts = self.loc*npy.ones((Nticks,2))
- verts[:,0] = self.ticklocs
- self.tickmarkers.verts = verts
+ locs = self.loc*npy.ones((Nticks,2))
+ locs[:,0] = self.ticklocs
+ self.tickmarker.locs = locs
 
 def _update_tick_path(self):
- codes = Path.MOVETO, Path.LINETO
+ codes = MOVETO, LINETO
 verts = npy.array([[0., self.tickoffset], [0, self.tickoffset-1]])*self.ticksize
- self.tickmarkers.path.pathdata = codes, verts 
 
+ pathdata = codes, verts
+ self.tickmarker.path.pathdata = pathdata 
+
 def _update_linepath(self):
- codes = Path.MOVETO, Path.LINETO
+ 
+ codes = MOVETO, LINETO
 X = npy.array([[0, 1], [0, 0]], npy.float_).T
- self.linepath.pathdata = codes, X
+ pathdata = codes, X
+ self.line.pathdata = pathdata
 
 class YAxis(Axis):
 sequence = 'yaxes'
@@ -1139,28 +1215,31 @@
 c, sy, ty = self.adata.data[1]
 a = Affine()
 a.vec6 = 1, 0, 0, sy, self.loc, ty
- self.tickmarkers.affine.vec6 = (self.aview * a).vec6
+ self.tickmarker.affine.vec6 = (self.aview * a).vec6
 
 a = Affine()
 a.translate = self.loc, 0
- self.linepath.affine.vec6 = (self.aview * a).vec6 
+ self.line.affine.vec6 = (self.aview * a).vec6 
 
 def _update_marker_locations(self):
 Nticks = len(self.ticklocs)
- verts = self.loc*npy.ones((Nticks,2))
- verts[:,1] = self.ticklocs
- self.tickmarkers.verts = verts
+ locs = self.loc*npy.ones((Nticks,2))
+ locs[:,1] = self.ticklocs
+ self.tickmarker.locs = locs
 
 def _update_tick_path(self):
- codes = Path.MOVETO, Path.LINETO
+ codes = MOVETO, LINETO
 verts = npy.array([[self.tickoffset,0], [self.tickoffset+1,0]])*self.ticksize
- self.tickmarkers.path.pathdata = codes, verts 
+ pathdata = codes, verts
+ self.tickmarker.path.pathdata = pathdata
 
 def _update_linepath(self):
- codes = Path.MOVETO, Path.LINETO
+ codes = MOVETO, LINETO
 X = npy.array([[0, 0], [0, 1]], npy.float_).T
- self.linepath.pathdata = codes, X
 
+ pathdata = codes, X
+ self.line.pathdata = pathdata
+
 class FigurePane(ArtistContainer, Box):
 """
 The figure pane conceptually like the matplotlib Axes, but now
@@ -1168,10 +1247,10 @@
 Affine instances. It is a shell of it's former self: it has a
 rectangle and a default x and y axis instance
 """
- rectangle = traits.Instance(Rectangle, ())
+ rectangle = Instance(Rectangle, ())
 #gridabove = traits.false # TODO handle me
- xaxis = traits.Instance(XAxis, ())
- yaxis = traits.Instance(YAxis, ())
+ xaxis = Instance(XAxis, ())
+ yaxis = Instance(YAxis, ())
 sequence = 'panes'
 
 def __init__(self):
@@ -1181,56 +1260,120 @@
 self.rectangle.edgecolor = 'white' 
 self.rectangle.linewidth = 0
 
- print 'setting rect bounds'
 self.rectangle.bounds = [0,0,1,1]
- print 'set rect bounds'
 self.add_artist(self.rectangle, followdata=False)
 self.add_artist(self.xaxis)
 self.add_artist(self.yaxis) 
 
 def _bounds_changed(self, old, new):
 Box._bounds_changed(self, old, new)
- print 'pane bounds changed'
 l,b,w,h = self.bounds
 self.aview.scale = w, h
 self.aview.translate = l, b
 
 
-
+## begin examples
+ 
 def classic(fig):
- x = npy.arange(0, 10., 0.01)
- y = npy.sin(2*npy.pi*x)
 
 pane = FigurePane().set(bounds=[0.1, 0.1, 0.8, 0.8])
 fig.add_artist(pane, followdata=False, followview=False)
-
-
- line1 = Line().set(X=npy.array([x,y]).T,
- color='blue', linewidth=2.0, marker=None,
+ # update the view limits, all the affines should be automagically updated
+ x = npy.arange(0, 10., 0.01)
+ y = npy.sin(2*npy.pi*x)
+ y = npy.exp(-x/2.)
+ line1 = Line().set(XY=npy.array([x,y]).T,
+ color='blue', linewidth=2.0, 
 )
 
 
 pane.add_artist(line1)
-
- # update the view limits, all the affines should be automagically updated
 pane.adata.xlim = 0, 10
- pane.adata.ylim = -1.1, 1.1
+ pane.adata.ylim = -0.1, 1.1
 
- pane.xaxis.ticklocs = npy.arange(0., 11., 1.)
- pane.yaxis.ticklocs = npy.arange(-1.0, 1.1, 0.2)
+ # axis placement is still broken
+ xax, yax = pane.xaxis, pane.yaxis
+ xax.ticklocs = npy.arange(0., 11., 1)
+ xax.tickoffset = 0.5
+ xax.loc = -0.05
+ xax.line.color = 'black'
+ xax.tickmarker.path.color = 'black'
 
+ yax.ticklocs = npy.arange(-1.0, 1.1, 0.2)
+ yax.tickoffset = -0.5
+ yax.loc = -0.05
+ yax.line.color = 'black'
+ yax.tickmarker.path.color = 'black'
 
- # add a right and top axis
- xaxis2 = XAxis().set(loc=1, tickoffset=-1)
- yaxis2 = YAxis().set(loc=1, tickoffset=-1) 
- xaxis2.ticklocs = npy.arange(0., 11., 0.5)
- yaxis2.ticklocs = npy.arange(-1.0, 1.1, 0.1)
+ if 0:
+ x = npy.arange(0, 10., 0.1)
+ y = npy.sin(2*npy.pi*x)
 
- pane.add_artist(xaxis2)
- pane.add_artist(yaxis2)
- # uncomment to change Axes wwidth
- #pane.width = 0.8
+ marker = Marker().set(
+ locs=npy.array([x,y]).T, color='ref', linewidth=1.0,
+ size=10)
 
+
+ pane.add_artist(marker)
+
+
+ if 0:
+ xax, yax = pane.xaxis, pane.yaxis
+ xax.ticklocs = npy.arange(0., 11., 1)
+ xax.ticksize = 8
+ xax.line.color = 'black'
+ xax.line.linewidth = 2.0
+ xax.tickoffset = .5
+ xax.tickmarker.path.color = 'black'
+ xax.tickmarker.path.linewidth = 2
+
+ xax.loc = 0.5
+ xax.zorder = 10 
+
+ yax.ticklocs = npy.arange(-1.0, 1.1, 0.2)
+ yax.line.color = 'black'
+ yax.line.linewidth = 2.0
+ yax.tickmarker.path.color = 'black'
+ yax.ticksize = 8
+ yax.tickoffset = -0.5
+ yax.tickmarker.path.linewidth = 2
+ yax.loc = 0.5
+ yax.zorder = 10
+ if 0:
+ # add a right and top axis; the markers are getting the loc
+ # but the line path isn't... It appears all the line paths
+ # are getting 0
+ xaxis2 = XAxis()
+ xaxis2.loc = 0.6
+ xaxis2.tickoffset = -1
+ xaxis2.ticklocs = npy.arange(0., 10.1, 0.5)
+ yaxis2 = YAxis().set(loc=0.6, tickoffset=-1) 
+
+ yaxis2.tickmarker.path.color = 'green'
+ yaxis2.loc = 0.5
+ yaxis2.ticksize = 10
+ yaxis2.tickmarker.path.linewidth = 1
+ yaxis2.line.color = 'green'
+ yaxis2.tickmarker.path.color = 'green'
+ yaxis2.ticklocs = npy.arange(-1.0, 1.1, 0.1)
+
+ pane.add_artist(xaxis2)
+ pane.add_artist(yaxis2)
+ # uncomment to change Axes wwidth
+ #pane.width = 0.8
+
+ if 0:
+ # XXX: axes lines and tick markes are placed in vastly
+ # different locations depending on whether this is commented
+ # or uncommented, suggesting that the problem is caused by
+ # events not propogating unless lim are changed. If we set
+ # these lim to be the same as the lim above (note they are
+ # almost identical) then the graphs are the same regardless of
+ # whether the lim are set
+ pane.adata.xlim = 0.01, 10.01
+ pane.adata.ylim = -0.101, 1.101
+
+
 def make_subplot_ll(fig):
 x1 = npy.arange(0, 10., 0.05)
 x2 = npy.arange(0, 10., 0.1)
@@ -1243,9 +1386,7 @@
 
 
 line1 = Line().set(X=npy.array([x1,y1]).T,
- color='blue', linewidth=2.0, marker='s',
- markersize=5.0, markerfacecolor='green',
- markeredgewidth=0.5)
+ color='blue', linewidth=2.0)
 
 
 pane.add_artist(line1)
@@ -1257,14 +1398,14 @@
 pane.xaxis.ticklocs = npy.arange(0., 11., 1.)
 pane.xaxis.loc = -0.1
 pane.xaxis.tickoffset = -0.5
- pane.xaxis.linecolor = 'red'
+ pane.xaxis.line.color = 'red'
 
- pane.yaxis.ticklocs = npy.arange(-1.0, 1.1, 0.2)
+ Pane.yaxis.ticklocs = npy.arange(-1.0, 1.1, 0.2)
 pane.yaxis.loc = -0.1
 pane.xaxis.tickoffset = -0.5 
 
- pane.yaxis.linecolor = 'blue'
- pane.yaxis.tickcolor = 'blue'
+ pane.yaxis.line.color = 'blue'
+ pane.yaxis.tickmarker.color = 'blue'
 
 # uncomment to change Axes wwidth
 #pane.width = 0.8
@@ -1291,19 +1432,6 @@
 
 
 
-class TestContainer(ArtistContainer, Box):
- rectangle = traits.Instance(Rectangle, ())
- sequence = 'panes'
- 
- def __init__(self):
- ArtistContainer.__init__(self)
- self.rectangle.zorder = 0
- self.rectangle.facecolor = 'white'
-
- print 'setting rect bounds'
- self.rectangle.bounds = [0,0,1,1]
- print 'set rect bounds'
-
 if __name__=='__main__':
 
 renderer = RendererAgg()
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 3605
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3605&view=rev
Author: jdh2358
Date: 2007年07月22日 12:53:44 -0700 (2007年7月22日)
Log Message:
-----------
added vertex array trait handler
Modified Paths:
--------------
 trunk/matplotlib/mpl1/mpl1.py
Modified: trunk/matplotlib/mpl1/mpl1.py
===================================================================
--- trunk/matplotlib/mpl1/mpl1.py	2007年07月22日 16:53:37 UTC (rev 3604)
+++ trunk/matplotlib/mpl1/mpl1.py	2007年07月22日 19:53:44 UTC (rev 3605)
@@ -20,7 +20,7 @@
 import enthought.traits.api as traits
 from enthought.traits.api import HasTraits, Instance, Trait, Float, Int, \
 Array, Tuple
-
+from enthought.traits.trait_numeric import TraitArray
 from matplotlib import agg
 from matplotlib import colors as mcolors
 from matplotlib import cbook
@@ -30,7 +30,26 @@
 
 ## begin core infrastructure
 
+class TraitVertexArray(TraitArray):
 
+ def __init__ ( self, typecode = None, shape = None, coerce = False ):
+ TraitArray.__init__(self, typecode, shape, coerce)
+
+ def validate(self, object, name, value):
+ orig = value
+ value = TraitArray.validate(self, object, name, value)
+ if len(value.shape)!=2 or value.shape[1]!=2:
+ return self.error(object, name, orig)
+
+ return value
+
+ def info(self):
+ return 'an Nx2 array of doubles which are x,y vertices'
+
+VertexArray = Trait(npy.array([[0,0], [1,1]], npy.float_),
+ TraitVertexArray('d'))
+
+ 
 class Affine(HasTraits):
 """
 An affine 3x3 matrix that supports matrix multiplication with
@@ -396,23 +415,14 @@
 alpha = mtraits.Alpha(1.0)
 linewidth = mtraits.LineWidth(1.0)
 antialiased = mtraits.AntiAliased
- pathdata =Tuple(Array('b'), Array('d'))
+ pathdata =Tuple(Array('b'), VertexArray)
 affine = Instance(Affine, ())
 
 def _pathdata_default(self):
 return (npy.array([0,0], dtype=npy.uint8),
 npy.array([[0,0],[0,0]], npy.float_))
 
- def _pathdata_changed(self, old, new):
- codes, xy = new
 
- if len(xy.shape)!=2:
- raise ValueError('xy in path data must be Nx2')
- Ncodes = len(codes)
- Nxy = xy.shape[0]
- if Ncodes!=Nxy:
- raise ValueError('codes and xy must have equal rows')
-
 class MarkerPrimitive(HasTraits):
 locs = Array('d')
 path = Instance(PathPrimitive, ()) # marker path in points
@@ -852,7 +862,7 @@
 linestyle = mtraits.LineStyle('-')
 linewidth = mtraits.LineWidth(1.0) 
 model = mtraits.Model
- pathdata = traits.Tuple(Array('b'), Array('d'))
+ pathdata = traits.Tuple(Array('b'), VertexArray)
 sequence = 'paths'
 zorder = Float(1.0)
 
@@ -1039,8 +1049,6 @@
 #print 'LINE shapes', codes.shape, self.XY.shape
 self.pathdata = codes, self.XY
 
- # XXX: to we need to push pathdata changed here or will it
- # happen automagically
 
 
 class Polygon(Path):
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 3606
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3606&view=rev
Author: jdh2358
Date: 2007年07月22日 13:03:08 -0700 (2007年7月22日)
Log Message:
-----------
added more path codes
Modified Paths:
--------------
 trunk/matplotlib/mpl1/mpl1.py
Modified: trunk/matplotlib/mpl1/mpl1.py
===================================================================
--- trunk/matplotlib/mpl1/mpl1.py	2007年07月22日 19:53:44 UTC (rev 3605)
+++ trunk/matplotlib/mpl1/mpl1.py	2007年07月22日 20:03:08 UTC (rev 3606)
@@ -30,25 +30,7 @@
 
 ## begin core infrastructure
 
-class TraitVertexArray(TraitArray):
 
- def __init__ ( self, typecode = None, shape = None, coerce = False ):
- TraitArray.__init__(self, typecode, shape, coerce)
-
- def validate(self, object, name, value):
- orig = value
- value = TraitArray.validate(self, object, name, value)
- if len(value.shape)!=2 or value.shape[1]!=2:
- return self.error(object, name, orig)
-
- return value
-
- def info(self):
- return 'an Nx2 array of doubles which are x,y vertices'
-
-VertexArray = Trait(npy.array([[0,0], [1,1]], npy.float_),
- TraitVertexArray('d'))
-
 
 class Affine(HasTraits):
 """
@@ -317,7 +299,29 @@
 
 def _bounds_changed(self, old, new):
 pass
+
+
+## begin custom trait handlers
 
+class TraitVertexArray(TraitArray):
+
+ def __init__ ( self, typecode = None, shape = None, coerce = False ):
+ TraitArray.__init__(self, typecode, shape, coerce)
+
+ def validate(self, object, name, value):
+ orig = value
+ value = TraitArray.validate(self, object, name, value)
+ if len(value.shape)!=2 or value.shape[1]!=2:
+ return self.error(object, name, orig)
+
+ return value
+
+ def info(self):
+ return 'an Nx2 array of doubles which are x,y vertices'
+
+VertexArray = Trait(npy.array([[0,0], [1,1]], npy.float_),
+ TraitVertexArray('d'))
+ 
 class ColorHandler(traits.TraitHandler):
 """
 This is a clever little traits mechanism -- users can specify the
@@ -401,7 +405,17 @@
 
 
 ## begin backend API
-MOVETO, LINETO, CLOSEPOLY = range(3)
+# PATH CODES
+STOP = 0
+MOVETO = 1
+LINETO = 2
+CURVE3 = 3
+CURVE4 = 4
+CURVEN = 5
+CATROM = 6
+UBSPLINE = 7
+CLOSEPOLY = 0x0F
+
 class PathPrimitive(HasTraits):
 """
 The path is an object that talks to the backends, and is an
@@ -1044,7 +1058,7 @@
 
 def _XY_changed(self):
 #print 'LINE: XY changed'
- codes = npy.ones(len(self.XY), npy.uint8)
+ codes = LINETO*npy.ones(len(self.XY), npy.uint8)
 codes[0] = MOVETO
 #print 'LINE shapes', codes.shape, self.XY.shape
 self.pathdata = codes, self.XY
@@ -1134,7 +1148,7 @@
 tickmarker = Instance(Marker, ())
 line = Instance(Line, ())
 ticklocs = Array('d')
- ticksize = Float(5.0)
+ ticksize = Float(7.0)
 
 
 loc = Float(0.) # the y location of the x-axis
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Revision: 3607
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3607&view=rev
Author: jdh2358
Date: 2007年07月22日 13:03:45 -0700 (2007年7月22日)
Log Message:
-----------
added more path codes
Modified Paths:
--------------
 trunk/matplotlib/mpl1/mpl1.py
Modified: trunk/matplotlib/mpl1/mpl1.py
===================================================================
--- trunk/matplotlib/mpl1/mpl1.py	2007年07月22日 20:03:08 UTC (rev 3606)
+++ trunk/matplotlib/mpl1/mpl1.py	2007年07月22日 20:03:45 UTC (rev 3607)
@@ -506,6 +506,7 @@
 for i in range(Ncodes):
 x, y = xy[i]
 code = codes[i]
+ #XXX handle other path codes here
 if code==MOVETO:
 agg_path.move_to(x, y)
 elif code==LINETO:
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.
Thanks for helping keep SourceForge clean.
X





Briefly describe the problem (required):
Upload screenshot of ad (required):
Select a file, or drag & drop file here.
Screenshot instructions:

Click URL instructions:
Right-click on the ad, choose "Copy Link", then paste here →
(This may not be possible with some types of ads)

More information about our ad policies

Ad destination/click URL:

AltStyle によって変換されたページ (->オリジナル) /