Revision: 3947
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3947&view=rev
Author: mdboom
Date: 2007-10-15 06:49:25 -0700 (Mon, 15 Oct 2007)
Log Message:
-----------
Significant speed improvement in text layout. Reverted to fix bug in
ticklabels. Lots of other minor things.
Modified Paths:
--------------
branches/transforms/lib/matplotlib/axes.py
branches/transforms/lib/matplotlib/axis.py
branches/transforms/lib/matplotlib/collections.py
branches/transforms/lib/matplotlib/lines.py
branches/transforms/lib/matplotlib/path.py
branches/transforms/lib/matplotlib/text.py
branches/transforms/lib/matplotlib/transforms.py
Modified: branches/transforms/lib/matplotlib/axes.py
===================================================================
--- branches/transforms/lib/matplotlib/axes.py 2007-10-14 21:14:18 UTC (rev
3946)
+++ branches/transforms/lib/matplotlib/axes.py 2007-10-15 13:49:25 UTC (rev
3947)
@@ -1037,6 +1037,7 @@
a.set_axes(self)
self.artists.append(a)
self._set_artist_props(a)
+ a.set_clip_path(self.axesPatch)
a._remove_method = lambda h: self.artists.remove(h)
def add_collection(self, collection, autolim=False):
@@ -1091,6 +1092,7 @@
'Add a table instance to the list of axes tables'
self._set_artist_props(tab)
self.tables.append(tab)
+ tab.set_clip_path(self.axesPatch)
tab._remove_method = lambda h: self.tables.remove(h)
def relim(self):
Modified: branches/transforms/lib/matplotlib/axis.py
===================================================================
--- branches/transforms/lib/matplotlib/axis.py 2007-10-14 21:14:18 UTC (rev
3946)
+++ branches/transforms/lib/matplotlib/axis.py 2007-10-15 13:49:25 UTC (rev
3947)
@@ -91,7 +91,6 @@
self._size = size
self._padPixels = self.figure.dpi * self._pad * (1/72.0)
- self._locTransform = Affine2D()
self.tick1line = self._get_tick1line()
self.tick2line = self._get_tick2line()
@@ -286,7 +285,7 @@
markersize=self._size,
)
- l.set_transform(self._locTransform + self.axes.get_xaxis_transform())
+ l.set_transform(self.axes.get_xaxis_transform())
self._set_artist_props(l)
return l
@@ -298,16 +297,20 @@
linestyle=rcParams['grid.linestyle'],
linewidth=rcParams['grid.linewidth'],
)
- l.set_transform(self._locTransform + self.axes.get_xaxis_transform())
+ l.set_transform(self.axes.get_xaxis_transform())
self._set_artist_props(l)
return l
def update_position(self, loc):
'Set the location of tick in data coords with scalar loc'
- self._locTransform.clear().translate(loc, 0.0)
- self.label1.set_x(loc)
- self.label2.set_x(loc)
+ x = loc
+
+ self.tick1line.set_xdata((x,))
+ self.tick2line.set_xdata((x,))
+ self.gridline.set_xdata((x, ))
+ self.label1.set_x(x)
+ self.label2.set_x(x)
self._loc = loc
def get_view_interval(self):
@@ -385,7 +388,7 @@
linestyle = 'None',
markersize=self._size,
)
- l.set_transform(self._locTransform + self.axes.get_yaxis_transform())
+ l.set_transform(self.axes.get_yaxis_transform())
self._set_artist_props(l)
return l
@@ -398,7 +401,7 @@
markersize=self._size,
)
- l.set_transform(self._locTransform + self.axes.get_yaxis_transform())
+ l.set_transform(self.axes.get_yaxis_transform())
self._set_artist_props(l)
return l
@@ -411,19 +414,24 @@
linewidth=rcParams['grid.linewidth'],
)
- l.set_transform(self._locTransform + self.axes.get_yaxis_transform())
+ l.set_transform(self.axes.get_yaxis_transform())
self._set_artist_props(l)
return l
def update_position(self, loc):
'Set the location of tick in data coords with scalar loc'
- self._locTransform.clear().translate(0.0, loc)
- self.label1.set_y(loc)
- self.label2.set_y(loc)
+ y = loc
+ self.tick1line.set_ydata((y,))
+ self.tick2line.set_ydata((y,))
+ self.gridline.set_ydata((y, ))
+
+ self.label1.set_y( y )
+ self.label2.set_y( y )
+
self._loc = loc
-
+
def get_view_interval(self):
'return the Interval instance for this axis view limits'
return self.axes.viewLim.intervaly
@@ -751,7 +759,7 @@
if len(self.minorTicks) < numticks:
# update the new tick label properties from the old
for i in range(numticks - len(self.minorTicks)):
- tick = self._get_tick(minor=True)
+ tick = self._get_tick(major=False)
self.minorTicks.append(tick)
if self._lastNumMinorTicks < numticks:
Modified: branches/transforms/lib/matplotlib/collections.py
===================================================================
--- branches/transforms/lib/matplotlib/collections.py 2007-10-14 21:14:18 UTC
(rev 3946)
+++ branches/transforms/lib/matplotlib/collections.py 2007-10-15 13:49:25 UTC
(rev 3947)
@@ -43,7 +43,7 @@
linewidths=None,
antialiaseds = None,
offsets = None,
- transOffset = transforms.identity_transform(),
+ transOffset = transforms.IdentityTransform(),
norm = None, # optional for cm.ScalarMappable
cmap = None, # ditto
@@ -376,7 +376,7 @@
linewidths=None,
antialiaseds = None,
offsets = None,
- transOffset = transforms.identity_transform(),
+ transOffset = transforms.IdentityTransform(),
norm = None, # optional for cm.ScalarMappable
cmap = None, # ditto
Modified: branches/transforms/lib/matplotlib/lines.py
===================================================================
--- branches/transforms/lib/matplotlib/lines.py 2007-10-14 21:14:18 UTC (rev
3946)
+++ branches/transforms/lib/matplotlib/lines.py 2007-10-15 13:49:25 UTC (rev
3947)
@@ -455,8 +455,10 @@
gc.set_capstyle(cap)
funcname = self._lineStyles.get(self._linestyle, '_draw_nothing')
- lineFunc = getattr(self, funcname)
- lineFunc(renderer, gc,
*self._transformed_path.get_transformed_path_and_affine())
+ if funcname != '_draw_nothing':
+ tpath, affine =
self._transformed_path.get_transformed_path_and_affine()
+ lineFunc = getattr(self, funcname)
+ lineFunc(renderer, gc, tpath, affine)
if self._marker is not None:
gc = renderer.new_gc()
@@ -465,8 +467,10 @@
gc.set_linewidth(self._markeredgewidth)
gc.set_alpha(self._alpha)
funcname = self._markers.get(self._marker, '_draw_nothing')
- markerFunc = getattr(self, funcname)
- markerFunc(renderer, gc,
*self._transformed_path.get_transformed_path_and_affine())
+ if funcname != '_draw_nothing':
+ tpath, affine =
self._transformed_path.get_transformed_path_and_affine()
+ markerFunc = getattr(self, funcname)
+ markerFunc(renderer, gc, tpath, affine)
renderer.close_group('line2d')
@@ -621,11 +625,9 @@
ACCEPTS: npy.array
"""
- try: del self._xsorted
- except AttributeError: pass
+ self._xorig = x
+ self.recache()
- self.set_data(x, self.get_ydata())
-
def set_ydata(self, y):
"""
Set the data npy.array for y
@@ -633,9 +635,9 @@
ACCEPTS: npy.array
"""
- self.set_data(self.get_xdata(), y)
+ self._yorig = y
+ self.recache()
-
def set_dashes(self, seq):
"""
Set the dash sequence, sequence of dashes with on off ink in
Modified: branches/transforms/lib/matplotlib/path.py
===================================================================
--- branches/transforms/lib/matplotlib/path.py 2007-10-14 21:14:18 UTC (rev
3946)
+++ branches/transforms/lib/matplotlib/path.py 2007-10-15 13:49:25 UTC (rev
3947)
@@ -84,7 +84,8 @@
resulting path will be compressed, with MOVETO codes inserted
in the correct places to jump over the masked regions.
"""
- vertices = ma.asarray(vertices, npy.float_)
+ if not ma.isMaskedArray(vertices):
+ vertices = ma.asarray(vertices, npy.float_)
if codes is None:
if len(vertices) == 0:
Modified: branches/transforms/lib/matplotlib/text.py
===================================================================
--- branches/transforms/lib/matplotlib/text.py 2007-10-14 21:14:18 UTC (rev
3946)
+++ branches/transforms/lib/matplotlib/text.py 2007-10-15 13:49:25 UTC (rev
3947)
@@ -172,24 +172,18 @@
self._linespacing = other._linespacing
def _get_layout(self, renderer):
- # layout the xylocs in display coords as if angle = zero and
- # then rotate them around self._x, self._y
- #return _unit_box
key = self.get_prop_tup()
if self.cached.has_key(key): return self.cached[key]
+
horizLayout = []
- transform = self.get_transform()
- x, y = self.get_position()
- thisx, thisy = transform.transform_point((x, y))
- tx, ty = thisx, thisy
- width = 0
- height = 0
-
- xmin, ymin = thisx, thisy
+ thisx, thisy = 0.0, 0.0
+ xmin, ymin = 0.0, 0.0
+ width, height = 0.0, 0.0
lines = self._text.split('\n')
- whs = []
+ whs = npy.zeros((len(lines), 2))
+ horizLayout = npy.zeros((len(lines), 4))
# Find full vertical extent of font,
# including ascenders and descenders:
tmp, heightt, bl = renderer.get_text_width_height_descent(
@@ -197,43 +191,39 @@
offsety = heightt * self._linespacing
baseline = None
- for line in lines:
+ for i, line in enumerate(lines):
w, h, d = renderer.get_text_width_height_descent(
line, self._fontproperties, ismath=self.is_math_text(line))
if baseline is None:
baseline = h - d
- whs.append( (w,h) )
- horizLayout.append((line, thisx, thisy, w, h))
+ whs[i] = w, h
+ horizLayout[i] = thisx, thisy, w, h
thisy -= offsety
width = max(width, w)
- ymin = horizLayout[-1][2]
- ymax = horizLayout[0][2] + horizLayout[0][-1]
+ ymin = horizLayout[-1][1]
+ ymax = horizLayout[0][1] + horizLayout[0][3]
height = ymax-ymin
-
xmax = xmin + width
+
# get the rotation matrix
- M = self.get_rotation_matrix(xmin, ymin)
+ M = Affine2D().rotate_deg(self.get_rotation())
- # the corners of the unrotated bounding box
- cornersHoriz = npy.array(
- [(xmin, ymin), (xmin, ymax), (xmax, ymax), (xmax, ymin)],
- npy.float_)
offsetLayout = npy.zeros((len(lines), 2))
+ offsetLayout[:] = horizLayout[:, 0:2]
# now offset the individual text lines within the box
if len(lines)>1: # do the multiline aligment
malign = self._get_multialignment()
- 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[i] = (thisx, thisy)
- else: # no additional layout needed
- offsetLayout[0] = horizLayout[0][1:3]
+ if malign == 'center':
+ offsetLayout[:, 0] += width/2.0 - horizLayout[:, 2] / 2.0
+ elif malign == 'right':
+ offsetLayout[:, 0] += width - horizLayout[:, 2]
+ # the corners of the unrotated bounding box
+ cornersHoriz = npy.array(
+ [(xmin, ymin), (xmin, ymax), (xmax, ymax), (xmax, ymin)],
+ npy.float_)
# now rotate the bbox
-
cornersRotated = M.transform(cornersHoriz)
txs = cornersRotated[:, 0]
@@ -251,37 +241,30 @@
# compute the text location in display coords and the offsets
# necessary to align the bbox with that location
- tx, ty = self._get_xy_display()
+ if halign=='center': offsetx = (xmin + width/2.0)
+ elif halign=='right': offsetx = (xmin + width)
+ else: offsetx = xmin
- if halign=='center': offsetx = tx - (xmin + width/2.0)
- elif halign=='right': offsetx = tx - (xmin + width)
- else: offsetx = tx - xmin
+ if valign=='center': offsety = (ymin + height/2.0)
+ elif valign=='top': offsety = (ymin + height)
+ elif valign=='baseline': offsety = (ymin + height) + baseline
+ else: offsety = ymin
- if valign=='center': offsety = ty - (ymin + height/2.0)
- elif valign=='top': offsety = ty - (ymin + height)
- elif valign=='baseline': offsety = ty - (ymin + height) + baseline
- else: offsety = ty - ymin
+ xmin -= offsetx
+ ymin -= offsety
- xmin += offsetx
- ymin += offsety
-
bbox = Bbox.from_lbwh(xmin, ymin, width, height)
# now rotate the positions around the first x,y position
xys = M.transform(offsetLayout)
- xys += (offsetx, offsety)
+ xys -= (offsetx, offsety)
- # now inverse transform back to data coords
- inverse_transform = transform.inverted()
- xys = inverse_transform.transform(xys)
-
xs, ys = xys[:, 0], xys[:, 1]
ret = bbox, zip(lines, whs, xs, ys)
self.cached[key] = ret
return ret
-
def set_bbox(self, rectprops):
"""
Draw a bounding box around self. rect props are any settable
@@ -307,18 +290,20 @@
if self.get_clip_on():
gc.set_clip_rectangle(self.clipbox)
-
-
if self._bbox:
bbox_artist(self, renderer, self._bbox)
angle = self.get_rotation()
bbox, info = self._get_layout(renderer)
trans = self.get_transform()
+ posx, posy = self.get_position()
+ posx, posy = trans.transform_point((posx, posy))
+ canvasw, canvash = renderer.get_canvas_width_height()
+
if rcParams['text.usetex']:
- canvasw, canvash = renderer.get_canvas_width_height()
for line, wh, x, y in info:
- x, y = trans.transform_point((x, y))
+ x = x + posx
+ y = y + posy
if renderer.flipy():
y = canvash-y
@@ -326,9 +311,9 @@
self._fontproperties, angle)
return
- canvasw, canvash = renderer.get_canvas_width_height()
for line, wh, x, y in info:
- x, y = trans.transform_point((x, y))
+ x = x + posx
+ y = y + posy
if renderer.flipy():
y = canvash-y
@@ -402,8 +387,7 @@
x, y = self.get_position()
return (x, y, self._text, self._color,
self._verticalalignment, self._horizontalalignment,
- hash(self._fontproperties), self._rotation,
- self.get_transform().id
+ hash(self._fontproperties), self._rotation
)
def get_text(self):
@@ -432,11 +416,11 @@
angle = self.get_rotation()
bbox, info = self._get_layout(self._renderer)
+ x, y = self.get_position()
+ x, y = self.get_transform().transform_point((x, y))
+ bbox = bbox.translated(x, y)
return bbox
- def get_rotation_matrix(self, x0, y0):
- return Affine2D().rotate_deg_around(x0, y0, self.get_rotation())
-
def set_backgroundcolor(self, color):
"""
Set the background color of the text by updating the bbox (see
set_bbox for more info)
Modified: branches/transforms/lib/matplotlib/transforms.py
===================================================================
--- branches/transforms/lib/matplotlib/transforms.py 2007-10-14 21:14:18 UTC
(rev 3946)
+++ branches/transforms/lib/matplotlib/transforms.py 2007-10-15 13:49:25 UTC
(rev 3947)
@@ -34,8 +34,6 @@
DEBUG = False
-# MGDTODO: Cache get_affine???
-
class TransformNode(object):
"""
TransformNode is the base class for anything that participates in
@@ -51,7 +49,7 @@
# INVALID_AFFINE_ONLY
INVALID_NON_AFFINE = 1
INVALID_AFFINE = 2
- INVALID = INVALID_NON_AFFINE & INVALID_AFFINE
+ INVALID = INVALID_NON_AFFINE | INVALID_AFFINE
# Some metadata about the transform, used to determine whether an
# invalidation is affine-only
@@ -71,11 +69,6 @@
# them alive.
self._parents = WeakKeyDictionary()
- # id is an arbitrary integer that is updated every time the node
- # is invalidated.
- self.id = TransformNode._gid
- TransformNode._gid += 1
-
# TransformNodes start out as invalid until their values are
# computed for the first time.
self._invalid = 1
@@ -105,15 +98,14 @@
value = ((self.is_affine or self.is_bbox)
and self.INVALID_AFFINE
or self.INVALID)
-
+
# Invalidate all ancestors of self using pseudo-recursion.
+ parent = None
stack = [self]
while len(stack):
root = stack.pop()
# Stop at subtrees that have already been invalidated
if root._invalid == 0 or root.pass_through:
- root.id = TransformNode._gid
- TransformNode._gid += 1
root._invalid = value
stack.extend(root._parents.keys())
@@ -466,8 +458,7 @@
count = 0
for bbox in bboxes:
- # bx1, by1, bx2, by2 = bbox._get_lbrt()
- # The above, inlined...
+ # bx1, by1, bx2, by2 = bbox._get_lbrt() ... inlined...
bx1, by1, bx2, by2 = bbox.get_points().flatten()
if bx2 < bx1:
bx2, bx1 = bx1, bx2
@@ -497,6 +488,26 @@
"""
return Bbox(self._points + (tx, ty))
+ def corners(self):
+ """
+ Return an array of points which are the four corners of this
+ rectangle.
+ """
+ l, b, r, t = self.get_points().flatten()
+ return npy.array([[l, b], [l, t], [r, b], [r, t]])
+
+ def rotated(self, radians):
+ """
+ Return a new bounding box that bounds a rotated version of this
+ bounding box. The new bounding box is still aligned with the
+ axes, of course.
+ """
+ corners = self.corners()
+ corners_rotated = Affine2D().rotate(radians).transform(corners)
+ bbox = Bbox.unit()
+ bbox.update_from_data(corners_rotated, ignore=True)
+ return bbox
+
[EMAIL PROTECTED]
def union(bboxes):
"""
@@ -965,7 +976,6 @@
self.transform_path_non_affine = child.transform_path_non_affine
self.get_affine = child.get_affine
self.inverted = child.inverted
- # self.get_matrix = child.get_matrix
def set(self, child):
"""
@@ -1609,7 +1619,8 @@
self._x = x_transform
self._y = y_transform
self.set_children(x_transform, y_transform)
-
+ self._affine = None
+
def _get_is_affine(self):
return self._x.is_affine and self._y.is_affine
is_affine = property(_get_is_affine)
@@ -1648,9 +1659,7 @@
transform.__doc__ = Transform.transform.__doc__
def transform_affine(self, points):
- if self._x.is_affine and self._y.is_affine:
- return self.transform(points)
- return points
+ return self.get_affine().transform(points)
transform_affine.__doc__ = Transform.transform_affine.__doc__
def transform_non_affine(self, points):
@@ -1664,18 +1673,22 @@
inverted.__doc__ = Transform.inverted.__doc__
def get_affine(self):
- if self._x.is_affine and self._y.is_affine:
- if self._x == self._y:
- return self._x.get_affine()
+ if self._invalid or self._affine is None:
+ if self._x.is_affine and self._y.is_affine:
+ if self._x == self._y:
+ self._affine = self._x.get_affine()
+ else:
+ x_mtx = self._x.get_affine().get_matrix()
+ y_mtx = self._y.get_affine().get_matrix()
+ # This works because we already know the transforms are
+ # separable, though normally one would want to set b and
+ # c to zero.
+ mtx = npy.vstack((x_mtx[0], y_mtx[1], [0.0, 0.0, 1.0]))
+ self._affine = Affine2D(mtx)
else:
- x_mtx = self._x.get_affine().get_matrix()
- y_mtx = self._y.get_affine().get_matrix()
- # This works because we already know the transforms are
- # separable, though normally one would want to set b and
- # c to zero.
- mtx = npy.vstack((x_mtx[0], y_mtx[1], [0.0, 0.0, 1.0]))
- return Affine2D(mtx)
- return IdentityTransform()
+ self._affine = IdentityTransform()
+ self._invalid = 0
+ return self._affine
get_affine.__doc__ = Transform.get_affine.__doc__
@@ -1830,6 +1843,7 @@
self._b = b
self.set_children(a, b)
self._mtx = None
+ self._affine = None
def frozen(self):
self._invalid = 0
@@ -1857,8 +1871,7 @@
transform.__doc__ = Transform.transform.__doc__
def transform_affine(self, points):
- return self._b.transform_affine(
- self._a.transform(points))
+ return self.get_affine().transform(points)
transform_affine.__doc__ = Transform.transform_affine.__doc__
def transform_non_affine(self, points):
@@ -1886,10 +1899,14 @@
transform_path_non_affine.__doc__ =
Transform.transform_path_non_affine.__doc__
def get_affine(self):
- if self._a.is_affine and self._b.is_affine:
- return Affine2D(npy.dot(self._b.get_affine().get_matrix(),
- self._a.get_affine().get_matrix()))
- return self._b.get_affine()
+ if self._invalid or self._affine is None:
+ if self._a.is_affine and self._b.is_affine:
+ self._affine =
Affine2D(npy.dot(self._b.get_affine().get_matrix(),
+
self._a.get_affine().get_matrix()))
+ else:
+ self._affine = self._b.get_affine()
+ self._invalid = 0
+ return self._affine
get_affine.__doc__ = Transform.get_affine.__doc__
def inverted(self):
@@ -2023,6 +2040,7 @@
self._transform = transform
self.set_children(transform)
self._transformed_path = None
+ self.get_affine = self._transform.get_affine
def get_transformed_path_and_affine(self):
"""
@@ -2035,7 +2053,7 @@
self._transformed_path = \
self._transform.transform_path_non_affine(self._path)
self._invalid = 0
- return self._transformed_path, self._transform.get_affine()
+ return self._transformed_path, self.get_affine()
def get_fully_transformed_path(self):
"""
@@ -2047,12 +2065,6 @@
self._transform.transform_path_non_affine(self._path)
self._invalid = 0
return self._transform.transform_path_affine(self._transformed_path)
-
- def get_affine(self):
- """
- Get the affine part of the child transform.
- """
- return self._transform.get_affine()
def nonsingular(vmin, vmax, expander=0.001, tiny=1e-15, increasing=True):
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: Splunk Inc.
Still grepping through log files to find problems? Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/
_______________________________________________
Matplotlib-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins