Revision: 3848
          http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3848&view=rev
Author:   mdboom
Date:     2007-09-13 11:00:10 -0700 (Thu, 13 Sep 2007)

Log Message:
-----------
New milestone -- resizing figure window works.  shared_axis_demo.py
works.  (Uses callbacks to track changes between axes's).

Modified Paths:
--------------
    branches/transforms/lib/matplotlib/affine.py
    branches/transforms/lib/matplotlib/artist.py
    branches/transforms/lib/matplotlib/axes.py
    branches/transforms/lib/matplotlib/axis.py
    branches/transforms/lib/matplotlib/backend_bases.py
    branches/transforms/lib/matplotlib/figure.py
    branches/transforms/lib/matplotlib/pyplot.py
    branches/transforms/lib/matplotlib/text.py

Modified: branches/transforms/lib/matplotlib/affine.py
===================================================================
--- branches/transforms/lib/matplotlib/affine.py        2007-09-13 12:50:05 UTC 
(rev 3847)
+++ branches/transforms/lib/matplotlib/affine.py        2007-09-13 18:00:10 UTC 
(rev 3848)
@@ -20,284 +20,461 @@
 
 class TransformNode(object):
     def __init__(self):
-       self._parents = Set()
-       
+        self._parents = Set()
+        
     def invalidate(self):
-       if not self._do_invalidation():
-           for parent in self._parents:
-               parent.invalidate()
+        if not self._do_invalidation():
+            for parent in self._parents:
+                parent.invalidate()
 
     def _do_invalidation(self):
-       return False
-           
-    def add_children(self, children):
-       for child in children:
-           child._parents.add(self)
+        return False
 
-class Bbox(TransformNode):
+    def set_children(self, children):
+        for child in children:
+            getattr(self, child)._parents.add(self)
+        self._children = children
+
+#     def replace_child(self, index, child):
+#         children = self._children
+#         getattr(self, children[index])._parents.remove(self)
+#         setattr(self, children[index], child)
+#         # We have to reset children in case two or more
+#         # of the children are the same
+#         for child in children:
+#             getattr(self, child)._parents.add(self)
+#         self.invalidate()
+            
+class BboxBase(TransformNode):
+    '''
+    This is the read-only part of a bounding-box
+    '''
+    
+    def __init__(self):
+        TransformNode.__init__(self)
+    
+    def __array__(self):
+        return self.get_points()
+    
+    # MGDTODO: Probably a more efficient ways to do this...
+    def _get_xmin(self):
+        return self.get_points()[0, 0]
+    xmin = property(_get_xmin)
+    
+    def _get_ymin(self):
+        return self.get_points()[0, 1]
+    ymin = property(_get_ymin)
+
+    def _get_xmax(self):
+        return self.get_points()[1, 0]
+    xmax = property(_get_xmax)
+
+    def _get_ymax(self):
+        return self.get_points()[1, 1]
+    ymax = property(_get_ymax)
+
+    def _get_min(self):
+        return self.get_points()[0]
+    min = property(_get_min)
+    
+    def _get_max(self):
+        return self.get_points()[1]
+    max = property(_get_max)
+    
+    def _get_intervalx(self):
+        return self.get_points()[:, 0]
+    intervalx = property(_get_intervalx)
+
+    def _get_intervaly(self):
+        return self.get_points()[:, 1]
+    intervaly = property(_get_intervaly)
+                         
+    def _get_width(self):
+        return self.xmax - self.xmin
+    width = property(_get_width)
+
+    def _get_height(self):
+        return self.ymax - self.ymin
+    height = property(_get_height)
+
+    def _get_bounds(self):
+        return (self.xmin, self.ymin,
+                self.xmax - self.xmin, self.ymax - self.ymin)
+    bounds = property(_get_bounds)
+
+    def get_points(self):
+        return NotImplementedError()
+
+    # MGDTODO: Optimize
+    def containsx(self, x):
+        return x >= self.xmin and x <= self.xmax
+
+    def containsy(self, y):
+        return y >= self.ymin and y <= self.ymax
+    
+    def contains(self, x, y):
+        return self.containsx(x) and self.containsy(y)
+
+    def overlapsx(self, other):
+        return self.containsx(other.xmin) \
+            or self.containsx(other.xmax)
+
+    def overlapsy(self, other):
+        return self.containsy(other.ymin) \
+            or self.containsx(other.ymax)
+    
+    def overlaps(self, other):
+        return self.overlapsx(other) \
+            and self.overlapsy(other)
+    
+    def fully_containsx(self, x):
+        return x > self.xmin and x < self.xmax
+
+    def fully_containsy(self, y):
+        return y > self.ymin and y < self.ymax
+    
+    def fully_contains(self, x, y):
+        return self.fully_containsx(x) \
+            and self.fully_containsy(y)
+
+    def fully_overlapsx(self, other):
+        return self.fully_containsx(other.xmin) \
+            or self.fully_containsx(other.xmax)
+
+    def fully_overlapsy(self, other):
+        return self.fully_containsy(other.ymin) \
+            or self.fully_containsx(other.ymax)
+    
+    def fully_overlaps(self, other):
+        return self.fully_overlapsx(other) and \
+            self.fully_overlapsy(other)
+
+    
+class Bbox(BboxBase):
     def __init__(self, points):
-       TransformNode.__init__(self)
-       self._points = npy.asarray(points, npy.float_)
-       self.track = False
+        BboxBase.__init__(self)
+        self._points = npy.asarray(points, npy.float_)
 
     [EMAIL PROTECTED]
     def unit():
-       return Bbox.from_lbrt(0., 0., 1., 1.)
+        return Bbox.from_lbrt(0., 0., 1., 1.)
     unit = staticmethod(unit)
 
     [EMAIL PROTECTED]
     def from_lbwh(left, bottom, width, height):
-       return Bbox.from_lbrt(left, bottom, left + width, bottom + height)
+        return Bbox.from_lbrt(left, bottom, left + width, bottom + height)
     from_lbwh = staticmethod(from_lbwh)
 
     [EMAIL PROTECTED]
     def from_lbrt(*args):
-       points = npy.array(args, dtype=npy.float_).reshape(2, 2)
-       return Bbox(points)
+        points = npy.array(args, dtype=npy.float_).reshape(2, 2)
+        return Bbox(points)
     from_lbrt = staticmethod(from_lbrt)
     
     def __copy__(self):
-       return Bbox(self._points.copy())
+        return Bbox(self._points.copy())
 
     def __deepcopy__(self, memo):
-       return Bbox(self._points.copy())
+        return Bbox(self._points.copy())
     
     def __cmp__(self, other):
-       # MGDTODO: Totally suboptimal
-       if isinstance(other, Bbox) and (self._points == other._points).all():
-           return 0
-       return -1
+        # MGDTODO: Totally suboptimal
+        if isinstance(other, Bbox) and (self._points == other._points).all():
+            return 0
+        return -1
 
     def __repr__(self):
-       return 'Bbox(%s)' % repr(self._points)
+        return 'Bbox(%s)' % repr(self._points)
     __str__ = __repr__
 
-    def __array__(self):
-       return self._points
-    
     # JDH: the update method will update the box limits from the
     # existing limits and the new data; it appears here you are just
     # using the new data.  We use an "ignore" flag to specify whether
     # you want to include the existing data or not in the update
     def update_from_data(self, x, y, ignore=True):
-       self._points = npy.array([[x.min(), y.min()], [x.max(), y.max()]], 
npy.float_)
-       self.invalidate()
+        self._points = npy.array(
+            [[x.min(), y.min()], [x.max(), y.max()]],
+            npy.float_)
+        self.invalidate()
 
     # MGDTODO: Probably a more efficient ways to do this...
-    def _get_xmin(self):
-       return self._points[0, 0]
     def _set_xmin(self, val):
-       self._points[0, 0] = val
-       self.invalidate()
-    xmin = property(_get_xmin, _set_xmin)
+        self._points[0, 0] = val
+        self.invalidate()
+    xmin = property(BboxBase._get_xmin, _set_xmin)
 
-    def _get_ymin(self):
-       return self._points[0, 1]
     def _set_ymin(self, val):
-       self._points[0, 1] = val
-       self.invalidate()
-    ymin = property(_get_ymin, _set_ymin)
+        self._points[0, 1] = val
+        self.invalidate()
+    ymin = property(BboxBase._get_ymin, _set_ymin)
 
-    def _get_xmax(self):
-       return self._points[1, 0]
     def _set_xmax(self, val):
-       self._points[1, 0] = val
-       self.invalidate()
-    xmax = property(_get_xmax, _set_xmax)
+        self._points[1, 0] = val
+        self.invalidate()
+    xmax = property(BboxBase._get_xmax, _set_xmax)
 
-    def _get_ymax(self):
-       return self._points[1, 1]
     def _set_ymax(self, val):
-       self._points[1, 1] = val
-       self.invalidate()
-    ymax = property(_get_ymax, _set_ymax)
+        self._points[1, 1] = val
+        self.invalidate()
+    ymax = property(BboxBase._get_ymax, _set_ymax)
 
-    def _get_min(self):
-       return self._points[0]
     def _set_min(self, val):
-       self._points[0] = val
-       self.invalidate()
-    min = property(_get_min, _set_min)
+        self._points[0] = val
+        self.invalidate()
+    min = property(BboxBase._get_min, _set_min)
     
-    def _get_max(self):
-       return self._points[1]
     def _set_max(self, val):
-       self._points[1] = val
-       self.invalidate()
-    max = property(_get_max, _set_max)
+        self._points[1] = val
+        self.invalidate()
+    max = property(BboxBase._get_max, _set_max)
     
-    def _get_intervalx(self):
-       return self._points[:,0]
     def _set_intervalx(self, interval):
-       self._points[:,0] = interval
-       self.invalidate()
-    intervalx = property(_get_intervalx, _set_intervalx)
+        self._points[:, 0] = interval
+        self.invalidate()
+    intervalx = property(BboxBase._get_intervalx, _set_intervalx)
 
-    def _get_intervaly(self):
-       return self._points[:,1]
     def _set_intervaly(self, interval):
-       self._points[:,1] = interval
-       self.invalidate()
-    intervaly = property(_get_intervaly, _set_intervaly)
+        self._points[:, 1] = interval
+        self.invalidate()
+    intervaly = property(BboxBase._get_intervaly, _set_intervaly)
 
-    def _get_width(self):
-       return self.xmax - self.xmin
-    width = property(_get_width)
+    def _set_bounds(self, bounds):
+        l,b,w,h = bounds
+        self._points = npy.array([[l, b], [l+w, b+h]], npy.float_)
+        self.invalidate()
+    bounds = property(BboxBase._get_bounds, _set_bounds)
 
-    def _get_height(self):
-       return self.ymax - self.ymin
-    height = property(_get_height)
+    def get_points(self):
+        return self._points
 
-    def _get_bounds(self):
-       return (self.xmin, self.ymin,
-               self.xmax - self.xmin, self.ymax - self.ymin)
-    def _set_bounds(self, bounds):
-       l,b,w,h = bounds
-       self._points = npy.array([[l, b], [l+w, b+h]], npy.float_)
-       self.invalidate()
-    bounds = property(_get_bounds, _set_bounds)
-       
+    def set_points(self, points):
+        self._points = points
+        self.invalidate()
+
+    def set(self, other):
+        self._points = other.get_points()
+        self.invalidate()
+        
     def transformed(self, transform):
-       return Bbox(transform(self._points))
+        return Bbox(transform(self._points))
 
     def inverse_transformed(self, transform):
-       return Bbox(transform.inverted()(self._points))
+        return Bbox(transform.inverted()(self._points))
     
     def expanded(self, sw, sh):
-       width = self.width
-       height = self.height
-       deltaw = (sw * width - width) / 2.0
-       deltah = (sh * height - height) / 2.0
-       a = npy.array([[-deltaw, -deltah], [deltaw, deltah]])
-       return Bbox(self._points + a)
+        width = self.width
+        height = self.height
+        deltaw = (sw * width - width) / 2.0
+        deltah = (sh * height - height) / 2.0
+        a = npy.array([[-deltaw, -deltah], [deltaw, deltah]])
+        return Bbox(self._points + a)
 
-    def contains(self, x, y):
-       return (x >= self.xmin and x <= self.xmax and
-               y >= self.ymin and y <= self.ymax)
-
     [EMAIL PROTECTED]
     def union(bboxes):
-       """
-       Return the Bbox that bounds all bboxes
-       """
-       assert(len(bboxes))
+        """
+        Return the Bbox that bounds all bboxes
+        """
+        assert(len(bboxes))
 
-       if len(bboxes) == 1:
-           return bboxes[0]
+        if len(bboxes) == 1:
+            return bboxes[0]
 
-       bbox = bboxes[0]
-       xmin = bbox.xmin
-       ymin = bbox.ymin
-       xmax = bbox.xmax
-       ymax = bbox.ymax
+        bbox = bboxes[0]
+        xmin = bbox.xmin
+        ymin = bbox.ymin
+        xmax = bbox.xmax
+        ymax = bbox.ymax
 
-       for bbox in bboxes[1:]:
-           xmin = min(xmin, bbox.xmin)
-           ymin = min(ymin, bbox.ymin)
-           xmax = max(xmax, bbox.xmax)
-           ymax = max(ymax, bbox.ymax)
+        for bbox in bboxes[1:]:
+            xmin = min(xmin, bbox.xmin)
+            ymin = min(ymin, bbox.ymin)
+            xmax = max(xmax, bbox.xmax)
+            ymax = max(ymax, bbox.ymax)
 
-       return Bbox.from_lbrt(xmin, ymin, xmax, ymax)
+        return Bbox.from_lbrt(xmin, ymin, xmax, ymax)
     union = staticmethod(union)
+
+class TransformedBbox(BboxBase):
+    def __init__(self, bbox, transform):
+        assert isinstance(bbox, Bbox)
+        assert isinstance(transform, Transform)
+
+        BboxBase.__init__(self)
+        self.bbox = bbox
+        self.transform = transform
+        self.set_children(['bbox', 'transform'])
+        self._points = None
+
+    def __repr__(self):
+        return "TransformedBbox(%s, %s)" % (self.bbox, self.transform)
+    __str__ = __repr__
     
+    def _do_invalidation(self):
+        self._points = None
+
+    def get_points(self):
+        if self._points is None:
+            self._points = self.transform(self.bbox.get_points())
+        return self._points
+
+# MGDTODO: This code probably works, but I don't think it's a good idea
+# (from a code clarity perspective)
+# class BlendedBbox(BboxBase):
+#     def __init__(self, bbox_x, bbox_y):
+#         assert isinstance(bbox_x, BboxBase)
+#         assert isinstance(bbox_y, BboxBase)
+
+#         BboxBase.__init__(self)
+#         self._x = bbox_x
+#         self._y = bbox_y
+#         self.set_children(['_x', '_y'])
+#         self._points = None
+
+#     def __repr__(self):
+#         return "TransformedBbox(%s, %s)" % (self.bbox, self.transform)
+#     __str__ = __repr__
+    
+#     def _do_invalidation(self):
+#         self._points = None
+
+#     def get_points(self):
+#         if self._points is None:
+#             # MGDTODO: Optimize
+#             if self._x == self._y:
+#                 self._points = self._x.get_points()
+#             else:
+#                 x_points = self._x.get_points()
+#                 y_points = self._y.get_points()
+#                 self._points = npy.array(
+#                     [[x_points[0,0], y_points[0,1]],
+#                      [x_points[1,0], y_points[1,1]]],
+#                     npy.float_)
+#         return self._points
+
+#     def _set_intervalx(self, pair):
+#         # MGDTODO: Optimize
+#         bbox = Bbox([[pair[0], 0.0], [pair[1], 0.0]])
+#         self.replace_child(0, bbox)
+#     intervalx = property(BboxBase._get_intervalx, _set_intervalx)
+
+#     def _set_intervaly(self, pair):
+#         # MGDTODO: Optimize
+#         bbox = Bbox([[0.0, pair[0]], [0.0, pair[1]]])
+#         self.replace_child(1, bbox)
+#     intervaly = property(BboxBase._get_intervaly, _set_intervaly)
+    
 class Transform(TransformNode):
     def __init__(self):
-       TransformNode.__init__(self)
+        TransformNode.__init__(self)
     
     def __call__(self, points):
-       raise NotImplementedError()
+        raise NotImplementedError()
 
     def __add__(self, other):
-       if isinstance(other, Transform):
-           return composite_transform_factory(self, other)
-       raise TypeError("Can not add Transform to object of type '%s'" % 
type(other))
+        if isinstance(other, Transform):
+            return composite_transform_factory(self, other)
+        raise TypeError(
+            "Can not add Transform to object of type '%s'" % type(other))
 
     def __radd__(self, other):
-       if isinstance(other, Transform):
-           return composite_transform_factory(other, self)
-       raise TypeError("Can not add Transform to object of type '%s'" % 
type(other))
+        if isinstance(other, Transform):
+            return composite_transform_factory(other, self)
+        raise TypeError(
+            "Can not add Transform to object of type '%s'" % type(other))
 
     def transform_point(self, point):
-       return self.__call__(npy.asarray([point]))[0]
+        return self.__call__(npy.asarray([point]))[0]
     
     def has_inverse(self):
-       raise NotImplementedError()
+        raise NotImplementedError()
     
     def inverted(self):
-       raise NotImplementedError()
+        raise NotImplementedError()
 
     def is_separable(self):
-       return False
+        return False
 
     def is_affine(self):
-       return False
+        return False
 
 class Affine2DBase(Transform):
     input_dims = 2
     output_dims = 2
 
     def __init__(self):
-       Transform.__init__(self)
-       self._inverted = None
+        Transform.__init__(self)
+        self._inverted = None
 
     def _do_invalidation(self):
-       result = self._inverted is None
-       self._inverted = None
-       return result
+        result = self._inverted is None
+        self._inverted = None
+        return result
 
     [EMAIL PROTECTED]
     def _concat(a, b):
         return npy.dot(b, a)
     _concat = staticmethod(_concat)
+
+    [EMAIL PROTECTED]
+    def concat(a, b):
+        return Affine2D(Affine2D._concat(a.get_matrix(), b.get_matrix()))
+    concat = staticmethod(concat)
     
     def to_values(self):
-       mtx = self.get_matrix()
-       return tuple(mtx[:2].swapaxes(0, 1).flatten())
+        mtx = self.get_matrix()
+        return tuple(mtx[:2].swapaxes(0, 1).flatten())
     
     [EMAIL PROTECTED]
     def matrix_from_values(a, b, c, d, e, f):
-       affine = npy.zeros((3,3), npy.float_)
-       affine[0,] = a, c, e
-       affine[1,] = b, d, f
-       affine[2,2] = 1
-       return affine
+        affine = npy.zeros((3, 3), npy.float_)
+        affine[0,  ] = a, c, e
+        affine[1,  ] = b, d, f
+        affine[2, 2] = 1
+        return affine
     matrix_from_values = staticmethod(matrix_from_values)
 
     def get_matrix(self):
-       raise NotImplementedError()
+        raise NotImplementedError()
     
     def __call__(self, points):
         """
         Applies the transformation to an array of 2D points and
-       returns the result.
+        returns the result.
 
-       points must be a numpy array of shape (N, 2), where N is the
-       number of points.
-       """
-       # MGDTODO: The major speed trap here is just converting to
-       # the points to an array in the first place.  If we can use
-       # more arrays upstream, that should help here.
-       mtx = self.get_matrix()
-       points = npy.asarray(points, npy.float_)
-       points = points.transpose()
-       points = npy.dot(mtx[0:2, 0:2], points)
-       points = points + mtx[0:2, 2:]
-       return points.transpose()
+        points must be a numpy array of shape (N, 2), where N is the
+        number of points.
+        """
+        # MGDTODO: The major speed trap here is just converting to
+        # the points to an array in the first place.  If we can use
+        # more arrays upstream, that should help here.
+        if not isinstance(points, npy.ndarray):
+            import traceback
+            print '-' * 60
+            print 'A non-numpy array was passed in for transformation.  Please 
'
+            print 'correct this.'
+            print "".join(traceback.format_stack())
+            print points
+        mtx = self.get_matrix()
+        points = npy.asarray(points, npy.float_)
+        points = points.transpose()
+        points = npy.dot(mtx[0:2, 0:2], points)
+        points = points + mtx[0:2, 2:]
+        return points.transpose()
     
     def inverted(self):
-       if self._inverted is None:
-           mtx = self.get_matrix()
-           self._inverted = Affine2D(inv(mtx))
-       return self._inverted
+        if self._inverted is None:
+            mtx = self.get_matrix()
+            self._inverted = Affine2D(inv(mtx))
+        return self._inverted
     
     def is_separable(self):
-       mtx = self.get_matrix()
-       return mtx[0, 1] == 0.0 and mtx[1, 0] == 0.0
+        mtx = self.get_matrix()
+        return mtx[0, 1] == 0.0 and mtx[1, 0] == 0.0
 
     def is_affine(self):
-       return True
+        return True
 
-       
+        
 class Affine2D(Affine2DBase):
     input_dims = 2
     output_dims = 2
@@ -310,29 +487,29 @@
         b d f
         0 0 1
         """
-       Affine2DBase.__init__(self)
-       if matrix is None:
-           matrix = npy.identity(3)
-       else:
-           assert matrix.shape == (3, 3)
-       self._mtx = matrix
-       self._inverted = None
+        Affine2DBase.__init__(self)
+        if matrix is None:
+            matrix = npy.identity(3)
+        else:
+            assert matrix.shape == (3, 3)
+        self._mtx = matrix
+        self._inverted = None
 
     def __repr__(self):
-       return "Affine2D(%s)" % repr(self._mtx)
+        return "Affine2D(%s)" % repr(self._mtx)
     __str__ = __repr__
 
     def __cmp__(self, other):
-       if (isinstance(other, Affine2D) and
-           (self.get_matrix() == other.get_matrix()).all()):
-           return 0
-       return -1
+        if (isinstance(other, Affine2D) and
+            (self.get_matrix() == other.get_matrix()).all()):
+            return 0
+        return -1
     
     def __copy__(self):
-       return Affine2D(self._mtx.copy())
+        return Affine2D(self._mtx.copy())
     
     def __deepcopy__(self, memo):
-       return Affine2D(self._mtx.copy())
+        return Affine2D(self._mtx.copy())
     
     [EMAIL PROTECTED]
     def from_values(a, b, c, d, e, f):
@@ -340,209 +517,224 @@
     from_values = staticmethod(from_values)
 
     def get_matrix(self):
-       return self._mtx
+        return self._mtx
+
+    def set_matrix(self, mtx):
+        self._mtx = mtx
+        self.invalidate()
+
+    def set(self, other):
+        self._mtx = other.get_matrix()
+        self.invalidate()
     
     [EMAIL PROTECTED]
-    def concat(a, b):
-       return Affine2D(Affine2D._concat(a._mtx, b._mtx))
-    concat = staticmethod(concat)
-    
-    [EMAIL PROTECTED]
     def identity():
         return Affine2D(npy.identity(3))
     identity = staticmethod(identity)
 
+    def clear(self):
+        self._mtx = npy.identity(3)
+        self.invalidate()
+        return self
+    
     def rotate(self, theta):
         a = npy.cos(theta)
         b = npy.sin(theta)
         rotate_mtx = self.matrix_from_values(a, b, -b, a, 0, 0)
         self._mtx = self._concat(self._mtx, rotate_mtx)
-       self.invalidate()
-       return self
+        self.invalidate()
+        return self
 
     def rotate_deg(self, degrees):
         return self.rotate(degrees*npy.pi/180.)
 
+    def rotate_around(self, x, y, theta):
+        return self.translate(-x, -y).rotate(theta).translate(x, y)
+
+    def rotate_deg_around(self, x, y, degrees):
+        return self.translate(-x, -y).rotate_deg(degrees).translate(x, y)
+    
     def translate(self, tx, ty):
         translate_mtx = self.matrix_from_values(1., 0., 0., 1., tx, ty)
         self._mtx = self._concat(self._mtx, translate_mtx)
-       self.invalidate()
-       return self
+        self.invalidate()
+        return self
 
     def scale(self, sx, sy=None):
-       if sy is None:
-           sy = sx
-       scale_mtx = self.matrix_from_values(sx, 0., 0., sy, 0., 0.)
+        if sy is None:
+            sy = sx
+        scale_mtx = self.matrix_from_values(sx, 0., 0., sy, 0., 0.)
         self._mtx = self._concat(self._mtx, scale_mtx)
-       self.invalidate()
-       return self
+        self.invalidate()
+        return self
 
     def inverted(self):
-       if self._inverted is None:
-           mtx = self.get_matrix()
-           self._inverted = Affine2D(inv(mtx))
-       return self._inverted
+        if self._inverted is None:
+            mtx = self.get_matrix()
+            self._inverted = Affine2D(inv(mtx))
+        return self._inverted
     
     def is_separable(self):
-       mtx = self.get_matrix()
-       return mtx[0, 1] == 0.0 and mtx[1, 0] == 0.0
+        mtx = self.get_matrix()
+        return mtx[0, 1] == 0.0 and mtx[1, 0] == 0.0
 
     def is_affine(self):
-       return True
+        return True
     
-class BlendedAffine2D(Affine2DBase):
+class BlendedTransform(Transform):
     def __init__(self, x_transform, y_transform):
-       assert x_transform.is_affine()
-       assert y_transform.is_affine()
-       assert x_transform.is_separable()
-       assert y_transform.is_separable()
+        assert x_transform.is_separable()
+        assert y_transform.is_separable()
 
-       Affine2DBase.__init__(self)
-       self.add_children([x_transform, y_transform])
-       self._x = x_transform
-       self._y = y_transform
-       self._mtx = None
+        Transform.__init__(self)
+        self._x = x_transform
+        self._y = y_transform
+        self.set_children(['_x', '_y'])
 
+    def __call__(self, points):
+        if self._x == self._y:
+            return self._x(points)
+        
+        x_points = self._x(points)
+        y_points = self._y(points)
+        # This works because we already know the transforms are
+        # separable
+        return npy.hstack((x_points[:, 0:1], y_points[:, 1:2]))
+
+#     def set_x_transform(self, x_transform):
+#         self.replace_child(0, x_transform)
+
+#     def set_y_transform(self, y_transform):
+#         self.replace_child(1, y_transform)
+    
+class BlendedAffine2D(Affine2DBase, BlendedTransform):
+    def __init__(self, x_transform, y_transform):
+        assert x_transform.is_affine()
+        assert y_transform.is_affine()
+        assert x_transform.is_separable()
+        assert y_transform.is_separable()
+        BlendedTransform.__init__(self, x_transform, y_transform)
+        
+        Affine2DBase.__init__(self)
+        self._mtx = None
+
     def __repr__(self):
-       return "BlendedAffine2D(%s,%s)" % (self._x, self._y)
+        return "BlendedAffine2D(%s,%s)" % (self._x, self._y)
     __str__ = __repr__
-       
+        
     def _do_invalidation(self):
-       if self._mtx is not None:
-           self._mtx = None
-           Affine2DBase._do_invalidation(self)
-           return False
-       return True
+        if self._mtx is not None:
+            self._mtx = None
+            Affine2DBase._do_invalidation(self)
+            return False
+        return True
 
-    def _make__mtx(self):
-       if self._mtx is None:
-           x_mtx = self._x.get_matrix()
-           y_mtx = self._y.get_matrix()
-           # This works because we already know the transforms are
-           # separable, though normally one would want to set b and
-           # c to zero.
-           self._mtx = npy.vstack((x_mtx[0], y_mtx[1], [0.0, 0.0, 1.0]))
-       
     def is_separable(self):
-       return True
+        return True
 
     def get_matrix(self):
-       self._make__mtx()
-       return self._mtx
+        if self._mtx is None:
+            if self._x == self._y:
+                self._mtx = self._x.get_matrix()
+            else:
+                x_mtx = self._x.get_matrix()
+                y_mtx = self._y.get_matrix()
+                # This works because we already know the transforms are
+                # separable, though normally one would want to set b and
+                # c to zero.
+                self._mtx = npy.vstack((x_mtx[0], y_mtx[1], [0.0, 0.0, 1.0]))
+        return self._mtx
+        
+class CompositeTransform(Transform):
+    def __init__(self, a, b):
+        assert a.output_dims == b.input_dims
+        self.input_dims = a.input_dims
+        self.output_dims = b.output_dims
+        
+        Transform.__init__(self)
+        self._a = a
+        self._b = b
+        self.set_children(['_a', '_b'])
+        
+    def __call__(self, points):
+        return self._b(self._a(points))
     
-class BlendedTransform(Transform):
-    def __init__(self, x_transform, y_transform):
-       assert x_transform.is_separable()
-       assert y_transform.is_separable()
-
-       Transform.__init__(self)
-       self.add_children([x_transform, y_transform])
-       self._x = x_transform
-       self._y = y_transform
-
-    def __call__(self, points):
-       x_points = self._x(points)
-       y_points = self._y(points)
-       # This works because we already know the transforms are
-       # separable
-       return npy.hstack((x_points[:, 0:1], y_points[:, 1:2]))
-
 class CompositeAffine2D(Affine2DBase):
     def __init__(self, a, b):
-       assert a.is_affine()
-       assert b.is_affine()
+        assert a.is_affine()
+        assert b.is_affine()
 
-       Affine2DBase.__init__(self)
-       self.add_children([a, b])
-       self._a = a
-       self._b = b
-       self._mtx = None
+        Affine2DBase.__init__(self)
+        self._a = a
+        self._b = b
+        self.set_children(['_a', '_b'])
+        self._mtx = None
 
     def __repr__(self):
-       return "CompositeAffine2D(%s, %s)" % (self._a, self._b)
+        return "CompositeAffine2D(%s, %s)" % (self._a, self._b)
     __str__ = __repr__
 
     def _do_invalidation(self):
-       self._mtx = None
-       Affine2DBase._do_invalidation(self)
+        self._mtx = None
+        Affine2DBase._do_invalidation(self)
     
-    def _make__mtx(self):
-       if self._mtx is None:
-           self._mtx = self._concat(
-               self._a.get_matrix(),
-               self._b.get_matrix())
-
     def get_matrix(self):
-       self._make__mtx()
-       return self._mtx
-       
-class CompositeTransform(Transform):
-    def __init__(self, a, b):
-       assert a.output_dims == b.input_dims
-       self.input_dims = a.input_dims
-       self.output_dims = b.output_dims
-       
-       Transform.__init__(self)
-       self.add_children([a, b])
-       self._a = a
-       self._b = b
+        if self._mtx is None:
+            self._mtx = self._concat(
+                self._a.get_matrix(),
+                self._b.get_matrix())
+        return self._mtx
 
-    def __call__(self, points):
-       return self._b(self._a(points))
-
 class BboxTransform(Affine2DBase):
     def __init__(self, boxin, boxout):
-       assert isinstance(boxin, Bbox)
-       assert isinstance(boxout, Bbox)
+        assert isinstance(boxin, BboxBase)
+        assert isinstance(boxout, BboxBase)
 
-       Affine2DBase.__init__(self)
-       self.add_children([boxin, boxout])
-       self._boxin = boxin
-       self._boxout = boxout
-       self._mtx = None
-       self._inverted = None
+        Affine2DBase.__init__(self)
+        self._boxin = boxin
+        self._boxout = boxout
+        self.set_children(['_boxin', '_boxout'])
+        self._mtx = None
+        self._inverted = None
 
     def __repr__(self):
-       return "BboxTransform(%s, %s)" % (self._boxin, self._boxout)
+        return "BboxTransform(%s, %s)" % (self._boxin, self._boxout)
     __str__ = __repr__
-       
+        
     def _do_invalidation(self):
-       if self._mtx is not None:
-           self._mtx = None
-           Affine2DBase._do_invalidation(self)
-           return False
-       return True
+        if self._mtx is not None:
+            self._mtx = None
+            Affine2DBase._do_invalidation(self)
+            return False
+        return True
 
-    def _make__mtx(self):
-       if self._mtx is None:
-           boxin = self._boxin
-           boxout = self._boxout
-           x_scale = boxout.width / boxin.width
-           y_scale = boxout.height / boxin.height
+    def is_separable(self):
+        return True
 
-           # MGDTODO: Optimize
-           affine = Affine2D() \
-               .translate(-boxin.xmin, -boxin.ymin) \
-               .scale(x_scale, y_scale) \
-               .translate(boxout.xmin, boxout.ymin)
+    def get_matrix(self):
+        if self._mtx is None:
+            boxin = self._boxin
+            boxout = self._boxout
+            x_scale = boxout.width / boxin.width
+            y_scale = boxout.height / boxin.height
 
-           self._mtx = affine._mtx
-       
-    def is_separable(self):
-       return True
+            # MGDTODO: Optimize
+            affine = Affine2D() \
+                .translate(-boxin.xmin, -boxin.ymin) \
+                .scale(x_scale, y_scale) \
+                .translate(boxout.xmin, boxout.ymin)
 
-    def get_matrix(self):
-       self._make__mtx()
-       return self._mtx
-    
+            self._mtx = affine._mtx
+        return self._mtx
+
 def blend_xy_sep_transform(x_transform, y_transform):
     if x_transform.is_affine() and y_transform.is_affine():
-       return BlendedAffine2D(x_transform, y_transform)
+        return BlendedAffine2D(x_transform, y_transform)
     return BlendedTransform(x_transform, y_transform)
 
 def composite_transform_factory(a, b):
     if a.is_affine() and b.is_affine():
-       return CompositeAffine2D(a, b)
+        return CompositeAffine2D(a, b)
     return CompositeTransform(a, b)
 
 # MGDTODO: There's probably a better place for this
@@ -562,7 +754,7 @@
         vmin, vmax = vmax, vmin
         swapped = True
     if vmax - vmin <= max(abs(vmin), abs(vmax)) * tiny:
-        if vmin==0.0:
+        if vmin == 0.0:
             vmin = -expander
             vmax = expander
         else:
@@ -635,8 +827,8 @@
     assert scale.to_values() == (10, 0, 0, 20, 0, 0)
     rotation = Affine2D().rotate_deg(30)
     print rotation.to_values() == (0.86602540378443871, 0.49999999999999994,
-                                  -0.49999999999999994, 0.86602540378443871,
-                                  0.0, 0.0)
+                                   -0.49999999999999994, 0.86602540378443871,
+                                   0.0, 0.0)
     
     points = npy.array([[1,2],[3,4],[5,6],[7,8]], npy.float_)
     translated_points = translation(points)

Modified: branches/transforms/lib/matplotlib/artist.py
===================================================================
--- branches/transforms/lib/matplotlib/artist.py        2007-09-13 12:50:05 UTC 
(rev 3847)
+++ branches/transforms/lib/matplotlib/artist.py        2007-09-13 18:00:10 UTC 
(rev 3848)
@@ -21,7 +21,7 @@
 # 
http://groups.google.com/groups?hl=en&lr=&threadm=mailman.5090.1098044946.5135.python-list%40python.org&rnum=1&prev=/groups%3Fq%3D__doc__%2Bauthor%253Ajdhunter%2540ace.bsd.uchicago.edu%26hl%3Den%26btnG%3DGoogle%2BSearch
 
 
-class Artist:
+class Artist(object):
     """
     Abstract base class for someone who renders into a FigureCanvas
     """

Modified: branches/transforms/lib/matplotlib/axes.py
===================================================================
--- branches/transforms/lib/matplotlib/axes.py  2007-09-13 12:50:05 UTC (rev 
3847)
+++ branches/transforms/lib/matplotlib/axes.py  2007-09-13 18:00:10 UTC (rev 
3848)
@@ -436,8 +436,7 @@
               }
 
     def __str__(self):
-        return 
"Axes(%g,%g;%gx%g)"%(self._position[0].get(),self._position[1].get(),
-                                    
self._position[2].get(),self._position[3].get())
+        return "Axes(%g,%g;%gx%g)" % tuple(self._position.bounds)
     def __init__(self, fig, rect,
                  axisbg = None, # defaults to rc axes.facecolor
                  frameon = True,
@@ -590,13 +589,13 @@
 
         def follow_foreign_ylim(ax):
             ymin, ymax = axforeign.get_ylim()
-            # do not emit here or we'll get a ping png effect
+            # do not emit here or we'll get a ping pong effect
             self.set_ylim(ymin, ymax, emit=False)
             self.figure.canvas.draw_idle()
 
         def follow_self_ylim(ax):
             ymin, ymax = self.get_ylim()
-            # do not emit here or we'll get a ping png effect
+            # do not emit here or we'll get a ping pong effect
             axforeign.set_ylim(ymin, ymax, emit=False)
             axforeign.figure.canvas.draw_idle()
 
@@ -613,65 +612,66 @@
         """
         martist.Artist.set_figure(self, fig)
 
-        l, b, w, h = self._position.bounds
-        xmin = fig.bbox.xmin
-        xmax = fig.bbox.xmax
-        ymin = fig.bbox.ymin
-        ymax = fig.bbox.ymax
-        figw = xmax-xmin
-        figh = ymax-ymin
-        self.left   =  l*figw
-        self.bottom =  b*figh
-        self.right  =  (l+w)*figw
-        self.top    =  (b+h)*figh
-
-        self.bbox = maffine.Bbox.from_lbrt(
-            self.left, self.bottom,
-            self.right, self.top,
-            )
+        self.bbox = maffine.TransformedBbox(self._position, fig.transFigure)
         #these will be updated later as data is added
         self._set_lim_and_transforms()
 
+    def _shared_xlim_callback(self, ax):
+       xmin, xmax = ax.get_xlim()
+       self.set_xlim(xmin, xmax, emit=False)
+       self.figure.canvas.draw_idle()
+
+    def _shared_ylim_callback(self, ax):
+       ymin, ymax = ax.get_ylim()
+       self.set_ylim(ymin, ymax, emit=False)
+       self.figure.canvas.draw_idle()
+       
     def _set_lim_and_transforms(self):
         """
         set the dataLim and viewLim BBox attributes and the
         transData and transAxes Transformation attributes
         """
-        Bbox = maffine.Bbox
+       Bbox = maffine.Bbox
+       self.viewLim = Bbox.unit()
+       
         if self._sharex is not None:
-            left = self._sharex.viewLim.xmin()
-            right = self._sharex.viewLim.xmax()
-        else:
-            left = 0.0
-            right = 1.0
+           # MGDTODO: This may be doing at least one too many updates
+           # than necessary
+           self._sharex.callbacks.connect(
+               'xlim_changed', self._shared_xlim_callback)
+           self.viewLim.intervalx = self._sharex.viewLim.intervalx
         if self._sharey is not None:
-            bottom = self._sharey.viewLim.ymin()
-            top = self._sharey.viewLim.ymax()
-        else:
-            bottom = 0.0
-            top = 1.0
+           self._sharey.callbacks.connect(
+               'ylim_changed', self._shared_ylim_callback)
+           self.viewLim.intervaly = self._sharex.viewLim.intervaly
 
-        self.viewLim = Bbox.from_lbrt(left, bottom, right, top)
        self.dataLim = Bbox.unit()
        
-        self.transData = maffine.BboxTransform(
-            self.viewLim, self.bbox)
         self.transAxes = maffine.BboxTransform(
             Bbox.unit(), self.bbox)
 
-       # MGDTODO
-#         if self._sharex:
-#             self.transData.set_funcx(self._sharex.transData.get_funcx())
-
-#         if self._sharey:
-#             self.transData.set_funcy(self._sharey.transData.get_funcy())
-
+        localTransData = maffine.BboxTransform(
+            self.viewLim, self.bbox)
+       if self._sharex:
+           transDataX = self._sharex.transData
+       else:
+           transDataX = localTransData
+       if self._sharey:
+           transDataY = self._sharey.transData
+       else:
+           transDataY = localTransData
+       self.transData = localTransData # 
maffine.blend_xy_sep_transform(transDataX, transDataY)
+           
+           
     def get_position(self, original=False):
         'Return the axes rectangle left, bottom, width, height'
+       # MGDTODO: This changed from returning a list to returning a Bbox
+       # If you get any errors with the result of this function, please
+       # update the calling code
         if original:
-            return self._originalPosition.bounds
+            return copy.copy(self._originalPosition)
         else:
-            return self._position.bounds
+            return copy.copy(self._position)
            # return [val.get() for val in self._position]
 
     def set_position(self, pos, which='both'):
@@ -690,14 +690,9 @@
         ACCEPTS: len(4) sequence of floats
         """
         if which in ('both', 'active'):
-           # MGDTODO
-#             # Change values within self._position--don't replace it.
-#             for num,val in zip(pos, self._position):
-#                 val.set(num)
-           self._position.bounds = pos.bounds
-           # MGDTODO: side-effects
+           self._position.set(pos)
         if which in ('both', 'original'):
-            self._originalPosition.bounds = pos.bounds
+            self._originalPosition.set(pos)
            
            
     def _set_artist_props(self, a):
@@ -1546,7 +1541,14 @@
         xmin, xmax = maffine.nonsingular(xmin, xmax, increasing=False)
 
        self.viewLim.intervalx = (xmin, xmax)
-       
+        if emit:
+           self.callbacks.process('xlim_changed', self)
+           # MGDTODO: It would be nice to do this is in the above callback 
list,
+           # but it's difficult to tell how to initialize this at the
+           # right time
+           if self._sharex:
+               self._sharex.set_xlim(*self.viewLim.intervalx)
+           
         return xmin, xmax
 
     def get_xscale(self):
@@ -1650,7 +1652,6 @@
 
         ACCEPTS: len(2) sequence of floats
         """
-
         if ymax is None and iterable(ymin):
             ymin,ymax = ymin
 
@@ -1671,8 +1672,14 @@
 
         ymin, ymax = maffine.nonsingular(ymin, ymax, increasing=False)
        self.viewLim.intervaly = (ymin, ymax)
-        if emit: self.callbacks.process('ylim_changed', self)
-       
+        if emit:
+           self.callbacks.process('ylim_changed', self)
+           # MGDTODO: It would be nice to do this is in the above callback 
list,
+           # but it's difficult to tell how to initialize this at the
+           # right time
+           if self._sharey:
+               self._sharey.set_ylim(*self.viewLim.intervaly)
+           
         return ymin, ymax
 
     def get_yscale(self):

Modified: branches/transforms/lib/matplotlib/axis.py
===================================================================
--- branches/transforms/lib/matplotlib/axis.py  2007-09-13 12:50:05 UTC (rev 
3847)
+++ branches/transforms/lib/matplotlib/axis.py  2007-09-13 18:00:10 UTC (rev 
3848)
@@ -1028,9 +1028,8 @@
         x,y = self.label.get_position()
         if self.label_position == 'bottom':
             if not len(bboxes):
-                bottom = self.axes.bbox.ymin()
+                bottom = self.axes.bbox.ymin
             else:
-
                 bbox = Bbox.union(bboxes)
                 bottom = bbox.ymin
 
@@ -1041,7 +1040,6 @@
             if not len(bboxes2):
                 top = self.axes.bbox.ymax
             else:
-
                 bbox = bbox_union(bboxes2)
                 top = bbox.ymax
 
@@ -1054,7 +1052,7 @@
         """
         x,y = self.offsetText.get_position()
         if not len(bboxes):
-            bottom = self.axes.bbox.ymin()
+            bottom = self.axes.bbox.ymin
         else:
             bbox = Bbox.union(bboxes)
             bottom = bbox.ymin

Modified: branches/transforms/lib/matplotlib/backend_bases.py
===================================================================
--- branches/transforms/lib/matplotlib/backend_bases.py 2007-09-13 12:50:05 UTC 
(rev 3847)
+++ branches/transforms/lib/matplotlib/backend_bases.py 2007-09-13 18:00:10 UTC 
(rev 3848)
@@ -752,7 +752,8 @@
         else: # Just found one hit
             self.inaxes = axes_list[0]
 
-        try: xdata, ydata = self.inaxes.transData.inverted()([[x, y]])[0]
+        try:
+           xdata, ydata = self.inaxes.transData.inverted().transform_point((x, 
y))
         except ValueError:
             self.xdata  = None
             self.ydata  = None
@@ -1584,8 +1585,8 @@
             lims.append( (xmin, xmax, ymin, ymax) )
             # Store both the original and modified positions
             pos.append( (
-                    tuple( a.get_position(True) ),
-                    tuple( a.get_position() ) ) )
+                   a.get_position(True),
+                    a.get_position() ) )
         self._views.push(lims)
         self._positions.push(pos)
         self.set_history_buttons()

Modified: branches/transforms/lib/matplotlib/figure.py
===================================================================
--- branches/transforms/lib/matplotlib/figure.py        2007-09-13 12:50:05 UTC 
(rev 3847)
+++ branches/transforms/lib/matplotlib/figure.py        2007-09-13 18:00:10 UTC 
(rev 3848)
@@ -18,7 +18,7 @@
 from text import Text, _process_text_args
 
 from legend import Legend
-from affine import Bbox, BboxTransform
+from affine import Affine2D, Bbox, BboxTransform, TransformedBbox
 from ticker import FormatStrFormatter
 from cm import ScalarMappable
 from contour import ContourSet
@@ -128,17 +128,15 @@
         if facecolor is None: facecolor = rcParams['figure.facecolor']
         if edgecolor is None: edgecolor = rcParams['figure.edgecolor']
 
+       self._dpi_scale_trans = Affine2D()
         self.dpi = dpi
-       figwidth = figsize[0] * dpi
-       figheight = figsize[1] * dpi
-       self.bbox = Bbox.from_lbwh(0, 0, figwidth, figheight)
+       self.bbox_inches = Bbox.from_lbwh(0, 0, *figsize)
+       self.bbox = TransformedBbox(self.bbox_inches, self._dpi_scale_trans)
        
         self.frameon = frameon
 
-        self.transFigure = BboxTransform( Bbox.unit(), self.bbox)
+        self.transFigure = BboxTransform(Bbox.unit(), self.bbox)
 
-
-
         self.figurePatch = Rectangle(
             xy=(0,0), width=1, height=1,
             facecolor=facecolor, edgecolor=edgecolor,
@@ -160,6 +158,15 @@
 
         self._cachedRenderer = None
 
+    def _get_dpi(self):
+       return self._dpi
+    def _set_dpi(self, dpi):
+       print "setting dpi"
+       self._dpi = dpi
+       self._dpi_scale_trans.clear().scale(dpi, dpi)
+       print self._dpi_scale_trans
+    dpi = property(_get_dpi, _set_dpi)
+       
     def autofmt_xdate(self, bottom=0.2, rotation=30, ha='right'):
         """
         A common use case is a number of subplots with shared xaxes
@@ -325,7 +332,7 @@
             w,h = args
 
        dpival = self.dpi
-       self.bbox.max = w * dpival, h * dpival
+       self.bbox_inches.max = w, h
         # self.figwidth.set(w) MGDTODO
         # self.figheight.set(h)
        
@@ -339,7 +346,7 @@
                 manager.resize(int(canvasw), int(canvash))
 
     def get_size_inches(self):
-        return self.bbox.max
+        return self.bbox_inches.max
         # return self.figwidth.get(), self.figheight.get() MGDTODO
 
     def get_edgecolor(self):
@@ -352,12 +359,12 @@
 
     def get_figwidth(self):
         'Return the figwidth as a float'
-       return self.bbox.xmax
+       return self.bbox_inches.xmax
         # return self.figwidth.get() MGDTODO
 
     def get_figheight(self):
         'Return the figheight as a float'
-        return self.bbox.ymax
+        return self.bbox_inches.ymax
 
     def get_dpi(self):
         'Return the dpi as a float'
@@ -400,7 +407,7 @@
         ACCEPTS: float
         """
         # self.figwidth.set(val)  MGDTODO
-       self.bbox.xmax = val
+       self.bbox_inches.xmax = val
        
     def set_figheight(self, val):
         """
@@ -409,7 +416,7 @@
         ACCEPTS: float
         """
        # MGDTODO (set())
-       self.bbox.ymax = val
+       self.bbox_inches.ymax = val
 
     def set_frameon(self, b):
         """

Modified: branches/transforms/lib/matplotlib/pyplot.py
===================================================================
--- branches/transforms/lib/matplotlib/pyplot.py        2007-09-13 12:50:05 UTC 
(rev 3847)
+++ branches/transforms/lib/matplotlib/pyplot.py        2007-09-13 18:00:10 UTC 
(rev 3848)
@@ -481,7 +481,7 @@
     byebye = []
     for other in fig.axes:
         if other==a: continue
-        if bbox.overlaps(other.bbox, ignoreend=True):
+        if bbox.fully_overlaps(other.bbox):
             byebye.append(other)
     for ax in byebye: delaxes(ax)
 

Modified: branches/transforms/lib/matplotlib/text.py
===================================================================
--- branches/transforms/lib/matplotlib/text.py  2007-09-13 12:50:05 UTC (rev 
3847)
+++ branches/transforms/lib/matplotlib/text.py  2007-09-13 18:00:10 UTC (rev 
3848)
@@ -15,7 +15,7 @@
 from cbook import enumerate, is_string_like, maxdict, is_numlike
 from font_manager import FontProperties
 from patches import bbox_artist, YAArrow
-from affine import Bbox
+from affine import Affine2D, Bbox
 from lines import Line2D
 
 import matplotlib.nxutils as nxutils
@@ -213,30 +213,32 @@
         M = self.get_rotation_matrix(xmin, ymin)
 
         # the corners of the unrotated bounding box
-        cornersHoriz = ( (xmin, ymin), (xmin, ymax), (xmax, ymax), (xmax, 
ymin) )
-        offsetLayout = []
+        cornersHoriz = npy.array(
+           [(xmin, ymin), (xmin, ymax), (xmax, ymax), (xmax, ymin)],
+           npy.float_)
+        offsetLayout = npy.zeros((len(lines), 2))
         # now offset the individual text lines within the box
         if len(lines)>1: # do the multiline aligment
             malign = self._get_multialignment()
-            for line, thisx, thisy, w, h in horizLayout:
+            for i, (line, thisx, thisy, w, h) in enumerate(horizLayout):
                 if malign=='center': offsetx = width/2.0-w/2.0
                 elif malign=='right': offsetx = width-w
                 else: offsetx = 0
                 thisx += offsetx
-                offsetLayout.append( (thisx, thisy ))
+               offsetLayout[i] = (thisx, thisy)
         else: # no additional layout needed
-            offsetLayout = [ (thisx, thisy) for line, thisx, thisy, w, h in 
horizLayout]
+            offsetLayout[0] = horizLayout[0][1:3]
 
         # now rotate the bbox
 
-        cornersRotated = [npy.dot(M,npy.array([[thisx],[thisy],[1]])) for 
thisx, thisy in cornersHoriz]
+        cornersRotated = M(cornersHoriz)
 
-        txs = [float(v[0][0]) for v in cornersRotated]
-        tys = [float(v[1][0]) for v in cornersRotated]
+        txs = cornersRotated[:, 0]
+        tys = cornersRotated[:, 1]
 
         # compute the bounds of the rotated box
-        xmin, xmax = min(txs), max(txs)
-        ymin, ymax = min(tys), max(tys)
+        xmin, xmax = txs.min(), txs.max()
+        ymin, ymax = tys.min(), tys.max()
         width  = xmax - xmin
         height = ymax - ymin
 
@@ -264,17 +266,18 @@
 
         bbox = Bbox.from_lbwh(xmin, ymin, width, height)
 
+       
 
         # now rotate the positions around the first x,y position
-        xys = [npy.dot(M,npy.array([[thisx],[thisy],[1]])) for thisx, thisy in 
offsetLayout]
+        xys = M(offsetLayout)
+       tx = xys[:, 0]
+       ty = xys[:, 1]
+       tx += offsetx
+       ty += offsety
 
-
-        tx = [float(v[0][0])+offsetx for v in xys]
-        ty = [float(v[1][0])+offsety for v in xys]
-
         # now inverse transform back to data coords
        inverse_transform = self.get_transform().inverted()
-        xys = inverse_transform(zip(tx, ty))
+        xys = inverse_transform(xys)
 
         xs, ys = zip(*xys)
 
@@ -327,7 +330,7 @@
             return
 
         for line, wh, x, y in info:
-            x, y = trans([[x, y]])[0]
+            x, y = trans.transform_point((x, y))
 
             if renderer.flipy():
                 canvasw, canvash = renderer.get_canvas_width_height()
@@ -435,29 +438,9 @@
         bbox, info = self._get_layout(self._renderer)
         return bbox
 
-
-
     def get_rotation_matrix(self, x0, y0):
+       return Affine2D().rotate_deg_around(x0, y0, self.get_rotation())
 
-        theta = npy.pi/180.0*self.get_rotation()
-        # translate x0,y0 to origin
-        Torigin = npy.array([ [1, 0, -x0],
-                           [0, 1, -y0],
-                           [0, 0, 1  ]])
-
-        # rotate by theta
-        R = npy.array([ [npy.cos(theta),  -npy.sin(theta), 0],
-                     [npy.sin(theta), npy.cos(theta), 0],
-                     [0,           0,          1]])
-
-        # translate origin back to x0,y0
-        Tback = npy.array([ [1, 0, x0],
-                         [0, 1, y0],
-                         [0, 0, 1  ]])
-
-
-        return npy.dot(npy.dot(Tback,R), Torigin)
-
     def set_backgroundcolor(self, color):
         """
         Set the background color of the text by updating the bbox (see 
set_bbox for more info)


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Matplotlib-checkins mailing list
Matplotlib-checkins@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins

Reply via email to