SourceForge logo
SourceForge logo
Menu

matplotlib-checkins

From: <md...@us...> - 2007年09月10日 17:39:47
Revision: 3822
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3822&view=rev
Author: mdboom
Date: 2007年09月10日 10:39:37 -0700 (2007年9月10日)
Log Message:
-----------
Baby steps and horrible breakage on transforms branch.
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/artist.py
 branches/transforms/lib/matplotlib/axes.py
 branches/transforms/lib/matplotlib/axis.py
 branches/transforms/lib/matplotlib/backends/backend_agg.py
 branches/transforms/lib/matplotlib/figure.py
 branches/transforms/lib/matplotlib/legend.py
 branches/transforms/lib/matplotlib/lines.py
 branches/transforms/lib/matplotlib/pylab.py
 branches/transforms/lib/matplotlib/table.py
 branches/transforms/lib/matplotlib/text.py
 branches/transforms/lib/matplotlib/transforms.py
 branches/transforms/lib/matplotlib/widgets.py
Modified: branches/transforms/lib/matplotlib/artist.py
===================================================================
--- branches/transforms/lib/matplotlib/artist.py	2007年09月10日 06:55:10 UTC (rev 3821)
+++ branches/transforms/lib/matplotlib/artist.py	2007年09月10日 17:39:37 UTC (rev 3822)
@@ -1,7 +1,7 @@
 from __future__ import division
 import sys, re
 from cbook import iterable, flatten
-from transforms import identity_transform
+from affine import Affine2D
 import matplotlib.units as units
 
 ## Note, matplotlib artists use the doc strings for set and get
@@ -145,7 +145,7 @@
 def get_transform(self):
 'return the Transformation instance used by this artist'
 if self._transform is None:
- self._transform = identity_transform()
+ self._transform = Affine2D()
 return self._transform
 
 def hitlist(self,event):
Modified: branches/transforms/lib/matplotlib/axes.py
===================================================================
--- branches/transforms/lib/matplotlib/axes.py	2007年09月10日 06:55:10 UTC (rev 3821)
+++ branches/transforms/lib/matplotlib/axes.py	2007年09月10日 17:39:37 UTC (rev 3822)
@@ -9,6 +9,8 @@
 rcParams = matplotlib.rcParams
 
 from matplotlib import artist as martist
+from matplotlib import affine as maffine
+from matplotlib import bbox as mbbox
 from matplotlib import agg
 from matplotlib import axis as maxis
 from matplotlib import cbook
@@ -23,11 +25,11 @@
 from matplotlib import mlab
 from matplotlib import cm
 from matplotlib import patches as mpatches
+from matplotlib import pbox as mpbox
 from matplotlib import quiver as mquiver
 from matplotlib import table as mtable
 from matplotlib import text as mtext
 from matplotlib import ticker as mticker
-from matplotlib import transforms as mtrans
 
 iterable = cbook.iterable
 is_string_like = cbook.is_string_like
@@ -413,14 +415,7 @@
 yield seg
 remaining=remaining[2:]
 
-ValueType=type(mtrans.zero())
-def makeValue(v):
- if type(v) == ValueType:
- return v
- else:
- return mtrans.Value(v)
 
-
 class Axes(martist.Artist):
 """
 The Axes contains most of the figure elements: Axis, Tick, Line2D,
@@ -434,10 +429,15 @@
 
 """
 
- scaled = {mtrans.IDENTITY : 'linear',
- mtrans.LOG10 : 'log',
+ # MGDTODO
+# scaled = {mtrans.IDENTITY : 'linear',
+# mtrans.LOG10 : 'log',
+# }
+ scaled = {0 : 'linear',
+ 1 : 'log',
 }
 
+ 
 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())
@@ -485,7 +485,7 @@
 
 """
 martist.Artist.__init__(self)
- self._position = map(makeValue, rect)
+ self._position = rect
 self._originalPosition = rect
 self.set_axes(self)
 self.set_aspect('auto')
@@ -629,12 +629,9 @@
 self.right = (l+w)*figw
 self.top = (b+h)*figh
 
-
- Bbox = mtrans.Bbox
- Point = mtrans.Point
- self.bbox = Bbox(
- Point(self.left, self.bottom),
- Point(self.right, self.top ),
+ self.bbox = mbbox.Bbox.from_lbrt(
+ self.left, self.bottom,
+ self.right, self.top,
 )
 #these will be updated later as data is added
 self._set_lim_and_transforms()
@@ -644,40 +641,36 @@
 set the dataLim and viewLim BBox attributes and the
 transData and transAxes Transformation attributes
 """
-
-
- one = mtrans.one
- zero = mtrans.zero
- Point = mtrans.Point
- Bbox = mtrans.Bbox
+ Bbox = mbbox.Bbox
 if self._sharex is not None:
- left=self._sharex.viewLim.ll().x()
- right=self._sharex.viewLim.ur().x()
+ left = self._sharex.viewLim.xmin()
+ right = self._sharex.viewLim.xmax()
 else:
- left=zero()
- right=one()
+ left = 0.0
+ right = 1.0
 if self._sharey is not None:
- bottom=self._sharey.viewLim.ll().y()
- top=self._sharey.viewLim.ur().y()
+ bottom = self._sharey.viewLim.ymin()
+ top = self._sharey.viewLim.ymax()
 else:
- bottom=zero()
- top=one()
+ bottom = 0.0
+ top = 1.0
 
 
 
- self.viewLim = Bbox(Point(left, bottom), Point(right, top))
- self.dataLim = mtrans.unit_bbox()
+ self.viewLim = Bbox.from_lbrt(left, bottom, right, top)
+ self.dataLim = Bbox.unit()
 
- self.transData = mtrans.get_bbox_transform(
+ self.transData = maffine.get_bbox_transform(
 self.viewLim, self.bbox)
- self.transAxes = mtrans.get_bbox_transform(
- mtrans.unit_bbox(), self.bbox)
+ self.transAxes = maffine.get_bbox_transform(
+ Bbox.unit(), self.bbox)
 
- if self._sharex:
- self.transData.set_funcx(self._sharex.transData.get_funcx())
+	# 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())
+# if self._sharey:
+# self.transData.set_funcy(self._sharey.transData.get_funcy())
 
 def get_position(self, original=False):
 'Return the axes rectangle left, bottom, width, height'
@@ -861,7 +854,7 @@
 """
 ACCEPTS: ['C', 'SW', 'S', 'SE', 'E', 'NE', 'N', 'NW', 'W']
 """
- if anchor in mtrans.PBox.coefs.keys() or len(anchor) == 2:
+ if anchor in mpbox.PBox.coefs.keys() or len(anchor) == 2:
 self._anchor = anchor
 else:
 raise ValueError('argument must be among %s' %
@@ -901,7 +894,7 @@
 if data_ratio is None:
 data_ratio = ysize/xsize
 box_aspect = A * data_ratio
- pb = mtrans.PBox(self._originalPosition)
+ pb = mpbox.PBox(self._originalPosition)
 pb1 = pb.shrink_to_aspect(box_aspect, fig_aspect)
 self.set_position(pb1.anchor(self._anchor), 'active')
 return
@@ -1538,11 +1531,12 @@
 if xmin is None: xmin = old_xmin
 if xmax is None: xmax = old_xmax
 
- if (self.transData.get_funcx().get_type()==mtrans.LOG10
- and min(xmin, xmax)<=0):
- raise ValueError('Cannot set nonpositive limits with log transform')
+	# MGDTODO
+# if (self.transData.get_funcx().get_type()==mtrans.LOG10
+# and min(xmin, xmax)<=0):
+# raise ValueError('Cannot set nonpositive limits with log transform')
 
- xmin, xmax = mtrans.nonsingular(xmin, xmax, increasing=False)
+ xmin, xmax = mbbox.nonsingular(xmin, xmax, increasing=False)
 self.viewLim.intervalx().set_bounds(xmin, xmax)
 if emit: self.callbacks.process('xlim_changed', self)
 
@@ -1574,19 +1568,22 @@
 #if subsx is None: subsx = range(2, basex)
 assert(value.lower() in ('log', 'linear', ))
 if value == 'log':
- self.xaxis.set_major_locator(mticker.LogLocator(basex))
- self.xaxis.set_major_formatter(mticker.LogFormatterMathtext(basex))
- self.xaxis.set_minor_locator(mticker.LogLocator(basex,subsx))
- self.transData.get_funcx().set_type(mtrans.LOG10)
- minx, maxx = self.get_xlim()
- if min(minx, maxx)<=0:
- self.autoscale_view()
+	 # MGDTODO
+# self.xaxis.set_major_locator(mticker.LogLocator(basex))
+# self.xaxis.set_major_formatter(mticker.LogFormatterMathtext(basex))
+# self.xaxis.set_minor_locator(mticker.LogLocator(basex,subsx))
+# self.transData.get_funcx().set_type(mtrans.LOG10)
+# minx, maxx = self.get_xlim()
+# if min(minx, maxx)<=0:
+# self.autoscale_view()
+	 pass
 elif value == 'linear':
 self.xaxis.set_major_locator(mticker.AutoLocator())
 self.xaxis.set_major_formatter(mticker.ScalarFormatter())
 self.xaxis.set_minor_locator(mticker.NullLocator())
 self.xaxis.set_minor_formatter(mticker.NullFormatter())
- self.transData.get_funcx().set_type( mtrans.IDENTITY )
+ # self.transData.get_funcx().set_type( mtrans.IDENTITY )
+	 self.transData.get_funcx().set_type( 0 ) # MGDTODO
 
 def get_xticks(self):
 'Return the x ticks as a list of locations'
@@ -1659,11 +1656,12 @@
 if ymin is None: ymin = old_ymin
 if ymax is None: ymax = old_ymax
 
- if (self.transData.get_funcy().get_type()==mtrans.LOG10
- and min(ymin, ymax)<=0):
- raise ValueError('Cannot set nonpositive limits with log transform')
+	# MGDTODO
+# if (self.transData.get_funcy().get_type()==mtrans.LOG10
+# and min(ymin, ymax)<=0):
+# raise ValueError('Cannot set nonpositive limits with log transform')
 
- ymin, ymax = mtrans.nonsingular(ymin, ymax, increasing=False)
+ ymin, ymax = mbbox.nonsingular(ymin, ymax, increasing=False)
 self.viewLim.intervaly().set_bounds(ymin, ymax)
 if emit: self.callbacks.process('ylim_changed', self)
 
@@ -1696,21 +1694,24 @@
 assert(value.lower() in ('log', 'linear', ))
 
 if value == 'log':
- self.yaxis.set_major_locator(mticker.LogLocator(basey))
- self.yaxis.set_major_formatter(mticker.LogFormatterMathtext(basey))
- self.yaxis.set_minor_locator(mticker.LogLocator(basey,subsy))
- self.transData.get_funcy().set_type(mtrans.LOG10)
- miny, maxy = self.get_ylim()
- if min(miny, maxy)<=0:
- self.autoscale_view()
-
+	 # MGDTODO
+# self.yaxis.set_major_locator(mticker.LogLocator(basey))
+# self.yaxis.set_major_formatter(mticker.LogFormatterMathtext(basey))
+# self.yaxis.set_minor_locator(mticker.LogLocator(basey,subsy))
+# self.transData.get_funcy().set_type(mtrans.LOG10)
+# miny, maxy = self.get_ylim()
+# if min(miny, maxy)<=0:
+# self.autoscale_view()
+	 pass
+	 
 elif value == 'linear':
 self.yaxis.set_major_locator(mticker.AutoLocator())
 self.yaxis.set_major_formatter(mticker.ScalarFormatter())
 self.yaxis.set_minor_locator(mticker.NullLocator())
 self.yaxis.set_minor_formatter(mticker.NullFormatter())
- self.transData.get_funcy().set_type( mtrans.IDENTITY )
-
+ # self.transData.get_funcy().set_type( mtrans.IDENTITY ) MGDTODO
+ self.transData.get_funcy().set_type( 0 )
+	 
 def get_yticks(self):
 'Return the y ticks as a list of locations'
 return self.yaxis.get_ticklocs()
@@ -1744,9 +1745,11 @@
 
 def toggle_log_lineary(self):
 'toggle between log and linear on the y axis'
- funcy = self.transData.get_funcy().get_type()
- if funcy==mtrans.LOG10: self.set_yscale('linear')
- elif funcy==mtrans.IDENTITY: self.set_yscale('log')
+	# MGDTODO
+# funcy = self.transData.get_funcy().get_type()
+# if funcy==mtrans.LOG10: self.set_yscale('linear')
+# elif funcy==mtrans.IDENTITY: self.set_yscale('log')
+	pass
 
 def xaxis_date(self, tz=None):
 """Sets up x-axis ticks and labels that treat the x data as dates.
@@ -2172,7 +2175,7 @@
 %(Annotation)s
 """
 a = mtext.Annotation(*args, **kwargs)
- a.set_transform(mtrans.identity_transform())
+ a.set_transform(maffine.Affine2D.identity())
 self._set_artist_props(a)
 if kwargs.has_key('clip_on'): a.set_clip_box(self.bbox)
 self.texts.append(a)
@@ -2211,7 +2214,7 @@
 %(Line2D)s
 """
 
- trans = mtrans.blend_xy_sep_transform( self.transAxes, self.transData)
+ trans = maffine.blend_xy_sep_transform( self.transAxes, self.transData)
 l, = self.plot([xmin,xmax], [y,y], transform=trans, scalex=False, **kwargs)
 return l
 
@@ -2247,7 +2250,7 @@
 %(Line2D)s
 """
 
- trans = mtrans.blend_xy_sep_transform( self.transData, self.transAxes )
+ trans = maffine.blend_xy_sep_transform( self.transData, self.transAxes )
 l, = self.plot([x,x], [ymin,ymax] , transform=trans, scaley=False, **kwargs)
 return l
 
@@ -2286,7 +2289,7 @@
 %(Polygon)s
 """
 # convert y axis units
- trans = mtrans.blend_xy_sep_transform( self.transAxes, self.transData)
+ trans = maffine.blend_xy_sep_transform( self.transAxes, self.transData)
 verts = (xmin, ymin), (xmin, ymax), (xmax, ymax), (xmax, ymin)
 p = mpatches.Polygon(verts, **kwargs)
 p.set_transform(trans)
@@ -2326,7 +2329,7 @@
 %(Polygon)s
 """
 # convert x axis units
- trans = mtrans.blend_xy_sep_transform(self.transData, self.transAxes)
+ trans = maffine.blend_xy_sep_transform(self.transData, self.transAxes)
 verts = [(xmin, ymin), (xmin, ymax), (xmax, ymax), (xmax, ymin)]
 p = mpatches.Polygon(verts, **kwargs)
 p.set_transform(trans)
@@ -4105,7 +4108,7 @@
 offsets = zip(x,y),
 transOffset = self.transData,
 )
- collection.set_transform(mtrans.identity_transform())
+ collection.set_transform(maffine.Affine2D())
 collection.set_alpha(alpha)
 collection.update(kwargs)
 
@@ -5299,21 +5302,22 @@
 
 # the lim are theta, r
 
- Bbox = mtrans.Bbox
- Value = mtrans.Value
- Point = mtrans.Point
- self.dataLim = Bbox( Point( Value(5/4.*math.pi), Value(math.sqrt(2))),
- Point( Value(1/4.*math.pi), Value(math.sqrt(2))))
- self.viewLim = Bbox( Point( Value(5/4.*math.pi), Value(math.sqrt(2))),
- Point( Value(1/4.*math.pi), Value(math.sqrt(2))))
+	# MGDTODO
+# Bbox = mtrans.Bbox
+# Value = mtrans.Value
+# Point = mtrans.Point
+# self.dataLim = Bbox( Point( Value(5/4.*math.pi), Value(math.sqrt(2))),
+# Point( Value(1/4.*math.pi), Value(math.sqrt(2))))
+# self.viewLim = Bbox( Point( Value(5/4.*math.pi), Value(math.sqrt(2))),
+# Point( Value(1/4.*math.pi), Value(math.sqrt(2))))
 
- self.transData = mtrans.NonseparableTransformation(
- self.viewLim, self.bbox,
- mtrans.FuncXY(mtrans.POLAR))
- self.transAxes = mtrans.get_bbox_transform(
- mtrans.unit_bbox(), self.bbox)
+# self.transData = mtrans.NonseparableTransformation(
+# self.viewLim, self.bbox,
+# mtrans.FuncXY(mtrans.POLAR))
+# self.transAxes = mtrans.get_bbox_transform(
+# mtrans.unit_bbox(), self.bbox)
+	pass
 
-
 def contains(self,mouseevent):
 """Test whether the mouse event occured in the axes.
 
@@ -5380,6 +5384,7 @@
 
 # we need to set a view and data interval from 0->rmax to make
 # the formatter and locator work correctly
+	# MGDTODO
 Value = mtrans.Value
 Interval = mtrans.Interval
 self.rintv = Interval(Value(0), Value(1))
Modified: branches/transforms/lib/matplotlib/axis.py
===================================================================
--- branches/transforms/lib/matplotlib/axis.py	2007年09月10日 06:55:10 UTC (rev 3821)
+++ branches/transforms/lib/matplotlib/axis.py	2007年09月10日 17:39:37 UTC (rev 3822)
@@ -15,8 +15,8 @@
 from ticker import NullFormatter, FixedFormatter, ScalarFormatter, LogFormatter
 from ticker import NullLocator, FixedLocator, LinearLocator, LogLocator, AutoLocator
 
-from transforms import Value, blend_xy_sep_transform,\
- translation_transform, bbox_all, identity_transform
+from affine import Affine2D, blend_xy_sep_transform
+from bbox import bbox_union
 from font_manager import FontProperties
 from text import Text, TextWithDash, _process_text_args
 from patches import bbox_artist
@@ -81,16 +81,16 @@
 if self._tickdir == 'in':
 self._xtickmarkers = (TICKUP, TICKDOWN)
 self._ytickmarkers = (TICKRIGHT, TICKLEFT)
- self._pad = Value(pad)
+ self._pad = pad
 else:
 self._xtickmarkers = (TICKDOWN, TICKUP)
 self._ytickmarkers = (TICKLEFT, TICKRIGHT)
- self._pad = Value(pad + size)
+ self._pad = pad + size
 
 self._loc = loc
 self._size = size
 
- self._padPixels = self.figure.dpi*self._pad*Value(1/72.0)
+ self._padPixels = self.figure.dpi * self._pad * (1/72.0)
 
 
 self.tick1line = self._get_tick1line(loc)
@@ -236,14 +236,11 @@
 xaxis=True,
 )
 
-
- trans = blend_xy_sep_transform( self.axes.transData,
- self.axes.transAxes)
+	trans = blend_xy_sep_transform(
+	 self.axes.transData, self.axes.transAxes)
 #offset the text downward with a post transformation
- transOffset = translation_transform(
- Value(0), Value(-1)*self._padPixels)
- trans.set_offset( (0,0), transOffset)
- t.set_transform( trans)
+	trans = trans + Affine2D().translated(0, -1 * self._padPixels)
+ t.set_transform(trans)
 
 self._set_artist_props(t)
 return t
@@ -264,12 +261,10 @@
 horizontalalignment='center',
 )
 
- trans = blend_xy_sep_transform( self.axes.transData,
- self.axes.transAxes)
+	trans = blend_xy_sep_transformation(
+	 self.axes.transData, self.axes.transAxes)
 # offset the text upward with a post transformation
- transOffset = translation_transform(
- Value(0), self._padPixels)
- trans.set_offset( (0,0), transOffset)
+ trans = trans + Affine2D().translated(0, self._padPixels)
 t.set_transform( trans )
 self._set_artist_props(t)
 return t
@@ -284,8 +279,8 @@
 marker = self._xtickmarkers[0],
 markersize=self._size,
 )
- l.set_transform( blend_xy_sep_transform( self.axes.transData,
- self.axes.transAxes) )
+ l.set_transform(blend_xy_sep_transform(
+		self.axes.transData, self.axes.transAxes) )
 self._set_artist_props(l)
 return l
 
@@ -300,8 +295,8 @@
 markersize=self._size,
 )
 
- l.set_transform( blend_xy_sep_transform( self.axes.transData,
- self.axes.transAxes) )
+ l.set_transform(blend_xy_sep_transform(
+		self.axes.transData, self.axes.transAxes) )
 self._set_artist_props(l)
 return l
 
@@ -314,8 +309,9 @@
 linewidth=rcParams['grid.linewidth'],
 antialiased=False,
 )
- l.set_transform( blend_xy_sep_transform( self.axes.transData,
- self.axes.transAxes) )
+ l.set_transform(
+	 blend_xy_sep_transform(
+		self.axes.transData, self.axes.transAxes))
 l.set_clip_box(self.axes.bbox)
 self._set_artist_props(l)
 
@@ -363,13 +359,11 @@
 dashdirection=0,
 xaxis=False,
 )
- trans = blend_xy_sep_transform( self.axes.transAxes,
- self.axes.transData)
+ trans = blend_xy_sep_transform(
+	 self.axes.transAxes, self.axes.transData)
 # offset the text leftward with a post transformation
+	trans = trans + Affine2D().translated(-1 * self._padPixels, 0)
 
- transOffset = translation_transform(
- Value(-1)*self._padPixels, Value(0))
- trans.set_offset( (0,0), transOffset)
 t.set_transform( trans )
 #t.set_transform( self.axes.transData )
 self._set_artist_props(t)
@@ -388,13 +382,10 @@
 xaxis=False,
 horizontalalignment='left',
 )
- trans = blend_xy_sep_transform( self.axes.transAxes,
- self.axes.transData)
+ trans = blend_xy_sep_transform(
+	 self.axes.transAxes, self.axes.transData)
 # offset the text rightward with a post transformation
-
- transOffset = translation_transform(
- self._padPixels, Value(0))
- trans.set_offset( (0,0), transOffset)
+	trans = trans + Affine2D().translated(self._padPixels, 0)
 t.set_transform( trans )
 self._set_artist_props(t)
 return t
@@ -409,8 +400,9 @@
 linestyle = 'None',
 markersize=self._size,
 )
- l.set_transform( blend_xy_sep_transform( self.axes.transAxes,
- self.axes.transData) )
+ l.set_transform(
+	 blend_xy_sep_transform(
+		self.axes.transAxes, self.axes.transData))
 self._set_artist_props(l)
 return l
 
@@ -424,8 +416,9 @@
 markersize=self._size,
 )
 
- l.set_transform( blend_xy_sep_transform( self.axes.transAxes,
- self.axes.transData) )
+ l.set_transform(
+	 blend_xy_sep_transform(
+		self.axes.transAxes, self.axes.transData))
 self._set_artist_props(l)
 return l
 
@@ -439,8 +432,8 @@
 antialiased=False,
 )
 
- l.set_transform( blend_xy_sep_transform( self.axes.transAxes,
- self.axes.transData) )
+ l.set_transform( blend_xy_sep_transform(
+		self.axes.transAxes, self.axes.transData) )
 l.set_clip_box(self.axes.bbox)
 
 self._set_artist_props(l)
@@ -989,8 +982,8 @@
 verticalalignment='top',
 horizontalalignment='center',
 )
- label.set_transform( blend_xy_sep_transform( self.axes.transAxes,
- identity_transform() ))
+ label.set_transform( blend_xy_sep_transform(
+		self.axes.transAxes, Affine2D() ))
 
 self._set_artist_props(label)
 self.label_position='bottom'
@@ -1004,8 +997,8 @@
 verticalalignment='top',
 horizontalalignment='right',
 )
- offsetText.set_transform( blend_xy_sep_transform( self.axes.transAxes,
- identity_transform() ))
+ offsetText.set_transform( blend_xy_sep_transform(
+		self.axes.transAxes, Affine2D() ))
 self._set_artist_props(offsetText)
 self.offset_text_position='bottom'
 return offsetText
@@ -1041,7 +1034,7 @@
 bottom = self.axes.bbox.ymin()
 else:
 
- bbox = bbox_all(bboxes)
+ bbox = bbox_union(bboxes)
 bottom = bbox.ymin()
 
 self.label.set_position( (x, bottom-self.LABELPAD*self.figure.dpi.get()/72.0))
@@ -1051,7 +1044,7 @@
 top = self.axes.bbox.ymax()
 else:
 
- bbox = bbox_all(bboxes2)
+ bbox = bbox_union(bboxes2)
 top = bbox.ymax()
 
 self.label.set_position( (x, top+self.LABELPAD*self.figure.dpi.get()/72.0))
@@ -1065,7 +1058,7 @@
 if not len(bboxes):
 bottom = self.axes.bbox.ymin()
 else:
- bbox = bbox_all(bboxes)
+ bbox = bbox_union(bboxes)
 bottom = bbox.ymin()
 self.offsetText.set_position((x, bottom-self.OFFSETTEXTPAD*self.figure.dpi.get()/72.0))
 
@@ -1179,8 +1172,8 @@
 horizontalalignment='right',
 rotation='vertical',
 )
- label.set_transform( blend_xy_sep_transform( identity_transform(),
- self.axes.transAxes) )
+ label.set_transform( blend_xy_sep_transform(
+		Affine2D(), self.axes.transAxes) )
 
 self._set_artist_props(label)
 self.label_position='left'
@@ -1194,8 +1187,8 @@
 verticalalignment = 'bottom',
 horizontalalignment = 'left',
 )
- offsetText.set_transform(blend_xy_sep_transform(self.axes.transAxes,
- identity_transform()) )
+ offsetText.set_transform(blend_xy_sep_transform(
+		self.axes.transAxes, Affine2D()) )
 self._set_artist_props(offsetText)
 self.offset_text_position='left'
 return offsetText
@@ -1231,7 +1224,7 @@
 left = self.axes.bbox.xmin()
 else:
 
- bbox = bbox_all(bboxes)
+ bbox = bbox_union(bboxes)
 left = bbox.xmin()
 
 self.label.set_position( (left-self.LABELPAD*self.figure.dpi.get()/72.0, y))
@@ -1241,7 +1234,7 @@
 right = self.axes.bbox.xmax()
 else:
 
- bbox = bbox_all(bboxes2)
+ bbox = bbox_union(bboxes2)
 right = bbox.xmax()
 
 self.label.set_position( (right+self.LABELPAD*self.figure.dpi.get()/72.0, y))
Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py
===================================================================
--- branches/transforms/lib/matplotlib/backends/backend_agg.py	2007年09月10日 06:55:10 UTC (rev 3821)
+++ branches/transforms/lib/matplotlib/backends/backend_agg.py	2007年09月10日 17:39:37 UTC (rev 3822)
@@ -84,7 +84,7 @@
 from matplotlib.font_manager import findfont
 from matplotlib.ft2font import FT2Font, LOAD_DEFAULT
 from matplotlib.mathtext import MathTextParser
-from matplotlib.transforms import lbwh_to_bbox
+from matplotlib.bbox import Bbox
 
 from _backend_agg import RendererAgg as _RendererAgg
 
@@ -126,7 +126,7 @@
 self.mathtext_parser = MathTextParser('Agg')
 self._fontd = {}
 
- self.bbox = lbwh_to_bbox(0,0, self.width, self.height)
+ self.bbox = Bbox.from_lbwh(0,0, self.width, self.height)
 if __debug__: verbose.report('RendererAgg.__init__ done',
 'debug-annoying')
 
@@ -277,7 +277,7 @@
 
 cliprect = gc.get_clip_rectangle()
 if cliprect is None: bbox = None
- else: bbox = lbwh_to_bbox(*cliprect)
+ else: bbox = Bbox.from_lbwh(*cliprect)
 self.draw_image(x, self.height-y, im, bbox)
 
 def get_canvas_width_height(self):
Modified: branches/transforms/lib/matplotlib/figure.py
===================================================================
--- branches/transforms/lib/matplotlib/figure.py	2007年09月10日 06:55:10 UTC (rev 3821)
+++ branches/transforms/lib/matplotlib/figure.py	2007年09月10日 17:39:37 UTC (rev 3822)
@@ -18,7 +18,8 @@
 from text import Text, _process_text_args
 
 from legend import Legend
-from transforms import Bbox, Value, Point, get_bbox_transform, unit_bbox
+from affine import get_bbox_transform
+from bbox import Bbox
 from ticker import FormatStrFormatter
 from cm import ScalarMappable
 from contour import ContourSet
@@ -127,17 +128,14 @@
 if facecolor is None: facecolor = rcParams['figure.facecolor']
 if edgecolor is None: edgecolor = rcParams['figure.edgecolor']
 
- self.dpi = Value(dpi)
- self.figwidth = Value(figsize[0])
- self.figheight = Value(figsize[1])
- self.ll = Point( Value(0), Value(0) )
- self.ur = Point( self.figwidth*self.dpi,
- self.figheight*self.dpi )
- self.bbox = Bbox(self.ll, self.ur)
-
+ self.dpi = dpi
+	self.bbox = Bbox.from_lbwh(0, 0,
+				 self.figsize[0] * dpi,
+				 self.figsize[1] * dpi)
+	
 self.frameon = frameon
 
- self.transFigure = get_bbox_transform( unit_bbox(), self.bbox)
+ self.transFigure = get_bbox_transform( Bbox.unit(), self.bbox)
 
 
 
Modified: branches/transforms/lib/matplotlib/legend.py
===================================================================
--- branches/transforms/lib/matplotlib/legend.py	2007年09月10日 06:55:10 UTC (rev 3821)
+++ branches/transforms/lib/matplotlib/legend.py	2007年09月10日 17:39:37 UTC (rev 3822)
@@ -34,12 +34,9 @@
 from patches import Patch, Rectangle, RegularPolygon, Shadow, bbox_artist, draw_bbox
 from collections import LineCollection, RegularPolyCollection, PatchCollection
 from text import Text
-from transforms import Bbox, Point, Value, get_bbox_transform, bbox_all,\
- unit_bbox, inverse_transform_bbox, lbwh_to_bbox
+from affine import get_bbox_transform
+from bbox import Bbox, bbox_union
 
-
-
-
 def line_cuts_bbox(line, bbox):
 """ Return True if and only if line cuts bbox. """
 minx, miny, width, height = bbox.get_bounds()
@@ -168,7 +165,7 @@
 else:
 raise TypeError("Legend needs either Axes or Figure as parent")
 self.parent = parent
- self.set_transform( get_bbox_transform( unit_bbox(), parent.bbox) )
+ self.set_transform( get_bbox_transform( Bbox.unit(), parent.bbox) )
 
 if loc is None:
 loc = rcParams["legend.loc"]
@@ -263,10 +260,10 @@
 
 bboxesAll = bboxesText
 bboxesAll.extend(bboxesHandles)
- bbox = bbox_all(bboxesAll)
+ bbox = bbox_union(bboxesAll)
 self.save = bbox
 
- ibox = inverse_transform_bbox(self.get_transform(), bbox)
+ ibox = bbox.inverse_transform(self.get_transform())
 self.ibox = ibox
 
 return ibox
@@ -468,7 +465,7 @@
 
 candidates = []
 for l, b in consider:
- legendBox = lbwh_to_bbox(l, b, width, height)
+ legendBox = Bbox.from_lbwh(l, b, width, height)
 badness = 0
 badness = legendBox.count_contains(verts)
 ox, oy = l-tx, b-ty
Modified: branches/transforms/lib/matplotlib/lines.py
===================================================================
--- branches/transforms/lib/matplotlib/lines.py	2007年09月10日 06:55:10 UTC (rev 3821)
+++ branches/transforms/lib/matplotlib/lines.py	2007年09月10日 17:39:37 UTC (rev 3822)
@@ -18,7 +18,7 @@
 from cbook import iterable, is_string_like, is_numlike
 from colors import colorConverter
 
-from transforms import lbwh_to_bbox, LOG10
+from bbox import lbwh_to_bbox
 from matplotlib import rcParams
 
 # special-purpose marker identifiers:
@@ -378,7 +378,7 @@
 bottom -= ms/2
 width += ms
 height += ms
- return lbwh_to_bbox( left, bottom, width, height)
+ return lbwh_to_bbox(left, bottom, width, height)
 
 
 def set_axes(self, ax):
@@ -447,13 +447,15 @@
 
 x, y = self._x, self._y
 
- try: logx = self.get_transform().get_funcx().get_type()==LOG10
- except RuntimeError: logx = False # non-separable
+	# MGDTODO: Deal with the log scale here
+	
+# try: logx = self.get_transform().get_funcx().get_type()==LOG10
+# except RuntimeError: logx = False # non-separable
 
- try: logy = self.get_transform().get_funcy().get_type()==LOG10
- except RuntimeError: logy = False # non-separable
+# try: logy = self.get_transform().get_funcy().get_type()==LOG10
+# except RuntimeError: logy = False # non-separable
 
- if not logx and not logy:
+ if True:
 return x, y
 
 if self._logcache is not None:
Modified: branches/transforms/lib/matplotlib/pylab.py
===================================================================
--- branches/transforms/lib/matplotlib/pylab.py	2007年09月10日 06:55:10 UTC (rev 3821)
+++ branches/transforms/lib/matplotlib/pylab.py	2007年09月10日 17:39:37 UTC (rev 3822)
@@ -234,7 +234,6 @@
 from lines import Line2D
 from text import Text, Annotation
 from patches import Polygon, Rectangle, Circle, Arrow
-from transforms import blend_xy_sep_transform
 from widgets import SubplotTool, Button, Slider, Widget
 
 import numerix as nx
Modified: branches/transforms/lib/matplotlib/table.py
===================================================================
--- branches/transforms/lib/matplotlib/table.py	2007年09月10日 06:55:10 UTC (rev 3821)
+++ branches/transforms/lib/matplotlib/table.py	2007年09月10日 17:39:37 UTC (rev 3822)
@@ -29,12 +29,10 @@
 from patches import Rectangle
 from cbook import enumerate, is_string_like, flatten
 from text import Text
-from transforms import Bbox, inverse_transform_bbox, bbox_all, unit_bbox, \
- get_bbox_transform
+from bbox import Bbox, bbox_union
 
 
 
-
 class Cell(Rectangle):
 """
 A cell is a Rectangle with some associated text.
@@ -132,7 +130,7 @@
 def get_text_bounds(self, renderer):
 """ Get text bounds in axes co-ordinates. """
 bbox = self._text.get_window_extent(renderer)
- bboxa = inverse_transform_bbox(self.get_transform(), bbox)
+	bbox.inverse_transform(self.get_transform())
 return bboxa.get_bounds()
 
 def get_required_width(self, renderer):
Modified: branches/transforms/lib/matplotlib/text.py
===================================================================
--- branches/transforms/lib/matplotlib/text.py	2007年09月10日 06:55:10 UTC (rev 3821)
+++ branches/transforms/lib/matplotlib/text.py	2007年09月10日 17:39:37 UTC (rev 3822)
@@ -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 transforms import lbwh_to_bbox, bbox_all, identity_transform
+from bbox import lbwh_to_bbox, bbox_union
 from lines import Line2D
 
 import matplotlib.nxutils as nxutils
Modified: branches/transforms/lib/matplotlib/transforms.py
===================================================================
--- branches/transforms/lib/matplotlib/transforms.py	2007年09月10日 06:55:10 UTC (rev 3821)
+++ branches/transforms/lib/matplotlib/transforms.py	2007年09月10日 17:39:37 UTC (rev 3822)
@@ -1,652 +1,652 @@
-"""
-The transforms module is broken into two parts, a collection of
-classes written in the extension module _transforms to handle
-efficient transformation of data, and some helper functions in
-transforms to make it easy to instantiate and use those objects.
-Hence the core of this module lives in _transforms.
+# """
+# The transforms module is broken into two parts, a collection of
+# classes written in the extension module _transforms to handle
+# efficient transformation of data, and some helper functions in
+# transforms to make it easy to instantiate and use those objects.
+# Hence the core of this module lives in _transforms.
 
-The transforms class is built around the idea of a LazyValue. A
-LazyValue is a base class that defines a method get that returns the
-value. The concrete derived class Value wraps a float, and simply
-returns the value of that float. The concrete derived class BinOp
-allows binary operations on LazyValues, so you can add them, multiply
-them, etc. When you do something like
+# The transforms class is built around the idea of a LazyValue. A
+# LazyValue is a base class that defines a method get that returns the
+# value. The concrete derived class Value wraps a float, and simply
+# returns the value of that float. The concrete derived class BinOp
+# allows binary operations on LazyValues, so you can add them, multiply
+# them, etc. When you do something like
 
- inches = Value(8)
- dpi = Value(72)
- width = inches * dpi
+# inches = Value(8)
+# dpi = Value(72)
+# width = inches * dpi
 
-width is a BinOp instance (that tells you the width of the figure in
-pixels). Later, if the figure size in changed, ie we call
+# width is a BinOp instance (that tells you the width of the figure in
+# pixels). Later, if the figure size in changed, ie we call
 
- inches.set(10)
+# inches.set(10)
 
-The width variable is automatically updated because it stores a
-pointer to the inches variable, not the value. Since a BinOp is also
-a lazy value, you can define binary operations on BinOps as well, such
-as
+# The width variable is automatically updated because it stores a
+# pointer to the inches variable, not the value. Since a BinOp is also
+# a lazy value, you can define binary operations on BinOps as well, such
+# as
 
- middle = Value(0.5) * width
+# middle = Value(0.5) * width
 
-Pairs of LazyValue instances can occur as instances of two classes:
+# Pairs of LazyValue instances can occur as instances of two classes:
 
- pt = Point( Value(x), Value(y)) # where x, y are numbers
- pt.x(), pt.y() return Value(x), Value(y))
+# pt = Point( Value(x), Value(y)) # where x, y are numbers
+# pt.x(), pt.y() return Value(x), Value(y))
 
- iv = Interval( Value(x), Value(y))
- iv.contains(z) returns True if z is in the closed interval
- iv.contains_open(z): same for open interval
- iv.span() returns y-x as a float
- iv.get_bounds() returns (x,y) as a tuple of floats
- iv.set_bounds(x, y) allows input of new floats
- iv.update(seq) updates the bounds to include all elements
- in a sequence of floats
- iv.shift(s) shifts the interval by s, a float
+# iv = Interval( Value(x), Value(y))
+# iv.contains(z) returns True if z is in the closed interval
+# iv.contains_open(z): same for open interval
+# iv.span() returns y-x as a float
+# iv.get_bounds() returns (x,y) as a tuple of floats
+# iv.set_bounds(x, y) allows input of new floats
+# iv.update(seq) updates the bounds to include all elements
+# in a sequence of floats
+# iv.shift(s) shifts the interval by s, a float
 
-The bounding box class Bbox is also heavily used, and is defined by a
-lower left point ll and an upper right point ur. The points ll and ur
-are given by Point(x, y) instances, where x and y are LazyValues. So
-you can represent a point such as
+# The bounding box class Bbox is also heavily used, and is defined by a
+# lower left point ll and an upper right point ur. The points ll and ur
+# are given by Point(x, y) instances, where x and y are LazyValues. So
+# you can represent a point such as
 
- ll = Point( Value(0), Value(0) ) # the origin
- ur = Point( width, height ) # the upper right of the figure
+# ll = Point( Value(0), Value(0) ) # the origin
+# ur = Point( width, height ) # the upper right of the figure
 
-where width and height are defined as above, using the product of the
-figure width in inches and the dpi. This is, in face, how the Figure
-bbox is defined
+# where width and height are defined as above, using the product of the
+# figure width in inches and the dpi. This is, in face, how the Figure
+# bbox is defined
 
- bbox = Bbox(ll, ur)
+# bbox = Bbox(ll, ur)
 
-A bbox basically defines an x,y coordinate system, with ll giving the
-lower left of the coordinate system and ur giving the upper right.
+# A bbox basically defines an x,y coordinate system, with ll giving the
+# lower left of the coordinate system and ur giving the upper right.
 
-The bbox methods are
+# The bbox methods are
 
- ll() - return the lower left Point
- ur() - return the upper right Point
- contains(x,y) - return True if self contains point
- overlaps(bbox) - return True if self overlaps bbox
- overlapsx(bbox) - return True if self overlaps bbox in the x interval
- overlapsy(bbox) - return True if self overlaps bbox in the y interval
- intervalx() - return the x Interval instance
- intervaly() - return the y interval instance
- get_bounds() - get the left, bottom, width, height bounding tuple
- update(xys, ignore) - update the bbox to bound all the xy tuples in
- xys; if ignore is true ignore the current contents of bbox and
- just bound the tuples. If ignore is false, bound self + tuples
- width() - return the width of the bbox
- height() - return the height of the bbox
- xmax() - return the x coord of upper right
- ymax() - return the y coord of upper right
- xmin() - return the x coord of lower left
- ymin() - return the y coord of lower left
- scale(sx,sy) - scale the bbox by sx, sy
- deepcopy() - return a deep copy of self (pointers are lost)
+# ll() - return the lower left Point
+# ur() - return the upper right Point
+# contains(x,y) - return True if self contains point
+# overlaps(bbox) - return True if self overlaps bbox
+# overlapsx(bbox) - return True if self overlaps bbox in the x interval
+# overlapsy(bbox) - return True if self overlaps bbox in the y interval
+# intervalx() - return the x Interval instance
+# intervaly() - return the y interval instance
+# get_bounds() - get the left, bottom, width, height bounding tuple
+# update(xys, ignore) - update the bbox to bound all the xy tuples in
+# xys; if ignore is true ignore the current contents of bbox and
+# just bound the tuples. If ignore is false, bound self + tuples
+# width() - return the width of the bbox
+# height() - return the height of the bbox
+# xmax() - return the x coord of upper right
+# ymax() - return the y coord of upper right
+# xmin() - return the x coord of lower left
+# ymin() - return the y coord of lower left
+# scale(sx,sy) - scale the bbox by sx, sy
+# deepcopy() - return a deep copy of self (pointers are lost)
 
 
-The basic transformation maps one bbox to another, with an optional
-nonlinear transformation of one of coordinates (eg log scaling).
+# The basic transformation maps one bbox to another, with an optional
+# nonlinear transformation of one of coordinates (eg log scaling).
 
-The base class for transformations is Transformation, and the concrete
-derived classes are SeparableTransformation and Affine. Earlier
-versions of matplotlib handled transformation of x and y separately
-(ie we assumed all transformations were separable) but this makes it
-difficult to do rotations or polar transformations, for example. All
-artists contain their own transformation, defaulting to the identity
-transform.
+# The base class for transformations is Transformation, and the concrete
+# derived classes are SeparableTransformation and Affine. Earlier
+# versions of matplotlib handled transformation of x and y separately
+# (ie we assumed all transformations were separable) but this makes it
+# difficult to do rotations or polar transformations, for example. All
+# artists contain their own transformation, defaulting to the identity
+# transform.
 
-The signature of a separable transformation instance is
+# The signature of a separable transformation instance is
 
- trans = SeparableTransformation(bbox1, bbox2, funcx, funcy)
+# trans = SeparableTransformation(bbox1, bbox2, funcx, funcy)
 
-where funcx and funcy operate on x and y. The typical linear
-coordinate transformation maps one bounding box to another, with funcx
-and funcy both identity. Eg,
+# where funcx and funcy operate on x and y. The typical linear
+# coordinate transformation maps one bounding box to another, with funcx
+# and funcy both identity. Eg,
 
- transData = Transformation(viewLim, displayLim,
- Func(IDENTITY), Func(IDENTITY))
+# transData = Transformation(viewLim, displayLim,
+# Func(IDENTITY), Func(IDENTITY))
 
-maps the axes view limits to display limits. If the xaxis scaling is
-changed to log, one simply calls
+# maps the axes view limits to display limits. If the xaxis scaling is
+# changed to log, one simply calls
 
- transData.get_funcx().set_type(LOG10)
+# transData.get_funcx().set_type(LOG10)
 
-For more general transformations including rotation, the Affine class
-is provided, which is constructed with 6 LazyValue instances:
-a, b, c, d, tx, ty. These give the values of the matrix transformation
+# For more general transformations including rotation, the Affine class
+# is provided, which is constructed with 6 LazyValue instances:
+# a, b, c, d, tx, ty. These give the values of the matrix transformation
 
- [xo = |a c| [xi + [tx
- yo] |b d| yi] ty]
+# [xo = |a c| [xi + [tx
+# yo] |b d| yi] ty]
 
-where if sx, sy are the scaling components, tx, y are the translation
-components, and alpha is the rotation
+# where if sx, sy are the scaling components, tx, y are the translation
+# components, and alpha is the rotation
 
- a = sx*cos(alpha);
- b = -sx*sin(alpha);
- c = sy*sin(alpha);
- d = sy*cos(alpha);
+# a = sx*cos(alpha);
+# b = -sx*sin(alpha);
+# c = sy*sin(alpha);
+# d = sy*cos(alpha);
 
-The affine transformation can be accomplished for row vectors with a
-single matrix multiplication
- X_new = X_old * M
-where
- M = [ a b 0
- c d 0
- tx ty 1]
-and each X is the row vector [x, y, 1]. Hence M is
-the transpose of the matrix representation given in
-http://en.wikipedia.org/wiki/Affine_transformation,
-which is for the more usual column-vector representation
-of the position.)
+# The affine transformation can be accomplished for row vectors with a
+# single matrix multiplication
+# X_new = X_old * M
+# where
+# M = [ a b 0
+# c d 0
+# tx ty 1]
+# and each X is the row vector [x, y, 1]. Hence M is
+# the transpose of the matrix representation given in
+# http://en.wikipedia.org/wiki/Affine_transformation,
+# which is for the more usual column-vector representation
+# of the position.)
 
 
 
-From a user perspective, the most important Tranformation methods are
+# From a user perspective, the most important Tranformation methods are
 
-All transformations
--------------------
- freeze() - eval and freeze the lazy objects
- thaw() - release the lazy objects
+# All transformations
+# -------------------
+# freeze() - eval and freeze the lazy objects
+# thaw() - release the lazy objects
 
- xy_tup(xy) - transform the tuple (x,y)
- seq_x_y(x, y) - transform the python sequences x and y
- numerix_x_y(x, y) - x and y are numerix 1D arrays
- numerix_xy(xy) - xy is a numerix array of shape (N,2)
- inverse_numerix_xy(xy)- inverse of the above
- seq_xy_tups(seq) - seq is a sequence of xy tuples or a (N,2) array
- inverse_xy_tup(xy) - apply the inverse transformation to tuple xy
+# xy_tup(xy) - transform the tuple (x,y)
+# seq_x_y(x, y) - transform the python sequences x and y
+# numerix_x_y(x, y) - x and y are numerix 1D arrays
+# numerix_xy(xy) - xy is a numerix array of shape (N,2)
+# inverse_numerix_xy(xy)- inverse of the above
+# seq_xy_tups(seq) - seq is a sequence of xy tuples or a (N,2) array
+# inverse_xy_tup(xy) - apply the inverse transformation to tuple xy
 
- set_offset(xy, trans) - xy is an x,y tuple and trans is a
- Transformation instance. This will apply a post transformational
- offset of all future transformations by xt,yt = trans.xy_tup(xy[0], xy[1])
+# set_offset(xy, trans) - xy is an x,y tuple and trans is a
+# Transformation instance. This will apply a post transformational
+# offset of all future transformations by xt,yt = trans.xy_tup(xy[0], xy[1])
 
- deepcopy() - returns a deep copy; references are lost
- shallowcopy() - returns a shallow copy excluding the offset
+# deepcopy() - returns a deep copy; references are lost
+# shallowcopy() - returns a shallow copy excluding the offset
 
-Separable transformations
--------------------------
+# Separable transformations
+# -------------------------
 
- get_bbox1() - return the input bbox
- get_bbox2() - return the output bbox
- set_bbox1() - set the input bbox
- set_bbox2() - set the output bbox
- get_funcx() - return the Func instance on x
- get_funcy() - return the Func instance on y
- set_funcx() - set the Func instance on x
- set_funcy() - set the Func instance on y
+# get_bbox1() - return the input bbox
+# get_bbox2() - return the output bbox
+# set_bbox1() - set the input bbox
+# set_bbox2() - set the output bbox
+# get_funcx() - return the Func instance on x
+# get_funcy() - return the Func instance on y
+# set_funcx() - set the Func instance on x
+# set_funcy() - set the Func instance on y
 
 
-Affine transformations
-----------------------
+# Affine transformations
+# ----------------------
 
- as_vec6() - return the affine as length 6 list of Values
+# as_vec6() - return the affine as length 6 list of Values
 
 
-In general, you shouldn't need to construct your own transformations,
-but should use the helper functions defined in this module.
+# In general, you shouldn't need to construct your own transformations,
+# but should use the helper functions defined in this module.
 
 
- zero - return Value(0)
- one - return Value(1)
- origin - return Point(zero(), zero())
- unit_bbox - return the 0,0 to 1,1 bounding box
- identity_affine - An affine identity transformation
- identity_transform - An identity separable transformation
- translation_transform - a pure translational affine
- scale_transform - a pure scale affine
- scale_sep_transform - a pure scale separable transformation
- scale_translation_transform - a scale and translate affine
- bound_vertices - return the bbox that bounds all the xy tuples
- bbox_all - return the bbox that bounds all the bboxes
- lbwh_to_bbox - build a bbox from tuple
- left, bottom, width, height tuple
+# zero - return Value(0)
+# one - return Value(1)
+# origin - return Point(zero(), zero())
+# unit_bbox - return the 0,0 to 1,1 bounding box
+# identity_affine - An affine identity transformation
+# identity_transform - An identity separable transformation
+# translation_transform - a pure translational affine
+# scale_transform - a pure scale affine
+# scale_sep_transform - a pure scale separable transformation
+# scale_translation_transform - a scale and translate affine
+# bound_vertices - return the bbox that bounds all the xy tuples
+# bbox_all - return the bbox that bounds all the bboxes
+# lbwh_to_bbox - build a bbox from tuple
+# left, bottom, width, height tuple
 
- multiply_affines - return the affine that is the matrix product of
- the two affines
+# multiply_affines - return the affine that is the matrix product of
+# the two affines
 
- get_bbox_transform - return a SeparableTransformation instance that
- transforms one bbox to another
+# get_bbox_transform - return a SeparableTransformation instance that
+# transforms one bbox to another
 
- blend_xy_sep_transform - mix the x and y components of two separable
- transformations into a new transformation.
- This allows you to specify x and y in
- different coordinate systems
+# blend_xy_sep_transform - mix the x and y components of two separable
+# transformations into a new transformation.
+# This allows you to specify x and y in
+# different coordinate systems
 
- transform_bbox - apply a transformation to a bbox and return the
- transformed bbox
+# transform_bbox - apply a transformation to a bbox and return the
+# transformed bbox
 
- inverse_transform_bbox - apply the inverse transformation of a bbox
- and return the inverse transformed bbox
+# inverse_transform_bbox - apply the inverse transformation of a bbox
+# and return the inverse transformed bbox
 
- offset_copy - make a copy with an offset
+# offset_copy - make a copy with an offset
 
 
-The units/transform_unit.py code has many examples.
+# The units/transform_unit.py code has many examples.
 
-A related and partly overlapping class, PBox, has been added to the
-original transforms module to facilitate Axes repositioning and resizing.
-At present, the differences between Bbox and PBox include:
+# A related and partly overlapping class, PBox, has been added to the
+# original transforms module to facilitate Axes repositioning and resizing.
+# At present, the differences between Bbox and PBox include:
 
- Bbox works with the bounding box, the coordinates of the lower-left
- and upper-right corners; PBox works with the lower-left coordinates
- and the width, height pair (left, bottom, width, height, or 'lbwh').
- Obviously, these are equivalent, but lbwh is what is used by
- Axes._position, and it is the natural specification for the types of
- manipulations for which the PBox class was made.
+# Bbox works with the bounding box, the coordinates of the lower-left
+# and upper-right corners; PBox works with the lower-left coordinates
+# and the width, height pair (left, bottom, width, height, or 'lbwh').
+# Obviously, these are equivalent, but lbwh is what is used by
+# Axes._position, and it is the natural specification for the types of
+# manipulations for which the PBox class was made.
 
- Bbox uses LazyValues grouped in pairs as 'll' and 'ur' Point objects;
- PBox uses a 4-element list, subclassed from the python list.
+# Bbox uses LazyValues grouped in pairs as 'll' and 'ur' Point objects;
+# PBox uses a 4-element list, subclassed from the python list.
 
- Bbox and PBox methods are mostly quite different, reflecting their
- different original purposes. Similarly, the CXX implementation of
- Bbox is good for methods such as update and for lazy evaluation, but
- for PBox intended uses, involving very little calculation, pure
- python probably is adequate.
+# Bbox and PBox methods are mostly quite different, reflecting their
+# different original purposes. Similarly, the CXX implementation of
+# Bbox is good for methods such as update and for lazy evaluation, but
+# for PBox intended uses, involving very little calculation, pure
+# python probably is adequate.
 
-In the future we may reimplement the PBox using Bbox
-and transforms, or eliminate it entirely by adding its methods
-and attributes to Bbox and/or putting them elsewhere in this module.
-"""
-from __future__ import division
-import math
-import numpy as npy
+# In the future we may reimplement the PBox using Bbox
+# and transforms, or eliminate it entirely by adding its methods
+# and attributes to Bbox and/or putting them elsewhere in this module.
+# """
+# from __future__ import division
+# import math
+# import numpy as npy
 
-from matplotlib._transforms import Value, Point, Interval, Bbox, Affine
-from matplotlib._transforms import IDENTITY, LOG10, POLAR, Func, FuncXY
-from matplotlib._transforms import SeparableTransformation
-from matplotlib._transforms import NonseparableTransformation
+# from matplotlib._transforms import Value, Point, Interval, Bbox, Affine
+# from matplotlib._transforms import IDENTITY, LOG10, POLAR, Func, FuncXY
+# from matplotlib._transforms import SeparableTransformation
+# from matplotlib._transforms import NonseparableTransformation
 
-def nonsingular(vmin, vmax, expander=0.001, tiny=1e-15, increasing=True):
- '''
- Ensure the endpoints of a range are not too close together.
+# def nonsingular(vmin, vmax, expander=0.001, tiny=1e-15, increasing=True):
+# '''
+# Ensure the endpoints of a range are not too close together.
 
- "too close" means the interval is smaller than 'tiny' times
- the maximum absolute value.
+# "too close" means the interval is smaller than 'tiny' times
+# the maximum absolute value.
 
- If they are too close, each will be moved by the 'expander'.
- If 'increasing' is True and vmin > vmax, they will be swapped,
- regardless of whether they are too close.
- '''
- swapped = False
- if vmax < vmin:
- vmin, vmax = vmax, vmin
- swapped = True
- if vmax - vmin <= max(abs(vmin), abs(vmax)) * tiny:
- if vmin==0.0:
- vmin = -expander
- vmax = expander
- else:
- vmin -= expander*abs(vmin)
- vmax += expander*abs(vmax)
- if swapped and not increasing:
- vmin, vmax = vmax, vmin
- return vmin, vmax
+# If they are too close, each will be moved by the 'expander'.
+# If 'increasing' is True and vmin > vmax, they will be swapped,
+# regardless of whether they are too close.
+# '''
+# swapped = False
+# if vmax < vmin:
+# vmin, vmax = vmax, vmin
+# swapped = True
+# if vmax - vmin <= max(abs(vmin), abs(vmax)) * tiny:
+# if vmin==0.0:
+# vmin = -expander
+# vmax = expander
+# else:
+# vmin -= expander*abs(vmin)
+# vmax += expander*abs(vmax)
+# if swapped and not increasing:
+# vmin, vmax = vmax, vmin
+# return vmin, vmax
 
 
-def zero(): return Value(0)
+# def zero(): return Value(0)
 
-def one() : return Value(1)
+# def one() : return Value(1)
 
-def origin():
- return Point( zero(), zero() )
+# def origin():
+# return Point( zero(), zero() )
 
-def unit_bbox():
- """
- Get a 0,0 -> 1,1 Bbox instance
- """
- return Bbox( origin(), Point( one(), one() ) )
+# def unit_bbox():
+# """
+# Get a 0,0 -> 1,1 Bbox instance
+# """
+# return Bbox( origin(), Point( one(), one() ) )
 
-def identity_affine():
- """
- Get an affine transformation that maps x,y -> x,y
- """
+# def identity_affine():
+# """
+# Get an affine transformation that maps x,y -> x,y
+# """
 
- return Affine(one(), zero(), zero(), one(), zero(), zero())
+# return Affine(one(), zero(), zero(), one(), zero(), zero())
 
-def identity_transform():
- """
- Get an affine transformation that maps x,y -> x,y
- """
- return SeparableTransformation(unit_bbox(), unit_bbox(),
- Func(IDENTITY),
- Func(IDENTITY))
+# def identity_transform():
+# """
+# Get an affine transformation that maps x,y -> x,y
+# """
+# return SeparableTransformation(unit_bbox(), unit_bbox(),
+# Func(IDENTITY),
+# Func(IDENTITY))
 
-def translation_transform(tx, ty):
- """
- return a pure tranlational transformation...
 
[truncated message content]
From: <md...@us...> - 2007年09月10日 17:40:51
Revision: 3823
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3823&view=rev
Author: mdboom
Date: 2007年09月10日 10:40:47 -0700 (2007年9月10日)
Log Message:
-----------
Adding new files that will eventually replace transforms.py/cpp
Added Paths:
-----------
 branches/transforms/lib/matplotlib/affine.py
 branches/transforms/lib/matplotlib/bbox.py
Added: branches/transforms/lib/matplotlib/affine.py
===================================================================
--- branches/transforms/lib/matplotlib/affine.py	 (rev 0)
+++ branches/transforms/lib/matplotlib/affine.py	2007年09月10日 17:40:47 UTC (rev 3823)
@@ -0,0 +1,207 @@
+"""
+A set of classes to handle transformations.
+
+2007 Michael Droettboom
+"""
+
+import numpy as N
+from numpy.linalg import inv
+
+class Transform(object):
+ def __call__(self, points):
+	raise NotImplementedError()
+
+ def __add__(self, other):
+	if isinstance(other, Transform):
+	 return CompositeTransform(self, other)
+	raise TypeError("Can not add Transform to object of type '%s'" % type(other))
+
+ def __radd__(self, other):
+	if isinstance(other, Transform):
+	 return CompositeTransform(other, self)
+	raise TypeError("Can not add Transform to object of type '%s'" % type(other))
+ 
+ def has_inverse(self):
+	raise NotImplementedError()
+ 
+ def inverted(self):
+	raise NotImplementedError()
+
+ def is_separable(self):
+	return False
+
+class CompositeTransform(Transform):
+ def __init__(self, a, b):
+	assert a.output_dims == b.input_dims
+	self.a = a
+	self.b = b
+
+ def __call__(self, points):
+	return self.b(self.a(points))
+ 
+class Affine2D(Transform):
+ input_dims = 2
+ output_dims = 2
+ 
+ def __init__(self, matrix = None):
+ """
+ Initialize an Affine transform from a 3x3 numpy float array.
+
+ a c e
+ b d f
+ 0 0 1
+ """
+	if matrix is None:
+	 matrix = N.identity(3)
+	else:
+	 assert matrix.shape == (3, 3)
+	self.mtx = matrix
+
+ def __repr__(self):
+	return repr(self.mtx)
+
+ def __str__(self):
+	return str(self.mtx)
+ 
+ #@staticmethod
+ def from_values(a, b, c, d, e, f):
+ return Affine2D(Affine2D.matrix_from_values(a, b, c, d, e, f))
+ from_values = staticmethod(from_values)
+ 
+ #@staticmethod
+ def matrix_from_values(a, b, c, d, e, f):
+	affine = N.zeros((3,3), N.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 __call__(self, points):
+ """
+ Applies the transformation to a set of 2D points and
+	returns the result.
+
+	points must be a numpy array of shape (N, 2), where N is the
+	number of points.
+	"""
+	# MGDTODO: This involves a copy. We may need to do something like
+	# http://neuroimaging.scipy.org/svn/ni/ni/trunk/neuroimaging/core/reference/mapping.py
+	# to separate the matrix out into the translation and scale components
+	# and apply each separately (which is still sub-optimal)
+
+	# This is nicer for now, however, since we can just keep a
+	# regular affine matrix around
+	new_points = points.swapaxes(0, 1)
+	new_points = N.vstack((new_points, N.ones((1, points.shape[0]))))
+	result = N.dot(self.mtx, new_points)[:2]
+	result.swapaxes(0, 1)
+	return result
+ 
+ #@staticmethod
+ def _concat(a, b):
+ return N.dot(b, a)
+ _concat = staticmethod(_concat)
+
+ def concat(a, b):
+	return Affine2D(Affine2D._concat(a.mtx, b.mtx))
+ concat = staticmethod(concat)
+ 
+ #@staticmethod
+ def identity():
+ return Affine2D(N.identity(3))
+ identity = staticmethod(identity)
+
+ def __add__(self, other):
+ if isinstance(other, Affine2D):
+	 return Affine2D.concat(self, other)
+	return Transform.__add__(self, other)
+
+ def __radd__(self, other):
+ if isinstance(other, Affine2D):
+	 return Affine2D.concat(other, self)
+	return Transform.__radd__(self, other)
+	
+ def rotated(self, theta):
+ a = N.cos(theta)
+ b = N.sin(theta)
+ rotate_mtx = self.matrix_from_values(a, b, -b, a, 0, 0)
+ return Affine2D(self._concat(self.mtx, rotate_mtx))
+
+ def rotated_deg(self, degrees):
+ return self.rotated(degrees*N.pi/180.)
+
+ def translated(self, tx, ty):
+ translate_mtx = self.matrix_from_values(1., 0., 0., 1., tx, ty)
+ return Affine2D(self._concat(self.mtx, translate_mtx))
+
+ def scaled(self, sx, sy=None):
+	if sy is None:
+	 sy = sx
+	scale_mtx = self.matrix_from_values(sx, 0., 0., sy, 0., 0.)
+ return Affine2D(self._concat(self.mtx, scale_mtx))
+
+ def inverted(self):
+	# MGDTODO: We may want to optimize by storing the inverse
+	# of the transform with every transform
+	return Affine2D(inv(self.mtx))
+ 
+ def is_separable(self):
+	mtx = self.mtx
+	return mtx[0, 1] == 0.0 and mtx[1, 0] == 0.0
+
+class BlendedAffine2D(Affine2D):
+ def __init__(self, x_transform, y_transform):
+	assert isinstance(x_transform, Affine2D)
+	assert isinstance(y_transform, Affine2D)
+	assert x_transform.is_separable()
+	assert y_transform.is_separable()
+	x_mtx = x_transform.mtx
+	y_mtx = y_transform.mtx
+	self.mtx = self.matrix_from_values(
+	 x_mtx[0,0], 0.0, 0.0, y_mtx[1,1], x_mtx[0,2], y_mtx[1,2])
+
+# This is a placeholder since eventually we may need to handle the
+# more general case of two transforms that aren't affines
+BlendedTransform = BlendedAffine2D
+
+def blend_xy_sep_transform(x_transform, y_transform):
+ return BlendedAffine2D(x_transform, y_transform)
+
+def get_bbox_transform(boxin, boxout):
+ x_scale = boxout.width() / boxin.width()
+ y_scale = boxout.height() / boxin.height()
+ 
+ # MGDTODO: Optimize
+ return Affine2D() \
+	.translated(-boxin.xmin(), -boxin.ymin()) \
+	.scaled(x_scale, y_scale) \
+	.translated(boxout.xmin(), boxout.ymin())
+ 
+if __name__ == '__main__':
+ print Affine2D.from_values(1., 0, 0, 1, 0, 0)
+ 
+ print "translated", Affine2D.identity().translated(5, 4)
+ print "rotated", Affine2D.identity().rotated_deg(30)
+ print "scaled", Affine2D.identity().scaled(5, 4)
+ 
+ transform = Affine2D.identity().rotated_deg(30).translated(5, 4)
+
+ points = N.array([[1, 2], [3, 4], [5, 6]])
+
+ print inv(transform.mtx)
+ 
+ print transform(points)
+
+ transform = Affine2D.identity().scaled(5., 1.).translated(10, 0)
+ print transform
+ print transform.inverted()
+
+ from bbox import Bbox
+ boxin = Bbox([[10, 10], [320, 240]])
+ boxout = Bbox([[25, 25], [640, 400]])
+ trans = bbox_transform(boxin, boxout)
+ print trans
+ print trans(N.array([[10, 10], [320, 240]]))
+ 
+__all__ = ['Transform', 'Affine2D']
Added: branches/transforms/lib/matplotlib/bbox.py
===================================================================
--- branches/transforms/lib/matplotlib/bbox.py	 (rev 0)
+++ branches/transforms/lib/matplotlib/bbox.py	2007年09月10日 17:40:47 UTC (rev 3823)
@@ -0,0 +1,108 @@
+"""
+A convenience class for handling bounding boxes
+
+2007 Michael Droettboom
+"""
+
+import numpy as N
+
+class Bbox:
+ def __init__(self, points):
+	self._points = N.array(points)
+
+ #@staticmethod
+ def unit():
+	return Bbox([[0,0], [1,1]])
+ unit = staticmethod(unit)
+
+ #@staticmethod
+ def from_lbwh(left, bottom, width, height):
+	return Bbox([[left, bottom], [left + width, bottom + height]])
+ from_lbwh = staticmethod(from_lbwh)
+
+ #@staticmethod
+ def from_lbrt(left, bottom, right, top):
+	return Bbox([[left, bottom], [right, top]])
+ from_lbwh = staticmethod(from_lbwh)
+ 
+ # MGDTODO: Probably a more efficient ways to do this...
+ def xmin(self):
+	return self._points[0,0]
+
+ def ymin(self):
+	return self._points[0,1]
+
+ def xmax(self):
+	return self._points[1,0]
+ 
+ def ymax(self):
+	return self._points[1,1]
+
+ def width(self):
+	return self.xmax() - self.xmin()
+
+ def height(self):
+	return self.ymax() - self.ymin()
+
+ def transform(self, transform):
+	return Bbox(transform(points))
+
+ def inverse_transform(self, transform):
+	return Bbox(transform.inverted()(points))
+
+ def get_bounds(self):
+	return (self.xmin(), self.ymin(),
+		self.xmax() - self.xmin(), self.ymax() - self.ymin())
+ 
+def lbwh_to_bbox(left, bottom, width, height):
+ return Bbox([[left, bottom], [left + width, bottom + height]])
+ 
+def bbox_union(bboxes):
+ """
+ Return the Bbox that bounds all bboxes
+ """
+ assert(len(bboxes))
+
+ if len(bboxes) == 1:
+	return bboxes[0]
+
+ 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)
+
+ return Bbox(xmin, ymin, xmax, ymax)
+
+# MGDTODO: There's probably a better place for this
+def nonsingular(vmin, vmax, expander=0.001, tiny=1e-15, increasing=True):
+ '''
+ Ensure the endpoints of a range are not too close together.
+
+ "too close" means the interval is smaller than 'tiny' times
+ the maximum absolute value.
+
+ If they are too close, each will be moved by the 'expander'.
+ If 'increasing' is True and vmin > vmax, they will be swapped,
+ regardless of whether they are too close.
+ '''
+ swapped = False
+ if vmax < vmin:
+ vmin, vmax = vmax, vmin
+ swapped = True
+ if vmax - vmin <= max(abs(vmin), abs(vmax)) * tiny:
+ if vmin==0.0:
+ vmin = -expander
+ vmax = expander
+ else:
+ vmin -= expander*abs(vmin)
+ vmax += expander*abs(vmax)
+ if swapped and not increasing:
+ vmin, vmax = vmax, vmin
+ return vmin, vmax
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2007年09月12日 13:36:31
Revision: 3835
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3835&view=rev
Author: mdboom
Date: 2007年09月12日 06:36:25 -0700 (2007年9月12日)
Log Message:
-----------
Second pass, using a stateful transform tree.
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/backends/backend_agg.py
 branches/transforms/lib/matplotlib/backends/backend_tkagg.py
 branches/transforms/lib/matplotlib/figure.py
 branches/transforms/lib/matplotlib/legend.py
 branches/transforms/lib/matplotlib/lines.py
 branches/transforms/lib/matplotlib/table.py
 branches/transforms/lib/matplotlib/text.py
 branches/transforms/lib/matplotlib/ticker.py
Removed Paths:
-------------
 branches/transforms/lib/matplotlib/bbox.py
Modified: branches/transforms/lib/matplotlib/affine.py
===================================================================
--- branches/transforms/lib/matplotlib/affine.py	2007年09月12日 07:04:38 UTC (rev 3834)
+++ branches/transforms/lib/matplotlib/affine.py	2007年09月12日 13:36:25 UTC (rev 3835)
@@ -6,19 +6,203 @@
 
 import numpy as N
 from numpy.linalg import inv
+from sets import Set
 
-class Transform(object):
+# MGDTODO: This creates a ton of cyclical references. We may want to
+# consider using weak references
+
+class TransformNode(object):
+ def __init__(self):
+	self._parents = Set()
+	
+ def invalidate(self):
+	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)
+
+class Bbox(TransformNode):
+ def __init__(self, points):
+	TransformNode.__init__(self)
+	self._points = N.asarray(points, N.float_)
+	self.track = False
+
+ def __del__(self):
+	if self.track:
+	 print "Bbox::__del__"
+	
+ #@staticmethod
+ def unit():
+	return Bbox([[0,0], [1,1]])
+ unit = staticmethod(unit)
+
+ #@staticmethod
+ def from_lbwh(left, bottom, width, height):
+	return Bbox([[left, bottom], [left + width, bottom + height]])
+ from_lbwh = staticmethod(from_lbwh)
+
+ #@staticmethod
+ def from_lbrt(left, bottom, right, top):
+	return Bbox([[left, bottom], [right, top]])
+ from_lbrt = staticmethod(from_lbrt)
+
+ def update_from_data(self, x, y):
+	self._points = N.array([[x.min(), y.min()], [x.max(), y.max()]], N.float_)
+	self.invalidate()
+	if self.track:
+	 print "Bbox::update_from_data", self._points
+ 
+ def copy(self):
+	if self.track:
+	 print "Bbox::copy"
+	return Bbox(self._points.copy())
+
+ def __repr__(self):
+	return 'Bbox(%s)' % repr(self._points)
+ __str__ = __repr__
+
+ def __cmp__(self, other):
+	# MGDTODO: Totally suboptimal
+	if isinstance(other, Bbox):
+	 return (self._points == other._points).all()
+	return -1
+ 
+ # MGDTODO: Probably a more efficient ways to do this...
+ def _get_xmin(self):
+	if self.track:
+	 print "Bbox::_get_xmin"
+	return self._points[0, 0]
+ def _set_xmin(self, val):
+	print "Bbox::_set_xmin"
+	self._points[0, 0] = val
+	self.invalidate()
+ xmin = property(_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)
+
+ 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)
+
+ 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)
+
+ 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)
+ 
+ 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)
+ 
+ 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)
+
+ 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)
+
+ 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 transformed(self, transform):
+	return Bbox(self.transform(self._points))
+
+ def inverse_transformed(self, transform):
+	return Bbox(self.transform.inverted()(self._points))
+ 
+ def get_bounds(self):
+	return (self.xmin, self.ymin,
+		self.xmax - self.xmin, self.ymax - self.ymin)
+
+ def expanded(self, sw, sh):
+	width = self.width()
+	height = self.height()
+	deltaw = (sw * width - width) / 2.0
+	deltah = (sh * height - height) / 2.0
+	a = N.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)
+
+ #@staticmethod
+ def union(bboxes):
+	"""
+	Return the Bbox that bounds all bboxes
+	"""
+	assert(len(bboxes))
+
+	if len(bboxes) == 1:
+	 return bboxes[0]
+
+	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)
+
+	return Bbox.from_lbrt(xmin, ymin, xmax, ymax)
+ union = staticmethod(union)
+ 
+class Transform(TransformNode):
+ def __init__(self):
+	TransformNode.__init__(self)
+ 
 def __call__(self, points):
 	raise NotImplementedError()
 
 def __add__(self, other):
 	if isinstance(other, Transform):
-	 return CompositeTransform(self, other)
+	 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 CompositeTransform(other, self)
+	 return composite_transform_factory(other, self)
 	raise TypeError("Can not add Transform to object of type '%s'" % type(other))
 
 def has_inverse(self):
@@ -30,15 +214,9 @@
 def is_separable(self):
 	return False
 
-class CompositeTransform(Transform):
- def __init__(self, a, b):
-	assert a.output_dims == b.input_dims
-	self.a = a
-	self.b = b
-
- def __call__(self, points):
-	return self.b(self.a(points))
- 
+ def is_affine(self):
+	return False
+	
 class Affine2D(Transform):
 input_dims = 2
 output_dims = 2
@@ -51,15 +229,22 @@
 b d f
 0 0 1
 """
+	Transform.__init__(self)
 	if matrix is None:
 	 matrix = N.identity(3)
 	else:
 	 assert matrix.shape == (3, 3)
-	self.mtx = matrix
+	self._mtx = matrix
+	self._inverted = None
 
 def __repr__(self):
-	return "Affine2D(%s)" % repr(self.mtx)
+	return "Affine2D(%s)" % repr(self._mtx)
 __str__ = __repr__
+
+ def _do_invalidation(self):
+	result = self._inverted is None
+	self._inverted = None
+	return result
 
 #@staticmethod
 def from_values(a, b, c, d, e, f):
@@ -67,7 +252,8 @@
 from_values = staticmethod(from_values)
 
 def to_values(self):
-	return tuple(self.mtx[:2].swapaxes(0, 1).flatten())
+	mtx = self.get_matrix()
+	return tuple(mtx[:2].swapaxes(0, 1).flatten())
 
 #@staticmethod
 def matrix_from_values(a, b, c, d, e, f):
@@ -78,6 +264,9 @@
 	return affine
 matrix_from_values = staticmethod(matrix_from_values)
 
+ def get_matrix(self):
+	return self._mtx
+ 
 def __call__(self, points):
 """
 Applies the transformation to a set of 2D points and
@@ -91,13 +280,14 @@
 	# to separate the matrix out into the translation and scale components
 	# and apply each separately (which is still sub-optimal)
 
-	# This is nicer for now, however, since we can just keep a
+	# This is easier for now, however, since we can just keep a
 	# regular affine matrix around
 	# MGDTODO: Trap cases where this isn't an array and fix there
-	points = N.array(points, N.float_)
+	mtx = self.get_matrix()
+	points = N.asarray(points, N.float_)
 	new_points = points.swapaxes(0, 1)
 	new_points = N.vstack((new_points, N.ones((1, points.shape[0]))))
-	result = N.dot(self.mtx, new_points)[:2]
+	result = N.dot(mtx, new_points)[:2]
 	return result.swapaxes(0, 1)
 
 #@staticmethod
@@ -105,8 +295,9 @@
 return N.dot(b, a)
 _concat = staticmethod(_concat)
 
+ #@staticmethod
 def concat(a, b):
-	return Affine2D(Affine2D._concat(a.mtx, b.mtx))
+	return Affine2D(Affine2D._concat(a._mtx, b._mtx))
 concat = staticmethod(concat)
 
 #@staticmethod
@@ -114,100 +305,246 @@
 return Affine2D(N.identity(3))
 identity = staticmethod(identity)
 
- def __add__(self, other):
- if isinstance(other, Affine2D):
-	 return Affine2D.concat(self, other)
-	return Transform.__add__(self, other)
-
- def __radd__(self, other):
- if isinstance(other, Affine2D):
-	 return Affine2D.concat(other, self)
-	return Transform.__radd__(self, other)
-	
- def rotated(self, theta):
+ def rotate(self, theta):
 a = N.cos(theta)
 b = N.sin(theta)
 rotate_mtx = self.matrix_from_values(a, b, -b, a, 0, 0)
- return Affine2D(self._concat(self.mtx, rotate_mtx))
+ self._mtx = self._concat(self._mtx, rotate_mtx)
+	self.invalidate()
+	return self
 
- def rotated_deg(self, degrees):
- return self.rotated(degrees*N.pi/180.)
+ def rotate_deg(self, degrees):
+ return self.rotate(degrees*N.pi/180.)
 
- def translated(self, tx, ty):
+ def translate(self, tx, ty):
 translate_mtx = self.matrix_from_values(1., 0., 0., 1., tx, ty)
- return Affine2D(self._concat(self.mtx, translate_mtx))
+ self._mtx = self._concat(self._mtx, translate_mtx)
+	self.invalidate()
+	return self
 
- def scaled(self, sx, sy=None):
+ def scale(self, sx, sy=None):
 	if sy is None:
 	 sy = sx
 	scale_mtx = self.matrix_from_values(sx, 0., 0., sy, 0., 0.)
- return Affine2D(self._concat(self.mtx, scale_mtx))
+ self._mtx = self._concat(self._mtx, scale_mtx)
+	self.invalidate()
+	return self
 
 def inverted(self):
-	# MGDTODO: We may want to optimize by storing the inverse
-	# of the transform with every transform
-	return Affine2D(inv(self.mtx))
+	if self._inverted is None:
+	 mtx = self.get_matrix()
+	 self._inverted = Affine2D(inv(mtx))
+	return self._inverted
 
 def is_separable(self):
-	mtx = self.mtx
+	mtx = self.get_matrix()
 	return mtx[0, 1] == 0.0 and mtx[1, 0] == 0.0
 
+ def is_affine(self):
+	return True
+ 
 class BlendedAffine2D(Affine2D):
 def __init__(self, x_transform, y_transform):
-#	assert isinstance(x_transform, Affine2D)
-#	assert isinstance(y_transform, Affine2D)
+	assert x_transform.is_affine()
+	assert y_transform.is_affine()
 	assert x_transform.is_separable()
 	assert y_transform.is_separable()
-	x_mtx = x_transform.mtx
-	y_mtx = y_transform.mtx
-	self.mtx = self.matrix_from_values(
-	 x_mtx[0,0], 0.0, 0.0, y_mtx[1,1], x_mtx[0,2], y_mtx[1,2])
 
-# This is a placeholder since eventually we may need to handle the
-# more general case of two transforms that aren't affines
-BlendedTransform = BlendedAffine2D
+	Transform.__init__(self)
+	self.add_children([x_transform, y_transform])
+	self._x = x_transform
+	self._y = y_transform
+	self._mtx = None
+	self._inverted = None
 
-def blend_xy_sep_transform(x_transform, y_transform):
- return BlendedAffine2D(x_transform, y_transform)
+ def __repr__(self):
+	return "BlendedAffine2D(%s,%s)" % (self._x, self._y)
+ __str__ = __repr__
+	
+ def _do_invalidation(self):
+	if self._mtx is not None:
+	 self._mtx = None
+	 Affine2D._do_invalidation(self)
+	 return False
+	return True
 
-def get_bbox_transform(boxin, boxout):
- x_scale = boxout.width() / boxin.width()
- y_scale = boxout.height() / boxin.height()
+ def _make__mtx(self):
+	if self._mtx is None:
+	 x_mtx = self._x.get_matrix()
+	 y_mtx = self._y.get_matrix()
+	 self._mtx = N.vstack([x_mtx[0], y_mtx[1], [0.0, 0.0, 1.0]])
+# 	 self._mtx = self.matrix_from_values(
+# 		x_mtx[0,0], 0.0, 0.0, y_mtx[1,1], x_mtx[0,2], y_mtx[1,2])
+	 print "Blended", x_mtx, y_mtx, self._mtx
+	
+ def is_separable(self):
+	return True
+
+ def get_matrix(self):
+	self._make__mtx()
+	return self._mtx
 
- # MGDTODO: Optimize
- return Affine2D() \
-	.translated(-boxin.xmin(), -boxin.ymin()) \
-	.scaled(x_scale, y_scale) \
-	.translated(boxout.xmin(), boxout.ymin())
+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):
+	# MGDTODO: Implement me
+	pass
+
+class CompositeAffine2D(Affine2D):
+ def __init__(self, a, b):
+	assert a.is_affine()
+	assert b.is_affine()
+
+	Transform.__init__(self)
+	self.add_children([a, b])
+	self._a = a
+	self._b = b
+	self._mtx = None
+	self._inverted = None
+
+ def __repr__(self):
+	return "CompositeAffine2D(%s, %s)" % (self._a, self._b)
+ __str__ = __repr__
+
+ def _do_invalidation(self):
+	self._mtx = None
+	Affine2D._do_invalidation(self)
 
-if __name__ == '__main__':
- print Affine2D.from_values(1., 0, 0, 1, 0, 0)
- 
- print "translated", Affine2D.identity().translated(5, 4)
- print "rotated", Affine2D.identity().rotated_deg(30)
- print "scaled", Affine2D.identity().scaled(5, 4)
- 
- transform = Affine2D.identity().rotated_deg(30).translated(5, 4)
+ def _make__mtx(self):
+	if self._mtx is None:
+	 self._mtx = self._concat(
+		self._b.get_matrix(),
+		self._a.get_matrix())
 
- points = N.array([[1, 2], [3, 4], [5, 6]])
+ 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
 
- print inv(transform.mtx)
+	Transform.__init__(self)
+	self.add_children([a, b])
+	self._a = a
+	self._b = b
+
+ def __call__(self, points):
+	# MGDTODO: Optimize here by concatenating affines if possible
+	return self._b(self._a(points))
+
+class BboxTransform(Affine2D):
+ def __init__(self, boxin, boxout):
+	assert isinstance(boxin, Bbox)
+	assert isinstance(boxout, Bbox)
+
+	Transform.__init__(self)
+	self.add_children([boxin, boxout])
+	self._boxin = boxin
+	self._boxout = boxout
+	self._mtx = None
+	self._inverted = None
+
+ def __repr__(self):
+	return "BboxTransform(%s, %s)" % (self._boxin, self._boxout)
+ __str__ = __repr__
+	
+ def _do_invalidation(self):
+	if self._mtx is not None:
+	 self._mtx = None
+	 Affine2D._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
+
+	 # MGDTODO: Optimize
+	 affine = Affine2D() \
+		.translate(-boxin.xmin, -boxin.ymin) \
+		.scale(x_scale, y_scale) \
+		.translate(boxout.xmin, boxout.ymin)
+
+	 self._mtx = affine._mtx
+	
+ def __call__(self, points):
+	self._make__mtx()
+	return Affine2D.__call__(self, points)
+
+ def inverted(self):
+	self._make__mtx()
+	return Affine2D.inverted(self)
+
+ def is_separable(self):
+	return True
+
+ def get_matrix(self):
+	self._make__mtx()
+	return self._mtx
 
- print transform(points)
+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 BlendedTransform(x_transform, y_transform)
 
- transform = Affine2D.identity().scaled(5., 1.).translated(10, 0)
- print transform
- print transform.inverted()
+def composite_transform_factory(a, b):
+ if a.is_affine() and b.is_affine():
+	return CompositeAffine2D(a, b)
+ return CompositeTransform(a, b)
 
- from bbox import Bbox
- print "BBOX"
- boxin = Bbox([[10, 10], [320, 240]])
- boxout = Bbox([[25, 25], [640, 400]])
- print boxin._points, boxin.xmin(), boxin.ymin(), boxin.xmax(), boxin.ymax()
- print boxout._points, boxout.xmin(), boxout.ymin(), boxout.xmax(), boxout.ymax()
- trans = get_bbox_transform(boxin, boxout)
- print trans
- print trans(N.array([[10, 10], [320, 240]]))
- print trans([[10, 10]])
+# MGDTODO: There's probably a better place for this
+def nonsingular(vmin, vmax, expander=0.001, tiny=1e-15, increasing=True):
+ '''
+ Ensure the endpoints of a range are not too close together.
+
+ "too close" means the interval is smaller than 'tiny' times
+ the maximum absolute value.
+
+ If they are too close, each will be moved by the 'expander'.
+ If 'increasing' is True and vmin > vmax, they will be swapped,
+ regardless of whether they are too close.
+ '''
+ swapped = False
+ if vmax < vmin:
+ vmin, vmax = vmax, vmin
+ swapped = True
+ if vmax - vmin <= max(abs(vmin), abs(vmax)) * tiny:
+ if vmin==0.0:
+ vmin = -expander
+ vmax = expander
+ else:
+ vmin -= expander*abs(vmin)
+ vmax += expander*abs(vmax)
+ if swapped and not increasing:
+ vmin, vmax = vmax, vmin
+ return vmin, vmax
+
+# MGDTODO: Optimize
+def interval_contains(interval, val):
+ return interval[0] <= val and interval[1] >= val
+
+def interval_contains_open(interval, val):
+ return interval[0] < val and interval[1] > val
 
+if __name__ == '__main__':
+ bbox1 = Bbox([[10., 15.], [20., 25.]])
+ bbox2 = Bbox([[30., 35.], [40., 45.]])
+ trans = BboxTransform(bbox1, bbox2)
+ print trans(bbox1._points)
+
+ bbox2.intervalx = 50, 55
+ print trans(bbox1._points)
+ 
 __all__ = ['Transform', 'Affine2D']
Modified: branches/transforms/lib/matplotlib/artist.py
===================================================================
--- branches/transforms/lib/matplotlib/artist.py	2007年09月12日 07:04:38 UTC (rev 3834)
+++ branches/transforms/lib/matplotlib/artist.py	2007年09月12日 13:36:25 UTC (rev 3835)
@@ -138,7 +138,6 @@
 
 ACCEPTS: a matplotlib.transform transformation instance
 """
-	print "set_transform", t
 self._transform = t
 self._transformSet = True
 self.pchanged()
Modified: branches/transforms/lib/matplotlib/axes.py
===================================================================
--- branches/transforms/lib/matplotlib/axes.py	2007年09月12日 07:04:38 UTC (rev 3834)
+++ branches/transforms/lib/matplotlib/axes.py	2007年09月12日 13:36:25 UTC (rev 3835)
@@ -12,7 +12,6 @@
 from matplotlib import affine as maffine
 from matplotlib import agg
 from matplotlib import axis as maxis
-from matplotlib import bbox as mbbox
 from matplotlib import cbook
 from matplotlib import collections as mcoll
 from matplotlib import colors as mcolors
@@ -33,7 +32,6 @@
 
 iterable = cbook.iterable
 is_string_like = cbook.is_string_like
-Wrapper = cbook.Wrapper
 
 
 def delete_masked_points(*args):
@@ -484,8 +482,8 @@
 
 """
 martist.Artist.__init__(self)
- self._position = rect
- self._originalPosition = rect
+ self._position = maffine.Bbox.from_lbwh(*rect)
+ self._originalPosition = self._position.copy()
 self.set_axes(self)
 self.set_aspect('auto')
 self.set_adjustable('box')
@@ -615,11 +613,11 @@
 """
 martist.Artist.set_figure(self, fig)
 
- l, b, w, h = self._position
- xmin = fig.bbox.xmin()
- xmax = fig.bbox.xmax()
- ymin = fig.bbox.ymin()
- ymax = fig.bbox.ymax()
+ l, b, w, h = self._position.get_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
@@ -627,7 +625,7 @@
 self.right = (l+w)*figw
 self.top = (b+h)*figh
 
- self.bbox = mbbox.Bbox.from_lbrt(
+ self.bbox = maffine.Bbox.from_lbrt(
 self.left, self.bottom,
 self.right, self.top,
 )
@@ -639,7 +637,7 @@
 set the dataLim and viewLim BBox attributes and the
 transData and transAxes Transformation attributes
 """
- Bbox = mbbox.Bbox
+ Bbox = maffine.Bbox
 if self._sharex is not None:
 left = self._sharex.viewLim.xmin()
 right = self._sharex.viewLim.xmax()
@@ -655,11 +653,12 @@
 
 self.viewLim = Bbox.from_lbrt(left, bottom, right, top)
 	self.dataLim = Bbox.unit()
+	self.dataLim.track = True
 	
- self.transData = maffine.get_bbox_transform(
+ self.transData = maffine.BboxTransform(
 self.viewLim, self.bbox)
- self.transAxes = maffine.get_bbox_transform(
- self.dataLim, self.bbox)
+ self.transAxes = maffine.BboxTransform(
+ Bbox.unit(), self.bbox)
 
 	print "_set_lim_and_transforms", self.viewLim, self.transData, self.dataLim, self.transAxes, self.bbox
 
@@ -1184,9 +1183,8 @@
 	# MGDTODO
 ## self.dataLim.update_numerix(x, y, -1)
 	print "update_datalim_numerix", self.dataLim,
-	self.dataLim = mbbox.Bbox.from_data(x, y)
+	self.dataLim.update_from_data(x, y)
 	print self.dataLim
-	# MGDTODO side-effects
 
 def _get_verts_in_data_coords(self, trans, xys):
 if trans == self.transData:
@@ -1247,7 +1245,7 @@
 axis direction reversal that has already been done.
 """
 # if image data only just use the datalim
-	print "autoscale_view"
+	print "autoscale_view", self._autoscaleon, scalex, scaley
 	
 if not self._autoscaleon: return
 if (tight or (len(self.images)>0 and
@@ -1504,7 +1502,7 @@
 
 def get_xlim(self):
 'Get the x axis range [xmin, xmax]'
- return self.viewLim.intervalx().get_bounds()
+ return self.viewLim.intervalx
 
 
 def set_xlim(self, xmin=None, xmax=None, emit=True, **kwargs):
@@ -1549,12 +1547,10 @@
 # and min(xmin, xmax)<=0):
 # raise ValueError('Cannot set nonpositive limits with log transform')
 
- xmin, xmax = mbbox.nonsingular(xmin, xmax, increasing=False)
+ xmin, xmax = maffine.nonsingular(xmin, xmax, increasing=False)
 
-	# MGDTODO: This is fairly cumbersome
-	# MGDTODO: side-effects on x-bounds should propagate
-	self.viewLim = mbbox.Bbox.from_lbrt(xmin, self.viewLim.ymin(), xmax, self.viewLim.ymax())
-	print 'set_xlim', self.viewLim
+	self.viewLim.intervalx = (xmin, xmax)
+	print 'set_xlim', self.viewLim, xmin, xmax
 	
 return xmin, xmax
 
@@ -1634,7 +1630,7 @@
 
 def get_ylim(self):
 'Get the y axis range [ymin, ymax]'
- return self.viewLim.intervaly().get_bounds()
+ return self.viewLim.intervaly
 
 def set_ylim(self, ymin=None, ymax=None, emit=True, **kwargs):
 """
@@ -1677,9 +1673,8 @@
 # and min(ymin, ymax)<=0):
 # raise ValueError('Cannot set nonpositive limits with log transform')
 
- ymin, ymax = mbbox.nonsingular(ymin, ymax, increasing=False)
-	# MGDTODO: side-effects on y-bounds should propagate
-	self.viewLim = mbbox.Bbox.from_lbrt(self.viewLim.xmin(), ymin, self.viewLim.xmax(), ymax)
+ ymin, ymax = maffine.nonsingular(ymin, ymax, increasing=False)
+	self.viewLim.intervaly = (ymin, ymax)
 if emit: self.callbacks.process('ylim_changed', self)
 	print "set_ylim", self.viewLim
 	
Modified: branches/transforms/lib/matplotlib/axis.py
===================================================================
--- branches/transforms/lib/matplotlib/axis.py	2007年09月12日 07:04:38 UTC (rev 3834)
+++ branches/transforms/lib/matplotlib/axis.py	2007年09月12日 13:36:25 UTC (rev 3835)
@@ -15,8 +15,8 @@
 from ticker import NullFormatter, FixedFormatter, ScalarFormatter, LogFormatter
 from ticker import NullLocator, FixedLocator, LinearLocator, LogLocator, AutoLocator
 
-from affine import Affine2D, blend_xy_sep_transform
-from bbox import bbox_union
+from affine import Affine2D, Bbox, blend_xy_sep_transform, interval_contains, \
+ interval_contains_open
 from font_manager import FontProperties
 from text import Text, TextWithDash, _process_text_args
 from patches import bbox_artist
@@ -160,7 +160,7 @@
 def draw(self, renderer):
 if not self.get_visible(): return
 renderer.open_group(self.__name__)
- midPoint = self.get_view_interval().contains_open( self.get_loc() )
+ midPoint = interval_contains_open(self.get_view_interval(), self.get_loc() )
 
 if midPoint:
 if self.gridOn: self.gridline.draw(renderer)
@@ -239,7 +239,7 @@
 	trans = blend_xy_sep_transform(
 	 self.axes.transData, self.axes.transAxes)
 #offset the text downward with a post transformation
-	trans = trans + Affine2D().translated(0, -1 * self._padPixels)
+	trans = trans + Affine2D().translate(0, -1 * self._padPixels)
 t.set_transform(trans)
 
 self._set_artist_props(t)
@@ -264,7 +264,7 @@
 	trans = blend_xy_sep_transform(
 	 self.axes.transData, self.axes.transAxes)
 # offset the text upward with a post transformation
- trans = trans + Affine2D().translated(0, self._padPixels)
+ trans = trans + Affine2D().translate(0, self._padPixels)
 t.set_transform( trans )
 self._set_artist_props(t)
 return t
@@ -331,11 +331,11 @@
 
 def get_view_interval(self):
 'return the Interval instance for this axis view limits'
- return self.axes.viewLim.intervalx()
+ return self.axes.viewLim.intervalx
 
 def get_data_interval(self):
 'return the Interval instance for this axis data limits'
- return self.axes.dataLim.intervalx()
+ return self.axes.dataLim.intervalx
 
 
 class YTick(Tick):
@@ -362,7 +362,7 @@
 trans = blend_xy_sep_transform(
 	 self.axes.transAxes, self.axes.transData)
 # offset the text leftward with a post transformation
-	trans = trans + Affine2D().translated(-1 * self._padPixels, 0)
+	trans = trans + Affine2D().translate(-1 * self._padPixels, 0)
 
 t.set_transform( trans )
 #t.set_transform( self.axes.transData )
@@ -385,7 +385,7 @@
 trans = blend_xy_sep_transform(
 	 self.axes.transAxes, self.axes.transData)
 # offset the text rightward with a post transformation
-	trans = trans + Affine2D().translated(self._padPixels, 0)
+	trans = trans + Affine2D().translate(self._padPixels, 0)
 t.set_transform( trans )
 self._set_artist_props(t)
 return t
@@ -455,11 +455,11 @@
 
 def get_view_interval(self):
 'return the Interval instance for this axis view limits'
- return self.axes.viewLim.intervaly()
+ return self.axes.viewLim.intervaly
 
 def get_data_interval(self):
 'return the Interval instance for this axis data limits'
- return self.axes.dataLim.intervaly()
+ return self.axes.dataLim.intervaly
 
 
 class Ticker:
@@ -575,7 +575,7 @@
 interval = self.get_view_interval()
 for tick, loc, label in zip(majorTicks, majorLocs, majorLabels):
 if tick is None: continue
- if not interval.contains(loc): continue
+ if not interval_contains(interval, loc): continue
 seen[loc] = 1
 tick.update_position(loc)
 tick.set_label1(label)
@@ -1034,19 +1034,19 @@
 bottom = self.axes.bbox.ymin()
 else:
 
- bbox = bbox_union(bboxes)
- bottom = bbox.ymin()
+ bbox = Bbox.union(bboxes)
+ bottom = bbox.ymin
 
 self.label.set_position( (x, bottom-self.LABELPAD*self.figure.dpi/72.0))
 # self.label.set_position( (x, bottom-self.LABELPAD*self.figure.dpi.get()/72.0)) MGDTODO
 
 else:
 if not len(bboxes2):
- top = self.axes.bbox.ymax()
+ top = self.axes.bbox.ymax
 else:
 
 bbox = bbox_union(bboxes2)
- top = bbox.ymax()
+ top = bbox.ymax
 
 self.label.set_position( (x, top+self.LABELPAD*self.figure.dpi.get()/72.0))
 
@@ -1059,8 +1059,8 @@
 if not len(bboxes):
 bottom = self.axes.bbox.ymin()
 else:
- bbox = bbox_union(bboxes)
- bottom = bbox.ymin()
+ bbox = Bbox.union(bboxes)
+ bottom = bbox.ymin
 self.offsetText.set_position((x, bottom-self.OFFSETTEXTPAD*self.figure.dpi/72.0))
 # self.offsetText.set_position((x, bottom-self.OFFSETTEXTPAD*self.figure.dpi.get()/72.0)) MGDTODO
 	
@@ -1133,11 +1133,11 @@
 
 def get_view_interval(self):
 'return the Interval instance for this axis view limits'
- return self.axes.viewLim.intervalx()
+ return self.axes.viewLim.intervalx
 
 def get_data_interval(self):
 'return the Interval instance for this axis data limits'
- return self.axes.dataLim.intervalx()
+ return self.axes.dataLim.intervalx
 
 
 class YAxis(Axis):
@@ -1223,11 +1223,11 @@
 x,y = self.label.get_position()
 if self.label_position == 'left':
 if not len(bboxes):
- left = self.axes.bbox.xmin()
+ left = self.axes.bbox.xmin
 else:
 
- bbox = bbox_union(bboxes)
- left = bbox.xmin()
+ bbox = Bbox.union(bboxes)
+ left = bbox.xmin
 
 self.label.set_position( (left-self.LABELPAD*self.figure.dpi/72.0, y))
 	 # self.label.set_position( (left-self.LABELPAD*self.figure.dpi.get()/72.0, y)) MGDTODO
@@ -1248,7 +1248,7 @@
 boxes of all the ticklabels
 """
 x,y = self.offsetText.get_position()
- top = self.axes.bbox.ymax()
+ top = self.axes.bbox.ymax
 self.offsetText.set_position((x, top+self.OFFSETTEXTPAD*self.figure.dpi/72.0))
 # self.offsetText.set_position((x, top+self.OFFSETTEXTPAD*self.figure.dpi.get()/72.0)) MGDTODO
 	
@@ -1335,11 +1335,11 @@
 
 def get_view_interval(self):
 'return the Interval instance for this axis view limits'
- return self.axes.viewLim.intervaly()
+ return self.axes.viewLim.intervaly
 
 def get_data_interval(self):
 'return the Interval instance for this axis data limits'
- return self.axes.dataLim.intervaly()
+ return self.axes.dataLim.intervaly
 
 
 
Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py
===================================================================
--- branches/transforms/lib/matplotlib/backends/backend_agg.py	2007年09月12日 07:04:38 UTC (rev 3834)
+++ branches/transforms/lib/matplotlib/backends/backend_agg.py	2007年09月12日 13:36:25 UTC (rev 3835)
@@ -84,7 +84,7 @@
 from matplotlib.font_manager import findfont
 from matplotlib.ft2font import FT2Font, LOAD_DEFAULT
 from matplotlib.mathtext import MathTextParser
-from matplotlib.bbox import Bbox
+from matplotlib.affine import Bbox
 
 from _backend_agg import RendererAgg as _RendererAgg
 
Modified: branches/transforms/lib/matplotlib/backends/backend_tkagg.py
===================================================================
--- branches/transforms/lib/matplotlib/backends/backend_tkagg.py	2007年09月12日 07:04:38 UTC (rev 3834)
+++ branches/transforms/lib/matplotlib/backends/backend_tkagg.py	2007年09月12日 13:36:25 UTC (rev 3835)
@@ -219,13 +219,13 @@
 def motion_notify_event(self, event):
 x = event.x
 # flipy so y=0 is bottom of canvas
- y = self.figure.bbox.height() - event.y
+ y = self.figure.bbox.height - event.y
 FigureCanvasBase.motion_notify_event(self, x, y, guiEvent=event)
 
 def button_press_event(self, event):
 x = event.x
 # flipy so y=0 is bottom of canvas
- y = self.figure.bbox.height() - event.y
+ y = self.figure.bbox.height - event.y
 num = getattr(event, 'num', None)
 
 if sys.platform=='darwin':
@@ -239,7 +239,7 @@
 def button_release_event(self, event):
 x = event.x
 # flipy so y=0 is bottom of canvas
- y = self.figure.bbox.height() - event.y
+ y = self.figure.bbox.height - event.y
 
 num = getattr(event, 'num', None)
 
@@ -609,7 +609,7 @@
 return b
 
 def _init_toolbar(self):
- xmin, xmax = self.canvas.figure.bbox.intervalx().get_bounds()
+ xmin, xmax = self.canvas.figure.bbox.intervalx
 height, width = 50, xmax-xmin
 Tk.Frame.__init__(self, master=self.window,
 width=width, height=height,
Deleted: branches/transforms/lib/matplotlib/bbox.py
===================================================================
--- branches/transforms/lib/matplotlib/bbox.py	2007年09月12日 07:04:38 UTC (rev 3834)
+++ branches/transforms/lib/matplotlib/bbox.py	2007年09月12日 13:36:25 UTC (rev 3835)
@@ -1,161 +0,0 @@
-"""
-A convenience class for handling bounding boxes
-
-2007 Michael Droettboom
-"""
-
-import numpy as N
-
-class Interval:
- def __init__(self, bounds):
-	self._bounds = N.array(bounds, N.float_)
-
- def contains(self, value):
-	bounds = self._bounds
-	return value >= bounds[0] and value <= bounds[1]
-
- def contains_open(self, value):
-	bounds = self._bounds
-	return value > bounds[0] and value < bounds[1]
-
- def get_bounds(self):
-	return self._bounds
-
- def span(self):
-	bounds = self._bounds
-	return bounds[1] - bounds[0]
-	
-class Bbox:
- def __init__(self, points):
-	self._points = N.array(points, N.float_)
-
- #@staticmethod
- def unit():
-	return Bbox([[0,0], [1,1]])
- unit = staticmethod(unit)
-
- #@staticmethod
- def from_lbwh(left, bottom, width, height):
-	return Bbox([[left, bottom], [left + width, bottom + height]])
- from_lbwh = staticmethod(from_lbwh)
-
- #@staticmethod
- def from_lbrt(left, bottom, right, top):
-	return Bbox([[left, bottom], [right, top]])
- from_lbrt = staticmethod(from_lbrt)
-
- #@staticmethod
- def from_data(x, y):
-	return Bbox([[x.min(), y.min()], [x.max(), y.max()]])
- from_data = staticmethod(from_data)
- 
- def copy(self):
-	return Bbox(self._points.copy())
-
- def __repr__(self):
-	return 'Bbox(%s)' % repr(self._points)
- __str__ = __repr__
-
- def __cmp__(self, other):
-	# MGDTODO: Totally suboptimal
-	if isinstance(other, Bbox):
-	 return (self._points == other._points).all()
-	return -1
- 
- # MGDTODO: Probably a more efficient ways to do this...
- def xmin(self):
-	return self._points[0,0]
-
- def ymin(self):
-	return self._points[0,1]
-
- def xmax(self):
-	return self._points[1,0]
- 
- def ymax(self):
-	return self._points[1,1]
-
- def width(self):
-	return self.xmax() - self.xmin()
-
- def height(self):
-	return self.ymax() - self.ymin()
-
- def transform(self, transform):
-	return Bbox(transform(self._points))
-
- def inverse_transform(self, transform):
-	return Bbox(transform.inverted()(self._points))
-
- def get_bounds(self):
-	return (self.xmin(), self.ymin(),
-		self.xmax() - self.xmin(), self.ymax() - self.ymin())
-
- # MGDTODO: This is an inefficient way to do this
- def intervalx(self):
-	return Interval(self._points[0])
-
- def intervaly(self):
-	return Interval(self._points[1])
-
- def scaled(self, sw, sh):
-	width = self.width()
-	height = self.height()
-	deltaw = (sw * width - width) / 2.0
-	deltah = (sh * height - height) / 2.0
-	a = N.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())
-
-def bbox_union(bboxes):
- """
- Return the Bbox that bounds all bboxes
- """
- assert(len(bboxes))
-
- if len(bboxes) == 1:
-	return bboxes[0]
-
- 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())
-
- return Bbox.from_lbrt(xmin, ymin, xmax, ymax)
-
-# MGDTODO: There's probably a better place for this
-def nonsingular(vmin, vmax, expander=0.001, tiny=1e-15, increasing=True):
- '''
- Ensure the endpoints of a range are not too close together.
-
- "too close" means the interval is smaller than 'tiny' times
- the maximum absolute value.
-
- If they are too close, each will be moved by the 'expander'.
- If 'increasing' is True and vmin > vmax, they will be swapped,
- regardless of whether they are too close.
- '''
- swapped = False
- if vmax < vmin:
- vmin, vmax = vmax, vmin
- swapped = True
- if vmax - vmin <= max(abs(vmin), abs(vmax)) * tiny:
- if vmin==0.0:
- vmin = -expander
- vmax = expander
- else:
- vmin -= expander*abs(vmin)
- vmax += expander*abs(vmax)
- if swapped and not increasing:
- vmin, vmax = vmax, vmin
- return vmin, vmax
Modified: branches/transforms/lib/matplotlib/figure.py
===================================================================
--- branches/transforms/lib/matplotlib/figure.py	2007年09月12日 07:04:38 UTC (rev 3834)
+++ branches/transforms/lib/matplotlib/figure.py	2007年09月12日 13:36:25 UTC (rev 3835)
@@ -18,8 +18,7 @@
 from text import Text, _process_text_args
 
 from legend import Legend
-from affine import get_bbox_transform
-from bbox import Bbox
+from affine import Bbox, BboxTransform
 from ticker import FormatStrFormatter
 from cm import ScalarMappable
 from contour import ContourSet
@@ -105,7 +104,7 @@
 class Figure(Artist):
 
 def __str__(self):
- return "Figure(%gx%g)"%(self.figwidth, self.figheight)
+ return "Figure(%gx%g)"%(self.bbox.max)
 # return "Figure(%gx%g)"%(self.figwidth.get(),self.figheight.get())
 
 def __init__(self,
@@ -130,13 +129,13 @@
 if edgecolor is None: edgecolor = rcParams['figure.edgecolor']
 
 self.dpi = dpi
-	self.figwidth = figsize[0] * dpi
-	self.figheight = figsize[1] * dpi
-	self.bbox = Bbox.from_lbwh(0, 0, self.figwidth, self.figheight)
+	figwidth = figsize[0] * dpi
+	figheight = figsize[1] * dpi
+	self.bbox = Bbox.from_lbwh(0, 0, figwidth, figheight)
 	
 self.frameon = frameon
 
- self.transFigure = get_bbox_transform( Bbox.unit(), self.bbox)
+ self.transFigure = BboxTransform( Bbox.unit(), self.bbox)
 
 
 
@@ -325,9 +324,9 @@
 else:
 w,h = args
 
-	
- self.figwidth = w
- self.figheight = h
+	dpival = self.dpi
+	self.bbox.max = w * dpival, h * dpival
+	print self.bbox
 # self.figwidth.set(w) MGDTODO
 # self.figheight.set(h)
 	
@@ -341,7 +340,7 @@
 manager.resize(int(canvasw), int(canvash))
 
 def get_size_inches(self):
- return self.figwidth, self.figheight
+ return self.bbox.max
 # return self.figwidth.get(), self.figheight.get() MGDTODO
 
 def get_edgecolor(self):
@@ -354,12 +353,12 @@
 
 def get_figwidth(self):
 'Return the figwidth as a float'
-	return self.figwidth
+	return self.bbox.xmax
 # return self.figwidth.get() MGDTODO
 
 def get_figheight(self):
 'Return the figheight as a float'
- return self.figheight.get()
+ return self.bbox.ymax
 
 def get_dpi(self):
 'Return the dpi as a float'
@@ -402,7 +401,7 @@
 ACCEPTS: float
 """
 # self.figwidth.set(val) MGDTODO
- self.figwidth = val
+	self.bbox.xmax = val
 	
 def set_figheight(self, val):
 """
@@ -411,7 +410,7 @@
 ACCEPTS: float
 """
 	# MGDTODO (set())
- self.figheight = val
+	self.bbox.ymax = val
 
 def set_frameon(self, b):
 """
Modified: branches/transforms/lib/matplotlib/legend.py
===================================================================
--- branches/transforms/lib/matplotlib/legend.py	2007年09月12日 07:04:38 UTC (rev 3834)
+++ branches/transforms/lib/matplotlib/legend.py	2007年09月12日 13:36:25 UTC (rev 3835)
@@ -34,8 +34,7 @@
 from patches import Patch, Rectangle, RegularPolygon, Shadow, bbox_artist, draw_bbox
 from collections import LineCollection, RegularPolyCollection, PatchCollection
 from text import Text
-from affine import get_bbox_transform
-from bbox import Bbox, bbox_union
+from affine import Bbox, BboxTransform
 
 def line_cuts_bbox(line, bbox):
 """ Return True if and only if line cuts bbox. """
@@ -165,7 +164,7 @@
 else:
 raise TypeError("Legend needs either Axes or Figure as parent")
 self.parent = parent
- self.set_transform( get_bbox_transform( Bbox.unit(), parent.bbox) )
+ self.set_transform( BboxTransform( Bbox.unit(), parent.bbox) )
 
 if loc is None:
 loc = rcParams["legend.loc"]
@@ -260,10 +259,10 @@
 
 bboxesAll = bboxesText
 bboxesAll.extend(bboxesHandles)
- bbox = bbox_union(bboxesAll)
+ bbox = Bbox.union(bboxesAll)
 self.save = bbox
 
- ibox = bbox.inverse_transform(self.get_transform())
+ ibox = bbox.inverse_transformed(self.get_transform())
 self.ibox = ibox
 
 return ibox
@@ -531,7 +530,7 @@
 if not len(self.legendHandles) and not len(self.texts): return
 def get_tbounds(text): #get text bounds in axes coords
 bbox = text.get_window_extent(renderer)
- bboxa = bbox.inverse_transform(self.get_transform())
+ bboxa = bbox.inverse_transformed(self.get_transform())
 return bboxa.get_bounds()
 
 hpos = []
Modified: branches/transforms/lib/matplotlib/lines.py
===================================================================
--- branches/transforms/lib/matplotlib/lines.py	2007年09月12日 07:04:38 UTC (rev 3834)
+++ branches/transforms/lib/matplotlib/lines.py	2007年09月12日 13:36:25 UTC (rev 3835)
@@ -14,11 +14,11 @@
 import numerix.ma as ma
 from matplotlib import verbose
 import artist
+from affine import Bbox
 from artist import Artist, setp
 from cbook import iterable, is_string_like, is_numlike
 from colors import colorConverter
 
-from bbox import Bbox
 from matplotlib import rcParams
 
 # special-purpose marker identifiers:
Modified: branches/transforms/lib/matplotlib/table.py
===================================================================
--- branches/transforms/lib/matplotlib/table.py	2007年09月12日 07:04:38 UTC (rev 3834)
+++ branches/transforms/lib/matplotlib/table.py	2007年09月12日 13:36:25 UTC (rev 3835)
@@ -29,7 +29,7 @@
 from patches import Rectangle
 from cbook import enumerate, is_string_like, flatten
 from text import Text
-from bbox import Bbox, bbox_union
+from affine import Bbox
 
 
 
@@ -130,7 +130,7 @@
 def get_text_bounds(self, renderer):
 """ Get text bounds in axes co-ordinates. """
 bbox = self._text.get_window_extent(renderer)
-	bbox.inverse_transform(self.get_transform())
+	bboxa = bbox.inverse_transformed(self.get_transform())
 return bboxa.get_bounds()
 
 def get_required_width(self, renderer):
Modified: branches/transforms/lib/matplotlib/text.py
===================================================================
--- branches/transforms/lib/matplotlib/text.py	2007年09月12日 07:04:38 UTC (rev 3834)
+++ branches/transforms/lib/matplotlib/text.py	2007年09月12日 13:36:25 UTC (rev 3835)
@@ -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 bbox import Bbox, bbox_union
+from affine import Bbox
 from lines import Line2D
 
 import matplotlib.nxutils as nxutils
Modified: branches/transforms/lib/matplotlib/ticker.py
===================================================================
--- branches/transforms/lib/matplotlib/ticker.py	2007年09月12日 07:04:38 UTC (rev 3834)
+++ branches/transforms/lib/matplotlib/ticker.py	2007年09月12日 13:36:25 UTC (rev 3835)
@@ -115,7 +115,7 @@
 import matplotlib as mpl
 from matplotlib import verbose, rcParams
 from matplotlib import cbook
-from matplotlib import bbox as mbbox
+from matplotlib import affine as maffine
 
 
 
@@ -148,8 +148,9 @@
 cases where the Intervals do not need to be updated
 automatically.
 '''
- self.dataInterval = mbbox.Interval([vmin, vmax])
- self.viewInterval = mbbox.Interval([vmin, vmax])
+	# MGDTODO: Interval no longer exists
+ self.dataInterval = maffine.Interval([vmin, vmax])
+ self.viewInterval = maffine.Interval([vmin, vmax])
 
 class Formatter(TickHelper):
 """
@@ -341,7 +342,8 @@
 self.locs = locs
 if len(self.locs) > 0:
 self.verify_intervals()
- d = abs(self.viewInterval.span())
+	 vmin, vmax = self.viewInterval
+ d = abs(vmax - vmin)
 if self._useOffset: self._set_offset(d)
 self._set_orderOfMagnitude(d)
 self._set_format()
@@ -571,7 +573,7 @@
 def autoscale(self):
 'autoscale the view limits'
 self.verify_intervals()
- return mbbox.nonsingular(*self.dataInterval.get_bounds())
+ return maffine.nonsingular(*self.dataInterval.get_bounds())
 
 def pan(self, numsteps):
 'Pan numticks (can be positive or negative)'
@@ -713,7 +715,7 @@
 vmin = math.floor(scale*vmin)/scale
 vmax = math.ceil(scale*vmax)/scale
 
- return mbbox.nonsingular(vmin, vmax)
+ return maffine.nonsingular(vmin, vmax)
 
 
 def closeto(x,y):
@@ -797,7 +799,7 @@
 vmin -=1
 vmax +=1
 
- return mbbox.nonsingular(vmin, vmax)
+ return maffine.nonsingular(vmin, vmax)
 
 def scale_range(vmin, vmax, n = 1, threshold=100):
 dv = abs(vmax - vmin)
@@ -864,14 +866,14 @@
 
 def __call__(self):
 self.verify_intervals()
- vmin, vmax = self.viewInterval.get_bounds()
- vmin, vmax = mbbox.nonsingular(vmin, vmax, expander = 0.05)
+ vmin, vmax = self.viewInterval
+ vmin, vmax = maffine.nonsingular(vmin, vmax, expander = 0.05)
 return self.bin_boundaries(vmin, vmax)
 
 def autoscale(self):
 self.verify_intervals()
- dmin, dmax = self.dataInterval.get_bounds()
- dmin, dmax = mbbox.nonsingular(dmin, dmax, expander = 0.05)
+ dmin, dmax = self.dataInterval
+ dmin, dmax = maffine.nonsingular(dmin, dmax, expander = 0.05)
 return npy.take(self.bin_boundaries(dmin, dmax), [0,-1])
 
 
@@ -972,7 +974,7 @@
 if vmin==vmax:
 vmin = decade_down(vmin,self._base)
 vmax = decade_up(vmax,self._base)
- return mbbox.nonsingular(vmin, vmax)
+ return maffine.nonsingular(vmin, vmax)
 
 class AutoLocator(MaxNLocator):
 def __init__(self):
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <jd...@us...> - 2007年09月12日 15:41:28
Revision: 3838
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3838&view=rev
Author: jdh2358
Date: 2007年09月12日 08:41:22 -0700 (2007年9月12日)
Log Message:
-----------
removed Interval from canonical tickers and formatters
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/affine.py
 branches/transforms/lib/matplotlib/axis.py
 branches/transforms/lib/matplotlib/ticker.py
Modified: branches/transforms/lib/matplotlib/affine.py
===================================================================
--- branches/transforms/lib/matplotlib/affine.py	2007年09月12日 14:46:03 UTC (rev 3837)
+++ branches/transforms/lib/matplotlib/affine.py	2007年09月12日 15:41:22 UTC (rev 3838)
@@ -33,6 +33,9 @@
 	self._points = N.asarray(points, N.float_)
 	self.track = False
 
+ # JDH: if you define a del method, the garbage collector won't
+ # destory cyclic references, so make sure you either manage these
+ # yourself or remove the __del__ after testing
 def __del__(self):
 	if self.track:
 	 print "Bbox::__del__"
@@ -52,6 +55,11 @@
 	return Bbox([[left, bottom], [right, top]])
 from_lbrt = staticmethod(from_lbrt)
 
+
+ # 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):
 	self._points = N.array([[x.min(), y.min()], [x.max(), y.max()]], N.float_)
 	self.invalidate()
Modified: branches/transforms/lib/matplotlib/axis.py
===================================================================
--- branches/transforms/lib/matplotlib/axis.py	2007年09月12日 14:46:03 UTC (rev 3837)
+++ branches/transforms/lib/matplotlib/axis.py	2007年09月12日 15:41:22 UTC (rev 3838)
@@ -855,9 +855,9 @@
 ACCEPTS: A Formatter instance
 """
 self.major.formatter = formatter
- self.major.formatter.set_view_interval( self.get_view_interval() )
- self.major.formatter.set_data_interval( self.get_data_interval() )
+ self.major.formatter.set_axis(self)
 
+
 def set_minor_formatter(self, formatter):
 """
 Set the formatter of the minor ticker
@@ -865,8 +865,7 @@
 ACCEPTS: A Formatter instance
 """
 self.minor.formatter = formatter
- self.minor.formatter.set_view_interval( self.get_view_interval() )
- self.minor.formatter.set_data_interval( self.get_data_interval() )
+ self.minor.formatter.set_axis(self)
 
 
 def set_major_locator(self, locator):
@@ -876,8 +875,7 @@
 ACCEPTS: a Locator instance
 """
 self.major.locator = locator
- self.major.locator.set_view_interval( self.get_view_interval() )
- self.major.locator.set_data_interval( self.get_data_interval() )
+ self.major.locator.set_axis(self)
 
 
 def set_minor_locator(self, locator):
@@ -887,8 +885,7 @@
 ACCEPTS: a Locator instance
 """
 self.minor.locator = locator
- self.minor.locator.set_view_interval( self.get_view_interval() )
- self.minor.locator.set_data_interval( self.get_data_interval() )
+ self.minor.locator.set_axis(self)
 
 def set_pickradius(self, pickradius):
 """
Modified: branches/transforms/lib/matplotlib/ticker.py
===================================================================
--- branches/transforms/lib/matplotlib/ticker.py	2007年09月12日 14:46:03 UTC (rev 3837)
+++ branches/transforms/lib/matplotlib/ticker.py	2007年09月12日 15:41:22 UTC (rev 3838)
@@ -99,13 +99,7 @@
 minor ticks. See the matplotlib.dates module for more information and
 examples of using date locators and formatters.
 
-DEVELOPERS NOTE
 
-If you are implementing your own class or modifying one of these, it
-is critical that you use viewlim and dataInterval READ ONLY MODE so
-multiple axes can share the same locator w/o side effects!
-
-
 """
 
 
@@ -121,37 +115,11 @@
 
 
 class TickHelper:
+ axis = None
+ def set_axis(self, axis):
+ self.axis = axis
 
- viewInterval = None
- dataInterval = None
 
- def verify_intervals(self):
- if self.dataInterval is None:
- raise RuntimeError("You must set the data interval to use this function")
-
- if self.viewInterval is None:
- raise RuntimeError("You must set the view interval to use this function")
-
-
- def set_view_interval(self, interval):
- self.viewInterval = interval
-
- def set_data_interval(self, interval):
- self.dataInterval = interval
-
- def set_bounds(self, vmin, vmax):
- '''
- Set dataInterval and viewInterval from numeric vmin, vmax.
-
- This is for stand-alone use of Formatters and/or
- Locators that require these intervals; that is, for
- cases where the Intervals do not need to be updated
- automatically.
- '''
-	# MGDTODO: Interval no longer exists
- self.dataInterval = maffine.Interval([vmin, vmax])
- self.viewInterval = maffine.Interval([vmin, vmax])
-
 class Formatter(TickHelper):
 """
 Convert the tick location to a string
@@ -341,9 +309,8 @@
 'set the locations of the ticks'
 self.locs = locs
 if len(self.locs) > 0:
- self.verify_intervals()
-	 vmin, vmax = self.viewInterval
- d = abs(vmax - vmin)
+ vmin, vmax = self.axis.get_view_interval()
+ d = abs(vmax-vmin)
 if self._useOffset: self._set_offset(d)
 self._set_orderOfMagnitude(d)
 self._set_format()
@@ -865,14 +832,12 @@
 
 
 def __call__(self):
- self.verify_intervals()
- vmin, vmax = self.viewInterval
+ vmin, vmax = self.axis.get_view_interval()
 vmin, vmax = maffine.nonsingular(vmin, vmax, expander = 0.05)
 return self.bin_boundaries(vmin, vmax)
 
 def autoscale(self):
- self.verify_intervals()
- dmin, dmax = self.dataInterval
+ dmin, dmax = self.axis.get_data_interval()
 dmin, dmax = maffine.nonsingular(dmin, dmax, expander = 0.05)
 return npy.take(self.bin_boundaries(dmin, dmax), [0,-1])
 
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2007年09月12日 17:25:26
Revision: 3839
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3839&view=rev
Author: mdboom
Date: 2007年09月12日 10:25:19 -0700 (2007年9月12日)
Log Message:
-----------
Milestone -- simple_plot.py working with new affine framework (with
the exception of dpi propagation)
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/affine.py
 branches/transforms/lib/matplotlib/axes.py
 branches/transforms/lib/matplotlib/figure.py
 branches/transforms/lib/matplotlib/lines.py
Modified: branches/transforms/lib/matplotlib/affine.py
===================================================================
--- branches/transforms/lib/matplotlib/affine.py	2007年09月12日 15:41:22 UTC (rev 3838)
+++ branches/transforms/lib/matplotlib/affine.py	2007年09月12日 17:25:19 UTC (rev 3839)
@@ -33,29 +33,29 @@
 	self._points = N.asarray(points, N.float_)
 	self.track = False
 
- # JDH: if you define a del method, the garbage collector won't
- # destory cyclic references, so make sure you either manage these
- # yourself or remove the __del__ after testing
- def __del__(self):
-	if self.track:
-	 print "Bbox::__del__"
-	
 #@staticmethod
 def unit():
-	return Bbox([[0,0], [1,1]])
+	return Bbox.from_lbrt(0., 0., 1., 1.)
 unit = staticmethod(unit)
 
 #@staticmethod
 def from_lbwh(left, bottom, width, height):
-	return Bbox([[left, bottom], [left + width, bottom + height]])
+	return Bbox.from_lbrt(left, bottom, left + width, bottom + height)
 from_lbwh = staticmethod(from_lbwh)
 
 #@staticmethod
- def from_lbrt(left, bottom, right, top):
-	return Bbox([[left, bottom], [right, top]])
+ def from_lbrt(*args):
+	points = N.array(args, dtype=N.float_).reshape(2, 2)
+	return Bbox(points)
 from_lbrt = staticmethod(from_lbrt)
 
-
+ def __cmp__(self, other):
+	# MGDTODO: Totally suboptimal
+	if isinstance(other, Bbox):
+	 if (self._points == other._points).all():
+		return 0
+	return -1
+ 
 # 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
@@ -63,31 +63,18 @@
 def update_from_data(self, x, y):
 	self._points = N.array([[x.min(), y.min()], [x.max(), y.max()]], N.float_)
 	self.invalidate()
-	if self.track:
-	 print "Bbox::update_from_data", self._points
 
 def copy(self):
-	if self.track:
-	 print "Bbox::copy"
 	return Bbox(self._points.copy())
 
 def __repr__(self):
 	return 'Bbox(%s)' % repr(self._points)
 __str__ = __repr__
 
- def __cmp__(self, other):
-	# MGDTODO: Totally suboptimal
-	if isinstance(other, Bbox):
-	 return (self._points == other._points).all()
-	return -1
- 
 # MGDTODO: Probably a more efficient ways to do this...
 def _get_xmin(self):
-	if self.track:
-	 print "Bbox::_get_xmin"
 	return self._points[0, 0]
 def _set_xmin(self, val):
-	print "Bbox::_set_xmin"
 	self._points[0, 0] = val
 	self.invalidate()
 xmin = property(_get_xmin, _set_xmin)
@@ -150,10 +137,10 @@
 height = property(_get_height)
 
 def transformed(self, transform):
-	return Bbox(self.transform(self._points))
+	return Bbox(transform(self._points))
 
 def inverse_transformed(self, transform):
-	return Bbox(self.transform.inverted()(self._points))
+	return Bbox(transform.inverted()(self._points))
 
 def get_bounds(self):
 	return (self.xmin, self.ymin,
@@ -249,6 +236,14 @@
 	return "Affine2D(%s)" % repr(self._mtx)
 __str__ = __repr__
 
+ def __cmp__(self, other):
+	# MGDTODO: We need to decide if we want deferred transforms
+	# to be equal to this one
+	if isinstance(other, Affine2D):
+	 if (self.get_matrix() == other.get_matrix()).all():
+		return 0
+	return -1
+ 
 def _do_invalidation(self):
 	result = self._inverted is None
 	self._inverted = None
@@ -380,10 +375,9 @@
 	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
 	 self._mtx = N.vstack([x_mtx[0], y_mtx[1], [0.0, 0.0, 1.0]])
-# 	 self._mtx = self.matrix_from_values(
-# 		x_mtx[0,0], 0.0, 0.0, y_mtx[1,1], x_mtx[0,2], y_mtx[1,2])
-	 print "Blended", x_mtx, y_mtx, self._mtx
 	
 def is_separable(self):
 	return True
@@ -429,8 +423,8 @@
 def _make__mtx(self):
 	if self._mtx is None:
 	 self._mtx = self._concat(
-		self._b.get_matrix(),
-		self._a.get_matrix())
+		self._a.get_matrix(),
+		self._b.get_matrix())
 
 def get_matrix(self):
 	self._make__mtx()
@@ -547,12 +541,70 @@
 return interval[0] < val and interval[1] > val
 
 if __name__ == '__main__':
+ bbox = Bbox.from_lbrt(10., 15., 20., 25.)
+ assert bbox.xmin == 10
+ assert bbox.ymin == 15
+ assert bbox.xmax == 20
+ assert bbox.ymax == 25
+
+ assert N.all(bbox.min == [10, 15])
+ assert N.all(bbox.max == [20, 25])
+ assert N.all(bbox.intervalx == (10, 20))
+ assert N.all(bbox.intervaly == (15, 25))
+
+ assert bbox.width == 10
+ assert bbox.height == 10
+
+ assert bbox.get_bounds() == (10, 15, 10, 10)
+
+ bbox.intervalx = (11, 21)
+ bbox.intervaly = (16, 26)
+ 
+ assert bbox.get_bounds() == (11, 16, 10, 10)
+
+ bbox.xmin = 12
+ bbox.ymin = 17
+ bbox.xmax = 22
+ bbox.ymax = 27
+
+ assert bbox.get_bounds() == (12, 17, 10, 10)
+
+ bbox = Bbox.from_lbwh(10, 11, 12, 13)
+ assert bbox.get_bounds() == (10, 11, 12, 13)
+
+ bbox_copy = bbox.copy()
+ assert bbox == bbox_copy
+ bbox_copy.max = (14, 15)
+ assert bbox.get_bounds() == (10, 11, 12, 13)
+ assert bbox_copy.get_bounds() == (10, 11, 4, 4)
+ 
 bbox1 = Bbox([[10., 15.], [20., 25.]])
 bbox2 = Bbox([[30., 35.], [40., 45.]])
 trans = BboxTransform(bbox1, bbox2)
- print trans(bbox1._points)
+ bbox3 = bbox1.transformed(trans)
+ assert bbox3 == bbox2
 
- bbox2.intervalx = 50, 55
- print trans(bbox1._points)
+ translation = Affine2D().translate(10, 20)
+ assert translation.to_values() == (1, 0, 0, 1, 10, 20)
+ scale = Affine2D().scale(10, 20)
+ 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)
 
+ points = N.array([[1,2],[3,4],[5,6],[7,8]], N.float_)
+ translated_points = translation(points)
+ assert (translated_points == [[11., 22.], [13., 24.], [15., 26.], [17., 28.]]).all()
+ scaled_points = scale(points)
+ print scaled_points
+ rotated_points = rotation(points)
+ print rotated_points
+
+ tpoints1 = rotation(translation(scale(points)))
+ trans_sum = rotation + translation + scale
+ tpoints2 = trans_sum(points)
+ print tpoints1, tpoints2
+ print tpoints1 == tpoints2
+ # Need to do some sort of fuzzy comparison here?
+ # assert (tpoints1 == tpoints2).all()
+ 
 __all__ = ['Transform', 'Affine2D']
Modified: branches/transforms/lib/matplotlib/axes.py
===================================================================
--- branches/transforms/lib/matplotlib/axes.py	2007年09月12日 15:41:22 UTC (rev 3838)
+++ branches/transforms/lib/matplotlib/axes.py	2007年09月12日 17:25:19 UTC (rev 3839)
@@ -653,15 +653,12 @@
 
 self.viewLim = Bbox.from_lbrt(left, bottom, right, top)
 	self.dataLim = Bbox.unit()
-	self.dataLim.track = True
 	
 self.transData = maffine.BboxTransform(
 self.viewLim, self.bbox)
 self.transAxes = maffine.BboxTransform(
 Bbox.unit(), self.bbox)
 
-	print "_set_lim_and_transforms", self.viewLim, self.transData, self.dataLim, self.transAxes, self.bbox
-
 	# MGDTODO
 # if self._sharex:
 # self.transData.set_funcx(self._sharex.transData.get_funcx())
@@ -697,7 +694,6 @@
 # # Change values within self._position--don't replace it.
 # for num,val in zip(pos, self._position):
 # val.set(num)
-	 print "set_position", self._position, pos
 	 self._position = pos
 	 # MGDTODO: side-effects
 if which in ('both', 'original'):
@@ -1182,9 +1178,7 @@
 #print type(x), type(y)
 	# MGDTODO
 ## self.dataLim.update_numerix(x, y, -1)
-	print "update_datalim_numerix", self.dataLim,
 	self.dataLim.update_from_data(x, y)
-	print self.dataLim
 
 def _get_verts_in_data_coords(self, trans, xys):
 if trans == self.transData:
@@ -1245,8 +1239,6 @@
 axis direction reversal that has already been done.
 """
 # if image data only just use the datalim
-	print "autoscale_view", self._autoscaleon, scalex, scaley
-	
 if not self._autoscaleon: return
 if (tight or (len(self.images)>0 and
 len(self.lines)==0 and
@@ -1274,7 +1266,7 @@
 
 def draw(self, renderer=None, inframe=False):
 "Draw everything (plot lines, axes, labels)"
- if renderer is None:
+	if renderer is None:
 renderer = self._cachedRenderer
 
 if renderer is None:
@@ -1550,7 +1542,6 @@
 xmin, xmax = maffine.nonsingular(xmin, xmax, increasing=False)
 
 	self.viewLim.intervalx = (xmin, xmax)
-	print 'set_xlim', self.viewLim, xmin, xmax
 	
 return xmin, xmax
 
@@ -1654,7 +1645,6 @@
 ACCEPTS: len(2) sequence of floats
 """
 
-	print "set_ylim", ymin, ymax, emit
 if ymax is None and iterable(ymin):
 ymin,ymax = ymin
 
@@ -1676,7 +1666,6 @@
 ymin, ymax = maffine.nonsingular(ymin, ymax, increasing=False)
 	self.viewLim.intervaly = (ymin, ymax)
 if emit: self.callbacks.process('ylim_changed', self)
-	print "set_ylim", self.viewLim
 	
 return ymin, ymax
 
Modified: branches/transforms/lib/matplotlib/figure.py
===================================================================
--- branches/transforms/lib/matplotlib/figure.py	2007年09月12日 15:41:22 UTC (rev 3838)
+++ branches/transforms/lib/matplotlib/figure.py	2007年09月12日 17:25:19 UTC (rev 3839)
@@ -326,7 +326,6 @@
 
 	dpival = self.dpi
 	self.bbox.max = w * dpival, h * dpival
-	print self.bbox
 # self.figwidth.set(w) MGDTODO
 # self.figheight.set(h)
 	
Modified: branches/transforms/lib/matplotlib/lines.py
===================================================================
--- branches/transforms/lib/matplotlib/lines.py	2007年09月12日 15:41:22 UTC (rev 3838)
+++ branches/transforms/lib/matplotlib/lines.py	2007年09月12日 17:25:19 UTC (rev 3839)
@@ -389,7 +389,6 @@
 
 
 def set_axes(self, ax):
-	print "set_axes"
 Artist.set_axes(self, ax)
 if ax.xaxis is not None:
 self._xcid = ax.xaxis.callbacks.connect('units', self.recache)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2007年09月12日 19:48:00
Revision: 3842
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3842&view=rev
Author: mdboom
Date: 2007年09月12日 12:47:56 -0700 (2007年9月12日)
Log Message:
-----------
More progress. Zooming and panning working thanks to John's patch.
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/affine.py
 branches/transforms/lib/matplotlib/artist.py
 branches/transforms/lib/matplotlib/axes.py
 branches/transforms/lib/matplotlib/backend_bases.py
 branches/transforms/lib/matplotlib/backends/backend_agg.py
 branches/transforms/lib/matplotlib/backends/backend_tkagg.py
Modified: branches/transforms/lib/matplotlib/affine.py
===================================================================
--- branches/transforms/lib/matplotlib/affine.py	2007年09月12日 18:22:24 UTC (rev 3841)
+++ branches/transforms/lib/matplotlib/affine.py	2007年09月12日 19:47:56 UTC (rev 3842)
@@ -8,9 +8,16 @@
 from numpy.linalg import inv
 from sets import Set
 
+# MGDTODO: The name of this module is bad, since it deals with
+# non-affine transformations as well. It should probably just be
+# "transforms", but we already had one of those... ;)
+
 # MGDTODO: This creates a ton of cyclical references. We may want to
 # consider using weak references
 
+# MGDTODO: deep copying is probably incorrect wrt the parent/child
+# relationships
+
 class TransformNode(object):
 def __init__(self):
 	self._parents = Set()
@@ -48,29 +55,31 @@
 	points = N.array(args, dtype=N.float_).reshape(2, 2)
 	return Bbox(points)
 from_lbrt = staticmethod(from_lbrt)
+ 
+ def __copy__(self):
+	return Bbox(self._points.copy())
 
+ def __deepcopy__(self, memo):
+	return Bbox(self._points.copy())
+ 
 def __cmp__(self, other):
 	# MGDTODO: Totally suboptimal
-	if isinstance(other, Bbox):
-	 if (self._points == other._points).all():
-		return 0
+	if isinstance(other, Bbox) and (self._points == other._points).all():
+	 return 0
 	return -1
- 
+
+ def __repr__(self):
+	return 'Bbox(%s)' % repr(self._points)
+ __str__ = __repr__
+
 # 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):
+ def update_from_data(self, x, y, ignore=True):
 	self._points = N.array([[x.min(), y.min()], [x.max(), y.max()]], N.float_)
 	self.invalidate()
- 
- def copy(self):
-	return Bbox(self._points.copy())
 
- def __repr__(self):
-	return 'Bbox(%s)' % repr(self._points)
- __str__ = __repr__
-
 # MGDTODO: Probably a more efficient ways to do this...
 def _get_xmin(self):
 	return self._points[0, 0]
@@ -136,19 +145,24 @@
 	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)
+ def _set_bounds(self, bounds):
+	l,b,w,h = bounds
+	self._points = N.array([[l, b], [l+w, b+h]], N.float_)
+	self.invalidate()
+ bounds = property(_get_bounds, _set_bounds)
+	
 def transformed(self, transform):
 	return Bbox(transform(self._points))
 
 def inverse_transformed(self, transform):
 	return Bbox(transform.inverted()(self._points))
 
- def get_bounds(self):
-	return (self.xmin, self.ymin,
-		self.xmax - self.xmin, self.ymax - self.ymin)
-
 def expanded(self, sw, sh):
-	width = self.width()
-	height = self.height()
+	width = self.width
+	height = self.height
 	deltaw = (sw * width - width) / 2.0
 	deltah = (sh * height - height) / 2.0
 	a = N.array([[-deltaw, -deltah], [deltaw, deltah]])
@@ -199,6 +213,9 @@
 	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__([point])[0]
 
 def has_inverse(self):
 	raise NotImplementedError()
@@ -211,49 +228,27 @@
 
 def is_affine(self):
 	return False
-	
-class Affine2D(Transform):
+
+# MGDTODO: Separate out Affine2DBase / Affine2DConcrete so BlendedAffine and CompositeAffine don't have translate/scale/rotate members
+
+class Affine2DBase(Transform):
 input_dims = 2
 output_dims = 2
- 
- def __init__(self, matrix = None):
- """
- Initialize an Affine transform from a 3x3 numpy float array.
 
- a c e
- b d f
- 0 0 1
- """
+ def __init__(self):
 	Transform.__init__(self)
-	if matrix is None:
-	 matrix = N.identity(3)
-	else:
-	 assert matrix.shape == (3, 3)
-	self._mtx = matrix
 	self._inverted = None
 
- def __repr__(self):
-	return "Affine2D(%s)" % repr(self._mtx)
- __str__ = __repr__
-
- def __cmp__(self, other):
-	# MGDTODO: We need to decide if we want deferred transforms
-	# to be equal to this one
-	if isinstance(other, Affine2D):
-	 if (self.get_matrix() == other.get_matrix()).all():
-		return 0
-	return -1
- 
 def _do_invalidation(self):
 	result = self._inverted is None
 	self._inverted = None
 	return result
+
+ #@staticmethod
+ def _concat(a, b):
+ return N.dot(b, a)
+ _concat = staticmethod(_concat)
 
- #@staticmethod
- def from_values(a, b, c, d, e, f):
- return Affine2D(Affine2D.matrix_from_values(a, b, c, d, e, f))
- from_values = staticmethod(from_values)
-
 def to_values(self):
 	mtx = self.get_matrix()
 	return tuple(mtx[:2].swapaxes(0, 1).flatten())
@@ -268,7 +263,7 @@
 matrix_from_values = staticmethod(matrix_from_values)
 
 def get_matrix(self):
-	return self._mtx
+	raise NotImplementedError()
 
 def __call__(self, points):
 """
@@ -278,26 +273,74 @@
 	points must be a numpy array of shape (N, 2), where N is the
 	number of points.
 	"""
-	# MGDTODO: This involves a copy. We may need to do something like
-	# http://neuroimaging.scipy.org/svn/ni/ni/trunk/neuroimaging/core/reference/mapping.py
-	# to separate the matrix out into the translation and scale components
-	# and apply each separately (which is still sub-optimal)
-
-	# This is easier for now, however, since we can just keep a
-	# regular affine matrix around
-	# MGDTODO: Trap cases where this isn't an array and fix there
+	# 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 = N.asarray(points, N.float_)
-	new_points = points.swapaxes(0, 1)
-	new_points = N.vstack((new_points, N.ones((1, points.shape[0]))))
-	result = N.dot(mtx, new_points)[:2]
-	return result.swapaxes(0, 1)
+	points = points.transpose()
+	points = N.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
+ 
+ def is_separable(self):
+	mtx = self.get_matrix()
+	return mtx[0, 1] == 0.0 and mtx[1, 0] == 0.0
+
+ def is_affine(self):
+	return True
+
+	
+class Affine2D(Affine2DBase):
+ input_dims = 2
+ output_dims = 2
+ 
+ def __init__(self, matrix = None):
+ """
+ Initialize an Affine transform from a 3x3 numpy float array.
+
+ a c e
+ b d f
+ 0 0 1
+ """
+	Affine2DBase.__init__(self)
+	if matrix is None:
+	 matrix = N.identity(3)
+	else:
+	 assert matrix.shape == (3, 3)
+	self._mtx = matrix
+	self._inverted = None
+
+ def __repr__(self):
+	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
+ 
+ def __copy__(self):
+	return Affine2D(self._mtx.copy())
+ 
+ def __deepcopy__(self, memo):
+	return Affine2D(self._mtx.copy())
+ 
 #@staticmethod
- def _concat(a, b):
- return N.dot(b, a)
- _concat = staticmethod(_concat)
+ def from_values(a, b, c, d, e, f):
+ return Affine2D(Affine2D.matrix_from_values(a, b, c, d, e, f))
+ from_values = staticmethod(from_values)
 
+ def get_matrix(self):
+	return self._mtx
+ 
 #@staticmethod
 def concat(a, b):
 	return Affine2D(Affine2D._concat(a._mtx, b._mtx))
@@ -346,19 +389,18 @@
 def is_affine(self):
 	return True
 
-class BlendedAffine2D(Affine2D):
+class BlendedAffine2D(Affine2DBase):
 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()
 
-	Transform.__init__(self)
+	Affine2DBase.__init__(self)
 	self.add_children([x_transform, y_transform])
 	self._x = x_transform
 	self._y = y_transform
 	self._mtx = None
-	self._inverted = None
 
 def __repr__(self):
 	return "BlendedAffine2D(%s,%s)" % (self._x, self._y)
@@ -367,7 +409,7 @@
 def _do_invalidation(self):
 	if self._mtx is not None:
 	 self._mtx = None
-	 Affine2D._do_invalidation(self)
+	 Affine2DBase._do_invalidation(self)
 	 return False
 	return True
 
@@ -376,8 +418,9 @@
 	 x_mtx = self._x.get_matrix()
 	 y_mtx = self._y.get_matrix()
 	 # This works because we already know the transforms are
-	 # separable
-	 self._mtx = N.vstack([x_mtx[0], y_mtx[1], [0.0, 0.0, 1.0]])
+	 # separable, though normally one would want to set b and
+	 # c to zero.
+	 self._mtx = N.vstack((x_mtx[0], y_mtx[1], [0.0, 0.0, 1.0]))
 	
 def is_separable(self):
 	return True
@@ -397,20 +440,22 @@
 	self._y = y_transform
 
 def __call__(self, points):
-	# MGDTODO: Implement me
-	pass
+	x_points = self._x(points)
+	y_points = self._y(points)
+	# This works because we already know the transforms are
+	# separable
+	return N.hstack((x_points[:, 0:1], y_points[:, 1:2]))
 
-class CompositeAffine2D(Affine2D):
+class CompositeAffine2D(Affine2DBase):
 def __init__(self, a, b):
 	assert a.is_affine()
 	assert b.is_affine()
 
-	Transform.__init__(self)
+	Affine2DBase.__init__(self)
 	self.add_children([a, b])
 	self._a = a
 	self._b = b
 	self._mtx = None
-	self._inverted = None
 
 def __repr__(self):
 	return "CompositeAffine2D(%s, %s)" % (self._a, self._b)
@@ -418,7 +463,7 @@
 
 def _do_invalidation(self):
 	self._mtx = None
-	Affine2D._do_invalidation(self)
+	Affine2DBase._do_invalidation(self)
 
 def _make__mtx(self):
 	if self._mtx is None:
@@ -433,22 +478,23 @@
 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
 
 def __call__(self, points):
-	# MGDTODO: Optimize here by concatenating affines if possible
 	return self._b(self._a(points))
 
-class BboxTransform(Affine2D):
+class BboxTransform(Affine2DBase):
 def __init__(self, boxin, boxout):
 	assert isinstance(boxin, Bbox)
 	assert isinstance(boxout, Bbox)
 
-	Transform.__init__(self)
+	Affine2DBase.__init__(self)
 	self.add_children([boxin, boxout])
 	self._boxin = boxin
 	self._boxout = boxout
@@ -462,7 +508,7 @@
 def _do_invalidation(self):
 	if self._mtx is not None:
 	 self._mtx = None
-	 Affine2D._do_invalidation(self)
+	 Affine2DBase._do_invalidation(self)
 	 return False
 	return True
 
@@ -481,14 +527,6 @@
 
 	 self._mtx = affine._mtx
 	
- def __call__(self, points):
-	self._make__mtx()
-	return Affine2D.__call__(self, points)
-
- def inverted(self):
-	self._make__mtx()
-	return Affine2D.inverted(self)
-
 def is_separable(self):
 	return True
 
@@ -541,6 +579,9 @@
 return interval[0] < val and interval[1] > val
 
 if __name__ == '__main__':
+ from random import random
+ import timeit
+
 bbox = Bbox.from_lbrt(10., 15., 20., 25.)
 assert bbox.xmin == 10
 assert bbox.ymin == 15
@@ -589,7 +630,9 @@
 scale = Affine2D().scale(10, 20)
 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)
+ print rotation.to_values() == (0.86602540378443871, 0.49999999999999994,
+				 -0.49999999999999994, 0.86602540378443871,
+				 0.0, 0.0)
 
 points = N.array([[1,2],[3,4],[5,6],[7,8]], N.float_)
 translated_points = translation(points)
@@ -600,11 +643,20 @@
 print rotated_points
 
 tpoints1 = rotation(translation(scale(points)))
- trans_sum = rotation + translation + scale
+ trans_sum = scale + translation + rotation
 tpoints2 = trans_sum(points)
 print tpoints1, tpoints2
 print tpoints1 == tpoints2
 # Need to do some sort of fuzzy comparison here?
 # assert (tpoints1 == tpoints2).all()
+
+ # Here are some timing tests
+ points = [(random(), random()) for i in xrange(10000)]
+ t = timeit.Timer("trans_sum(points)", "from __main__ import trans_sum, points")
+ print "Time to transform 10000 x 10 points as tuples:", t.timeit(10)
+
+ points2 = N.asarray(points)
+ t = timeit.Timer("trans_sum(points2)", "from __main__ import trans_sum, points2")
+ print "Time to transform 10000 x 10 points as numpy array:", t.timeit(10)
 
 __all__ = ['Transform', 'Affine2D']
Modified: branches/transforms/lib/matplotlib/artist.py
===================================================================
--- branches/transforms/lib/matplotlib/artist.py	2007年09月12日 18:22:24 UTC (rev 3841)
+++ branches/transforms/lib/matplotlib/artist.py	2007年09月12日 19:47:56 UTC (rev 3842)
@@ -337,7 +337,7 @@
 def _set_gc_clip(self, gc):
 'set the clip properly for the gc'
 if self.clipbox is not None:
- gc.set_clip_rectangle(self.clipbox.get_bounds())
+ gc.set_clip_rectangle(self.clipbox.bounds)
 gc.set_clip_path(self._clippath)
 
 def draw(self, renderer, *args, **kwargs):
Modified: branches/transforms/lib/matplotlib/axes.py
===================================================================
--- branches/transforms/lib/matplotlib/axes.py	2007年09月12日 18:22:24 UTC (rev 3841)
+++ branches/transforms/lib/matplotlib/axes.py	2007年09月12日 19:47:56 UTC (rev 3842)
@@ -1,5 +1,5 @@
 from __future__ import division, generators
-import math, sys, warnings
+import math, sys, warnings, copy
 
 import numpy as npy
 
@@ -483,7 +483,7 @@
 """
 martist.Artist.__init__(self)
 self._position = maffine.Bbox.from_lbwh(*rect)
- self._originalPosition = self._position.copy()
+ self._originalPosition = copy.deepcopy(self._position)
 self.set_axes(self)
 self.set_aspect('auto')
 self.set_adjustable('box')
@@ -613,7 +613,7 @@
 """
 martist.Artist.set_figure(self, fig)
 
- l, b, w, h = self._position.get_bounds()
+ l, b, w, h = self._position.bounds
 xmin = fig.bbox.xmin
 xmax = fig.bbox.xmax
 ymin = fig.bbox.ymin
@@ -669,9 +669,9 @@
 def get_position(self, original=False):
 'Return the axes rectangle left, bottom, width, height'
 if original:
- return self._originalPosition[:]
+ return self._originalPosition.bounds
 else:
- return self._position[:]
+ return self._position.bounds
 	 # return [val.get() for val in self._position]
 
 def set_position(self, pos, which='both'):
@@ -694,10 +694,10 @@
 # # Change values within self._position--don't replace it.
 # for num,val in zip(pos, self._position):
 # val.set(num)
-	 self._position = pos
+	 self._position.bounds = pos.bounds
 	 # MGDTODO: side-effects
 if which in ('both', 'original'):
- self._originalPosition = pos
+ self._originalPosition.bounds = pos.bounds
 	 
 	 
 def _set_artist_props(self, a):
@@ -1547,7 +1547,9 @@
 
 def get_xscale(self):
 'return the xaxis scale string: log or linear'
- return self.scaled[self.transData.get_funcx().get_type()]
+	# MGDTODO
+ # return self.scaled[self.transData.get_funcx().get_type()]
+	return 'linear'
 
 def set_xscale(self, value, basex = 10, subsx=None):
 """
@@ -1671,7 +1673,8 @@
 
 def get_yscale(self):
 'return the yaxis scale string: log or linear'
- return self.scaled[self.transData.get_funcy().get_type()]
+ # return self.scaled[self.transData.get_funcy().get_type()]
+	return 'linear'
 
 def set_yscale(self, value, basey=10, subsy=None):
 """
Modified: branches/transforms/lib/matplotlib/backend_bases.py
===================================================================
--- branches/transforms/lib/matplotlib/backend_bases.py	2007年09月12日 18:22:24 UTC (rev 3841)
+++ branches/transforms/lib/matplotlib/backend_bases.py	2007年09月12日 19:47:56 UTC (rev 3842)
@@ -4,7 +4,7 @@
 """
 
 from __future__ import division
-import os, sys, warnings
+import os, sys, warnings, copy
 
 import numpy as npy
 import matplotlib.numerix.npyma as ma
@@ -1070,7 +1070,7 @@
 def get_width_height(self):
 """return the figure width and height in points or pixels
 (depending on the backend), truncated to integers"""
- return int(self.figure.bbox.width()), int(self.figure.bbox.height())
+ return int(self.figure.bbox.width), int(self.figure.bbox.height)
 
 filetypes = {
 'emf': 'Enhanced Metafile',
@@ -1544,7 +1544,7 @@
 xmin, xmax = a.get_xlim()
 ymin, ymax = a.get_ylim()
 lim = xmin, xmax, ymin, ymax
- self._xypress.append((x, y, a, i, lim,a.transData.deepcopy()))
+ self._xypress.append((x, y, a, i, lim, copy.deepcopy(a.transData)))
 self.canvas.mpl_disconnect(self._idDrag)
 self._idDrag=self.canvas.mpl_connect('motion_notify_event', self.drag_pan)
 
@@ -1571,7 +1571,7 @@
 xmin, xmax = a.get_xlim()
 ymin, ymax = a.get_ylim()
 lim = xmin, xmax, ymin, ymax
- self._xypress.append(( x, y, a, i, lim, a.transData.deepcopy() ))
+ self._xypress.append(( x, y, a, i, lim, copy.deepcopy(a.transData) ))
 
 self.press(event)
 
@@ -1637,8 +1637,9 @@
 #safer to use the recorded button at the press than current button:
 #multiple button can get pressed during motion...
 if self._button_pressed==1:
- lastx, lasty = trans.inverse_xy_tup( (lastx, lasty) )
- x, y = trans.inverse_xy_tup( (event.x, event.y) )
+		inverse = trans.inverted()
+ lastx, lasty = inverse.transform_point((lastx, lasty))
+ x, y = inverse.transform_point( (event.x, event.y) )
 if a.get_xscale()=='log':
 dx=1-lastx/x
 else:
@@ -1664,15 +1665,16 @@
 ymax -= dy
 elif self._button_pressed==3:
 try:
- dx=(lastx-event.x)/float(a.bbox.width())
- dy=(lasty-event.y)/float(a.bbox.height())
+ dx=(lastx-event.x)/float(a.bbox.width)
+ dy=(lasty-event.y)/float(a.bbox.height)
 dx,dy=format_deltas(event,dx,dy)
 if a.get_aspect() != 'auto':
 dx = 0.5*(dx + dy)
 dy = dx
 alphax = pow(10.0,dx)
 alphay = pow(10.0,dy)#use logscaling, avoid singularities and smother scaling...
- lastx, lasty = trans.inverse_xy_tup( (lastx, lasty) )
+		 inverse = trans.inverted()
+ lastx, lasty = inverse.transform_point( (lastx, lasty) )
 if a.get_xscale()=='log':
 xmin = lastx*(xmin/lastx)**alphax
 xmax = lastx*(xmax/lastx)**alphax
@@ -1710,8 +1712,9 @@
 xmin, ymin, xmax, ymax = lim
 
 # zoom to rect
- lastx, lasty = a.transData.inverse_xy_tup( (lastx, lasty) )
- x, y = a.transData.inverse_xy_tup( (x, y) )
+	 inverse = a.transData.inverted()
+ lastx, lasty = inverse.transform_point( (lastx, lasty) )
+ x, y = inverse.transform_point( (x, y) )
 Xmin,Xmax=a.get_xlim()
 Ymin,Ymax=a.get_ylim()
 
Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py
===================================================================
--- branches/transforms/lib/matplotlib/backends/backend_agg.py	2007年09月12日 18:22:24 UTC (rev 3841)
+++ branches/transforms/lib/matplotlib/backends/backend_agg.py	2007年09月12日 19:47:56 UTC (rev 3842)
@@ -398,7 +398,7 @@
 self.figure.draw(self.renderer)
 
 def get_renderer(self):
- l,b,w,h = self.figure.bbox.get_bounds()
+ l,b,w,h = self.figure.bbox.bounds
 	# MGDTODO
 # key = w, h, self.figure.dpi.get()
 key = w, h, self.figure.dpi
Modified: branches/transforms/lib/matplotlib/backends/backend_tkagg.py
===================================================================
--- branches/transforms/lib/matplotlib/backends/backend_tkagg.py	2007年09月12日 18:22:24 UTC (rev 3841)
+++ branches/transforms/lib/matplotlib/backends/backend_tkagg.py	2007年09月12日 19:47:56 UTC (rev 3842)
@@ -147,7 +147,7 @@
 def __init__(self, figure, master=None, resize_callback=None):
 FigureCanvasAgg.__init__(self, figure)
 self._idle = True
- t1,t2,w,h = self.figure.bbox.get_bounds()
+ t1,t2,w,h = self.figure.bbox.bounds
 w, h = int(w), int(h)
 self._tkcanvas = Tk.Canvas(
 master=master, width=w, height=h, borderwidth=4)
@@ -288,7 +288,7 @@
 self.window.wm_title("Figure %d" % num)
 self.canvas = canvas
 self._num = num
- t1,t2,w,h = canvas.figure.bbox.get_bounds()
+ t1,t2,w,h = canvas.figure.bbox.bounds
 w, h = int(w), int(h)
 self.window.minsize(int(w*3/4),int(h*3/4))
 if matplotlib.rcParams['toolbar']=='classic':
@@ -436,7 +436,7 @@
 self.canvas = canvas
 self.window = window
 
- xmin, xmax = canvas.figure.bbox.intervalx().get_bounds()
+ xmin, xmax = canvas.figure.bbox.intervalx
 height, width = 50, xmax-xmin
 Tk.Frame.__init__(self, master=self.window,
 width=width, height=height,
@@ -582,7 +582,7 @@
 self.message.set(s)
 
 def draw_rubberband(self, event, x0, y0, x1, y1):
- height = self.canvas.figure.bbox.height()
+ height = self.canvas.figure.bbox.height
 y0 = height-y0
 y1 = height-y1
 try: self.lastrect
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2007年09月13日 12:44:23
Revision: 3846
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3846&view=rev
Author: mdboom
Date: 2007年09月13日 05:44:16 -0700 (2007年9月13日)
Log Message:
-----------
Minor changes -- committing so I can merge again.
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/affine.py
 branches/transforms/lib/matplotlib/patches.py
 branches/transforms/lib/matplotlib/text.py
Modified: branches/transforms/lib/matplotlib/affine.py
===================================================================
--- branches/transforms/lib/matplotlib/affine.py	2007年09月13日 06:29:14 UTC (rev 3845)
+++ branches/transforms/lib/matplotlib/affine.py	2007年09月13日 12:44:16 UTC (rev 3846)
@@ -4,7 +4,7 @@
 2007 Michael Droettboom
 """
 
-import numpy as N
+import numpy as npy
 from numpy.linalg import inv
 from sets import Set
 
@@ -37,7 +37,7 @@
 class Bbox(TransformNode):
 def __init__(self, points):
 	TransformNode.__init__(self)
-	self._points = N.asarray(points, N.float_)
+	self._points = npy.asarray(points, npy.float_)
 	self.track = False
 
 #@staticmethod
@@ -52,7 +52,7 @@
 
 #@staticmethod
 def from_lbrt(*args):
-	points = N.array(args, dtype=N.float_).reshape(2, 2)
+	points = npy.array(args, dtype=npy.float_).reshape(2, 2)
 	return Bbox(points)
 from_lbrt = staticmethod(from_lbrt)
 
@@ -72,12 +72,15 @@
 	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 = N.array([[x.min(), y.min()], [x.max(), y.max()]], N.float_)
+	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...
@@ -150,7 +153,7 @@
 		self.xmax - self.xmin, self.ymax - self.ymin)
 def _set_bounds(self, bounds):
 	l,b,w,h = bounds
-	self._points = N.array([[l, b], [l+w, b+h]], N.float_)
+	self._points = npy.array([[l, b], [l+w, b+h]], npy.float_)
 	self.invalidate()
 bounds = property(_get_bounds, _set_bounds)
 	
@@ -165,7 +168,7 @@
 	height = self.height
 	deltaw = (sw * width - width) / 2.0
 	deltah = (sh * height - height) / 2.0
-	a = N.array([[-deltaw, -deltah], [deltaw, deltah]])
+	a = npy.array([[-deltaw, -deltah], [deltaw, deltah]])
 	return Bbox(self._points + a)
 
 def contains(self, x, y):
@@ -215,7 +218,7 @@
 	raise TypeError("Can not add Transform to object of type '%s'" % type(other))
 
 def transform_point(self, point):
-	return self.__call__([point])[0]
+	return self.__call__(npy.asarray([point]))[0]
 
 def has_inverse(self):
 	raise NotImplementedError()
@@ -229,8 +232,6 @@
 def is_affine(self):
 	return False
 
-# MGDTODO: Separate out Affine2DBase / Affine2DConcrete so BlendedAffine and CompositeAffine don't have translate/scale/rotate members
-
 class Affine2DBase(Transform):
 input_dims = 2
 output_dims = 2
@@ -246,7 +247,7 @@
 
 #@staticmethod
 def _concat(a, b):
- return N.dot(b, a)
+ return npy.dot(b, a)
 _concat = staticmethod(_concat)
 
 def to_values(self):
@@ -255,7 +256,7 @@
 
 #@staticmethod
 def matrix_from_values(a, b, c, d, e, f):
-	affine = N.zeros((3,3), N.float_)
+	affine = npy.zeros((3,3), npy.float_)
 	affine[0,] = a, c, e
 	affine[1,] = b, d, f
 	affine[2,2] = 1
@@ -267,7 +268,7 @@
 
 def __call__(self, points):
 """
- Applies the transformation to a set of 2D points and
+ Applies the transformation to an array of 2D points and
 	returns the result.
 
 	points must be a numpy array of shape (N, 2), where N is the
@@ -277,9 +278,9 @@
 	# 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 = N.asarray(points, N.float_)
+	points = npy.asarray(points, npy.float_)
 	points = points.transpose()
-	points = N.dot(mtx[0:2, 0:2], points)
+	points = npy.dot(mtx[0:2, 0:2], points)
 	points = points + mtx[0:2, 2:]
 	return points.transpose()
 
@@ -311,7 +312,7 @@
 """
 	Affine2DBase.__init__(self)
 	if matrix is None:
-	 matrix = N.identity(3)
+	 matrix = npy.identity(3)
 	else:
 	 assert matrix.shape == (3, 3)
 	self._mtx = matrix
@@ -348,19 +349,19 @@
 
 #@staticmethod
 def identity():
- return Affine2D(N.identity(3))
+ return Affine2D(npy.identity(3))
 identity = staticmethod(identity)
 
 def rotate(self, theta):
- a = N.cos(theta)
- b = N.sin(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
 
 def rotate_deg(self, degrees):
- return self.rotate(degrees*N.pi/180.)
+ return self.rotate(degrees*npy.pi/180.)
 
 def translate(self, tx, ty):
 translate_mtx = self.matrix_from_values(1., 0., 0., 1., tx, ty)
@@ -420,7 +421,7 @@
 	 # This works because we already know the transforms are
 	 # separable, though normally one would want to set b and
 	 # c to zero.
-	 self._mtx = N.vstack((x_mtx[0], y_mtx[1], [0.0, 0.0, 1.0]))
+	 self._mtx = npy.vstack((x_mtx[0], y_mtx[1], [0.0, 0.0, 1.0]))
 	
 def is_separable(self):
 	return True
@@ -444,7 +445,7 @@
 	y_points = self._y(points)
 	# This works because we already know the transforms are
 	# separable
-	return N.hstack((x_points[:, 0:1], y_points[:, 1:2]))
+	return npy.hstack((x_points[:, 0:1], y_points[:, 1:2]))
 
 class CompositeAffine2D(Affine2DBase):
 def __init__(self, a, b):
@@ -579,6 +580,7 @@
 return interval[0] < val and interval[1] > val
 
 if __name__ == '__main__':
+ import copy
 from random import random
 import timeit
 
@@ -588,36 +590,38 @@
 assert bbox.xmax == 20
 assert bbox.ymax == 25
 
- assert N.all(bbox.min == [10, 15])
- assert N.all(bbox.max == [20, 25])
- assert N.all(bbox.intervalx == (10, 20))
- assert N.all(bbox.intervaly == (15, 25))
+ assert npy.all(bbox.min == [10, 15])
+ assert npy.all(bbox.max == [20, 25])
+ assert npy.all(bbox.intervalx == (10, 20))
+ assert npy.all(bbox.intervaly == (15, 25))
 
 assert bbox.width == 10
 assert bbox.height == 10
 
- assert bbox.get_bounds() == (10, 15, 10, 10)
+ assert bbox.bounds == (10, 15, 10, 10)
 
+ print npy.asarray(bbox)
+ 
 bbox.intervalx = (11, 21)
 bbox.intervaly = (16, 26)
 
- assert bbox.get_bounds() == (11, 16, 10, 10)
+ assert bbox.bounds == (11, 16, 10, 10)
 
 bbox.xmin = 12
 bbox.ymin = 17
 bbox.xmax = 22
 bbox.ymax = 27
 
- assert bbox.get_bounds() == (12, 17, 10, 10)
+ assert bbox.bounds == (12, 17, 10, 10)
 
 bbox = Bbox.from_lbwh(10, 11, 12, 13)
- assert bbox.get_bounds() == (10, 11, 12, 13)
+ assert bbox.bounds == (10, 11, 12, 13)
 
- bbox_copy = bbox.copy()
+ bbox_copy = copy.copy(bbox)
 assert bbox == bbox_copy
 bbox_copy.max = (14, 15)
- assert bbox.get_bounds() == (10, 11, 12, 13)
- assert bbox_copy.get_bounds() == (10, 11, 4, 4)
+ assert bbox.bounds == (10, 11, 12, 13)
+ assert bbox_copy.bounds == (10, 11, 4, 4)
 
 bbox1 = Bbox([[10., 15.], [20., 25.]])
 bbox2 = Bbox([[30., 35.], [40., 45.]])
@@ -634,7 +638,7 @@
 				 -0.49999999999999994, 0.86602540378443871,
 				 0.0, 0.0)
 
- points = N.array([[1,2],[3,4],[5,6],[7,8]], N.float_)
+ points = npy.array([[1,2],[3,4],[5,6],[7,8]], npy.float_)
 translated_points = translation(points)
 assert (translated_points == [[11., 22.], [13., 24.], [15., 26.], [17., 28.]]).all()
 scaled_points = scale(points)
@@ -655,7 +659,7 @@
 t = timeit.Timer("trans_sum(points)", "from __main__ import trans_sum, points")
 print "Time to transform 10000 x 10 points as tuples:", t.timeit(10)
 
- points2 = N.asarray(points)
+ points2 = npy.asarray(points)
 t = timeit.Timer("trans_sum(points2)", "from __main__ import trans_sum, points2")
 print "Time to transform 10000 x 10 points as numpy array:", t.timeit(10)
 
Modified: branches/transforms/lib/matplotlib/patches.py
===================================================================
--- branches/transforms/lib/matplotlib/patches.py	2007年09月13日 06:29:14 UTC (rev 3845)
+++ branches/transforms/lib/matplotlib/patches.py	2007年09月13日 12:44:16 UTC (rev 3846)
@@ -356,9 +356,9 @@
 left, right = self.convert_xunits((x, x + self.width))
 bottom, top = self.convert_yunits((y, y + self.height))
 
- return ( (left, bottom), (left, top),
- (right, top), (right, bottom),
- )
+ return npy.array([[left, bottom], [left, top],
+			 [right, top], [right, bottom]],
+			 npy.float_)
 
 def get_x(self):
 "Return the left coord of the rectangle"
Modified: branches/transforms/lib/matplotlib/text.py
===================================================================
--- branches/transforms/lib/matplotlib/text.py	2007年09月13日 06:29:14 UTC (rev 3845)
+++ branches/transforms/lib/matplotlib/text.py	2007年09月13日 12:44:16 UTC (rev 3846)
@@ -149,7 +149,7 @@
 def _get_xy_display(self):
 'get the (possibly unit converted) transformed x,y in display coords'
 x, y = self.get_position()
- return self.get_transform()([[x,y]])[0]
+ return self.get_transform().transform_point((x,y))
 
 def _get_multialignment(self):
 if self._multialignment is not None: return self._multialignment
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2007年09月13日 18:00:12
Revision: 3848
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3848&view=rev
Author: mdboom
Date: 2007年09月13日 11:00:10 -0700 (2007年9月13日)
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_)
 
 #@staticmethod
 def unit():
-	return Bbox.from_lbrt(0., 0., 1., 1.)
+ return Bbox.from_lbrt(0., 0., 1., 1.)
 unit = staticmethod(unit)
 
 #@staticmethod
 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)
 
 #@staticmethod
 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)
-
 #@staticmethod
 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
 
 #@staticmethod
 def _concat(a, b):
 return npy.dot(b, a)
 _concat = staticmethod(_concat)
+
+ #@staticmethod
+ 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())
 
 #@staticmethod
 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())
 
 #@staticmethod
 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()
 
 #@staticmethod
- def concat(a, b):
-	return Affine2D(Affine2D._concat(a._mtx, b._mtx))
- concat = staticmethod(concat)
- 
- #@staticmethod
 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.
From: <md...@us...> - 2007年09月19日 13:28:21
Revision: 3857
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3857&view=rev
Author: mdboom
Date: 2007年09月19日 06:28:11 -0700 (2007年9月19日)
Log Message:
-----------
Got legend working with new transforms
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/axes.py
 branches/transforms/lib/matplotlib/legend.py
 branches/transforms/lib/matplotlib/lines.py
 branches/transforms/lib/matplotlib/patches.py
 branches/transforms/lib/matplotlib/transforms.py
Modified: branches/transforms/lib/matplotlib/axes.py
===================================================================
--- branches/transforms/lib/matplotlib/axes.py	2007年09月18日 19:29:21 UTC (rev 3856)
+++ branches/transforms/lib/matplotlib/axes.py	2007年09月19日 13:28:11 UTC (rev 3857)
@@ -632,6 +632,7 @@
 	
 self.transAxes = mtransforms.BboxTransform(
 mtransforms.Bbox.unit(), self.bbox)
+ # self.set_transform(self.transAxes)
 self.transData = mtransforms.BboxTransform(
 self.viewLim, self.bbox)
 	 
@@ -724,6 +725,7 @@
 self.axesPatch.set_figure(self.figure)
 self.axesPatch.set_transform(self.transAxes)
 self.axesPatch.set_linewidth(rcParams['axes.linewidth'])
+ # MGDTODO: What is axesFrame for? We already have axesPatch
 self.axesFrame = mlines.Line2D((0,1,1,0,0), (0,0,1,1,0),
 linewidth=rcParams['axes.linewidth'],
 color=rcParams['axes.edgecolor'],
@@ -5201,7 +5203,7 @@
 Subplot(211) # 2 rows, 1 column, first (upper) plot
 """
 def __str__(self):
- return "Subplot(%g,%g)"%(self.bottom.get(),self.left.get())
+ return "Subplot(%f,%f,%f,%f)" % (self.bbox.bounds)
 
 def __init__(self, fig, *args, **kwargs):
 """
Modified: branches/transforms/lib/matplotlib/legend.py
===================================================================
--- branches/transforms/lib/matplotlib/legend.py	2007年09月18日 19:29:21 UTC (rev 3856)
+++ branches/transforms/lib/matplotlib/legend.py	2007年09月19日 13:28:11 UTC (rev 3857)
@@ -164,7 +164,7 @@
 else:
 raise TypeError("Legend needs either Axes or Figure as parent")
 self.parent = parent
- self.set_transform( BboxTransform( Bbox.unit(), parent.bbox) )
+ self.set_transform( BboxTransform(Bbox.unit(), parent.bbox) )
 
 if loc is None:
 loc = rcParams["legend.loc"]
@@ -223,7 +223,7 @@
 a.set_transform(self.get_transform())
 
 def _approx_text_height(self):
- return self.fontsize/72.0*self.figure.dpi/self.parent.bbox.height()
+ return self.fontsize/72.0*self.figure.dpi/self.parent.bbox.height
 
 
 def draw(self, renderer):
@@ -531,7 +531,7 @@
 def get_tbounds(text): #get text bounds in axes coords
 bbox = text.get_window_extent(renderer)
 bboxa = bbox.inverse_transformed(self.get_transform())
- return bboxa.get_bounds()
+ return bboxa.bounds
 
 hpos = []
 for t, tabove in zip(self.texts[1:], self.texts[:-1]):
@@ -560,10 +560,10 @@
 # Set the data for the legend patch
 bbox = copy.copy(self._get_handle_text_bbox(renderer))
 
- bbox = bbox.scaled(1 + self.pad, 1 + self.pad)
- l,b,w,h = bbox.get_bounds()
- self.legendPatch.set_bounds(l,b,w,h)
-
+ bbox = bbox.expanded(1 + self.pad, 1 + self.pad)
+ l, b, w, h = bbox.bounds
+ self.legendPatch.set_bounds(l, b, w, h)
+ 
 ox, oy = 0, 0 # center
 
 if iterable(self._loc) and len(self._loc)==2:
Modified: branches/transforms/lib/matplotlib/lines.py
===================================================================
--- branches/transforms/lib/matplotlib/lines.py	2007年09月18日 19:29:21 UTC (rev 3856)
+++ branches/transforms/lib/matplotlib/lines.py	2007年09月19日 13:28:11 UTC (rev 3857)
@@ -117,7 +117,7 @@
 '--' : '_draw_dashed',
 '-.' : '_draw_dash_dot',
 ':' : '_draw_dotted',
- 'steps': '_draw_steps',
+ 'steps': '_draw_solid',
 'None' : '_draw_nothing',
 ' ' : '_draw_nothing',
 '' : '_draw_nothing',
@@ -352,10 +352,10 @@
 self._picker = p
 
 def get_window_extent(self, renderer):
- xys = self.get_transform()(self._xys)
+ xy = self.get_transform()(self._xy)
 
-	x = xys[:, 0]
-	y = xys[:, 1]
+	x = xy[:, 0]
+	y = xy[:, 1]
 left = x.min()
 bottom = y.min()
 width = x.max() - left
@@ -426,9 +426,19 @@
 			 npy.asarray(y, npy.float_))).transpose()
 	self._x = self._xy[:, 0]
 	self._y = self._xy[:, 1]
-	self._path = Path(self._xy, closed=False)
-	
 self._logcache = None
+ 
+ if self._linestyle == 'steps':
+ siz=len(xt)
+ if siz<2: return
+ xt, yt = self._x, self._y
+ xt2=npy.ones((2*siz,), xt.dtype)
+ xt2[0:-1:2], xt2[1:-1:2], xt2[-1] = xt, xt[1:], xt[-1]
+ yt2=npy.ones((2*siz,), yt.dtype)
+ yt2[0:-1:2], yt2[1::2] = yt, yt
+ self._path = Path(npy.vstack((xt2, yt2)).transpose(), closed=False)
+ else:
+ self._path = Path(self._xy, closed=False)
 
 
 def _is_sorted(self, x):
@@ -700,24 +710,6 @@
 pass
 
 
- def _draw_steps(self, renderer, gc, xt, yt):
-	# MGDTODO: This is a quirky one. The step-plotting part
-	# should probably be moved to where the path is generated
-	# in recache, and then just drawn with _draw_solid
- siz=len(xt)
- if siz<2: return
- xt2=npy.ones((2*siz,), xt.dtype)
- xt2[0:-1:2], xt2[1:-1:2], xt2[-1]=xt, xt[1:], xt[-1]
- yt2=npy.ones((2*siz,), yt.dtype)
- yt2[0:-1:2], yt2[1::2]=yt, yt
- gc.set_linestyle('solid')
-
- if self._newstyle:
- renderer.draw_lines(gc, xt2, yt2, self.get_transform())
- else:
- renderer.draw_lines(gc, xt2, yt2)
-
-	 
 def _draw_solid(self, renderer, gc, path):
 gc.set_linestyle('solid')
 	renderer.draw_path(gc, path, self.get_transform())
Modified: branches/transforms/lib/matplotlib/patches.py
===================================================================
--- branches/transforms/lib/matplotlib/patches.py	2007年09月18日 19:29:21 UTC (rev 3856)
+++ branches/transforms/lib/matplotlib/patches.py	2007年09月19日 13:28:11 UTC (rev 3857)
@@ -212,8 +212,8 @@
 gc.set_hatch(self._hatch )
 
 path = self.get_path()
- transform = self.get_transform()
-
+ transform = self.get_patch_transform() + self.get_transform()
+ 
 renderer.draw_path(gc, path, transform, rgbFace)
 
 #renderer.close_group('patch')
@@ -284,7 +284,7 @@
 self.patch = patch
 self.props = props
 	self.ox, self.oy = ox, oy
-	self._shadow_transform = transforms.Affine2D.translate(self.ox, self.oy)
+	self._shadow_transform = transforms.Affine2D().translate(self.ox, self.oy)
 self._update()
 __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd
 
@@ -305,8 +305,8 @@
 def get_path(self):
 return self.patch.get_path()
 
- def get_transform(self):
-	return self._transform + self._shadow_transform
+ def get_patch_transform(self):
+	return self._shadow_transform
 
 class Rectangle(Patch):
 """
@@ -315,8 +315,6 @@
 
 """
 
- _path = Path.unit_rectangle()
- 
 def __str__(self):
 return str(self.__class__).split('.')[-1] \
 + "(%g,%g;%gx%g)"%(self.xy[0],self.xy[1],self.width,self.height)
@@ -346,16 +344,14 @@
 """
 Return the vertices of the rectangle
 """
-	# This is a "class-static" variable, so all rectangles in the plot
-	# will be shared (and merely have different transforms)
-	return self._path
+	return Path.unit_rectangle()
 
 # MGDTODO: Convert units
 # left, right = self.convert_xunits((x, x + self.width))
 # bottom, top = self.convert_yunits((y, y + self.height))
 
- def get_transform(self):
-	return self._rect_transform + self._transform
+ def get_patch_transform(self):
+	return self._rect_transform
 
 def get_x(self):
 "Return the left coord of the rectangle"
@@ -379,7 +375,8 @@
 
 ACCEPTS: float
 """
- self._bbox.xmin = x
+ w = self._bbox.width
+ self._bbox.intervalx = (x, x + w)
 
 def set_y(self, y):
 """
@@ -387,7 +384,8 @@
 
 ACCEPTS: float
 """
- self._bbox.ymin = y
+ h = self._bbox.height
+ self._bbox.intervaly = (y, y + h)
 
 def set_width(self, w):
 """
@@ -395,7 +393,7 @@
 
 ACCEPTS: float
 """
- self._bbox.width = w
+ self._bbox.xmax = self._bbox.xmin + w
 
 def set_height(self, h):
 """
@@ -403,7 +401,7 @@
 
 ACCEPTS: float
 """
- self._bbox.height = h
+ self._bbox.ymax = self._bbox.ymin + h
 
 def set_bounds(self, *args):
 """
Modified: branches/transforms/lib/matplotlib/transforms.py
===================================================================
--- branches/transforms/lib/matplotlib/transforms.py	2007年09月18日 19:29:21 UTC (rev 3856)
+++ branches/transforms/lib/matplotlib/transforms.py	2007年09月19日 13:28:11 UTC (rev 3857)
@@ -8,6 +8,8 @@
 from numpy.linalg import inv
 from sets import Set
 
+DEBUG = True
+
 # MGDTODO: This creates a ton of cyclical references. We may want to
 # consider using weak references
 
@@ -53,6 +55,13 @@
 
 def __array__(self):
 return self.get_points()
+
+ if DEBUG:
+ def invalidate(self):
+ points = self.get_points()
+ assert points[0, 0] <= points[1, 0]
+ assert points[0, 1] <= points[1, 1]
+ TransformNode.invalidate(self)
 
 # MGDTODO: Probably a more efficient ways to do this...
 def _get_xmin(self):
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2007年09月19日 19:46:41
Revision: 3859
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3859&view=rev
Author: mdboom
Date: 2007年09月19日 12:46:34 -0700 (2007年9月19日)
Log Message:
-----------
Lots of minor fixes
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/lines.py
 branches/transforms/lib/matplotlib/patches.py
 branches/transforms/lib/matplotlib/path.py
 branches/transforms/lib/matplotlib/pbox.py
 branches/transforms/lib/matplotlib/text.py
 branches/transforms/lib/matplotlib/transforms.py
Modified: branches/transforms/lib/matplotlib/lines.py
===================================================================
--- branches/transforms/lib/matplotlib/lines.py	2007年09月19日 16:18:51 UTC (rev 3858)
+++ branches/transforms/lib/matplotlib/lines.py	2007年09月19日 19:46:34 UTC (rev 3859)
@@ -252,12 +252,9 @@
 if not is_numlike(self.pickradius):
 raise ValueError,"pick radius should be a distance"
 
- if self._newstyle:
- # transform in backend
- x = self._x
- y = self._y
- else:
- x, y = self._get_plottable()
+ # transform in backend
+ x = self._x
+ y = self._y
 if len(x)==0: return False,{}
 
 xt, yt = self.get_transform().numerix_x_y(x, y)
@@ -337,7 +334,6 @@
 
 ACCEPTS: (npy.array xdata, npy.array ydata)
 """
-
 if len(args)==1:
 x, y = args[0]
 else:
@@ -347,8 +343,9 @@
 self._yorig = y
 self.recache()
 
+ # MGDTODO: Masked data arrays are broken
 _masked_array_to_path_code_mapping = npy.array(
- [Path.LINETO, Path.IGNORE, Path.MOVETO], Path.code_type)
+ [Path.LINETO, Path.MOVETO, Path.MOVETO], Path.code_type)
 def recache(self):
 #if self.axes is None: print 'recache no axes'
 #else: print 'recache units', self.axes.xaxis.units, self.axes.yaxis.units
@@ -387,18 +384,18 @@
 # MGDTODO: If _draw_steps is removed, remove the following line also
 self._step_path = None
 
-
 def _is_sorted(self, x):
 "return true if x is sorted"
 if len(x)<2: return 1
 return npy.alltrue(x[1:]-x[0:-1]>=0)
 
+ # MGDTODO: Remove me (seems to be used for old-style interface only)
 def _get_plottable(self):
 # If log scale is set, only pos data will be returned
 
 x, y = self._x, self._y
 
-	# MGDTODO: Deal with the log scale here
+	# MGDTODO: (log-scaling)
 	
 # try: logx = self.get_transform().get_funcx().get_type()==LOG10
 # except RuntimeError: logx = False # non-separable
Modified: branches/transforms/lib/matplotlib/patches.py
===================================================================
--- branches/transforms/lib/matplotlib/patches.py	2007年09月19日 16:18:51 UTC (rev 3858)
+++ branches/transforms/lib/matplotlib/patches.py	2007年09月19日 19:46:34 UTC (rev 3859)
@@ -319,8 +319,6 @@
 return str(self.__class__).split('.')[-1] \
 + "(%g,%g;%gx%g)"%(self.xy[0],self.xy[1],self.width,self.height)
 
- # MGDTODO: Perhaps pass in a Bbox here instead, then the updates will
- # happen automatically (without needing to call set_x etc.
 def __init__(self, xy, width, height, **kwargs):
 """
 xy is an x,y tuple lower, left
@@ -459,17 +457,14 @@
 
 def __init__(self, xy, **kwargs):
 """
- xy is a sequence of (x,y) 2 tuples
+ xy is a numpy array with shape Nx2
 
 Valid kwargs are:
 %(Patch)s
 See Patch documentation for additional kwargs
 """
-	# MGDTODO: This should encourage the use of numpy arrays of shape Nx2
 Patch.__init__(self, **kwargs)
- if not isinstance(xy, list):
- xy = list(xy)
-	self._path = Path(xy, closed=False)
+	self._path = Path(xy, closed=True)
 __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd
 
 def get_verts(self):
Modified: branches/transforms/lib/matplotlib/path.py
===================================================================
--- branches/transforms/lib/matplotlib/path.py	2007年09月19日 16:18:51 UTC (rev 3858)
+++ branches/transforms/lib/matplotlib/path.py	2007年09月19日 19:46:34 UTC (rev 3859)
@@ -1,15 +1,13 @@
 import numpy as npy
 
-DEBUG = True
-
 class Path(object):
 # Path codes
- IGNORE = 0 # 1 vertex
+ STOP = 0 # 1 vertex
 MOVETO = 1 # 1 vertex
 LINETO = 2 # 1 vertex
 CURVE3 = 3 # 2 vertices
 CURVE4 = 4 # 3 vertices
- CLOSEPOLY = 5
+ CLOSEPOLY = 5 # 1 vertex
 ###
 # MGDTODO: I'm not sure these are supported by PS/PDF/SVG,
 # so if they don't, we probably shouldn't
@@ -18,38 +16,36 @@
 UBSPLINE = 8
 ####
 
- NUM_VERTICES = [1, 1, 1, 2, 3, 0]
+ NUM_VERTICES = [1, 1, 1, 2, 3, 1]
 
 code_type = npy.uint8
 
 def __init__(self, vertices, codes=None, closed=True):
-	self._vertices = npy.asarray(vertices, npy.float_)
-	assert self._vertices.ndim == 2
-	assert self._vertices.shape[1] == 2
-
+ vertices = npy.asarray(vertices, npy.float_)
+	assert vertices.ndim == 2
+	assert vertices.shape[1] == 2
+ 
 	if codes is None:
 	 if closed:
 		codes = self.LINETO * npy.ones(
-		 self._vertices.shape[0] + 1, self.code_type)
+		 vertices.shape[0] + 1, self.code_type)
 		codes[0] = self.MOVETO
-		codes[-1] = self.CLOSEPOLY
+ codes[-1] = self.CLOSEPOLY
+ vertices = npy.concatenate((vertices, [[0.0, 0.0]]))
 	 else:
 		codes = self.LINETO * npy.ones(
-		 self._vertices.shape[0], self.code_type)
+		 vertices.shape[0], self.code_type)
 		codes[0] = self.MOVETO
 else:
 	 codes = npy.asarray(codes, self.code_type)
-	self._codes = codes
-	 
+ assert codes.ndim == 1
+ assert len(codes) == len(vertices)
+
+ self._codes = codes
+	self._vertices = vertices
+ 
 	assert self._codes.ndim == 1
 
-	if DEBUG:
-	 i = 0
-	 NUM_VERTICES = self.NUM_VERTICES
-	 for code in codes:
-		i += NUM_VERTICES[code]
-	 assert i == len(self.vertices)
-
 def __repr__(self):
 	return "Path(%s, %s)" % (self.vertices, self.codes)
 	 
@@ -66,11 +62,13 @@
 	NUM_VERTICES = self.NUM_VERTICES
 	vertices = self.vertices
 	for code in self.codes:
-	 num_vertices = NUM_VERTICES[code]
-	 if num_vertices >= 1:
-		i += num_vertices - 1
-		yield vertices[i]
-		i += 1
+ if code == self.CLOSEPOLY:
+ i += 1
+ else:
+ num_vertices = NUM_VERTICES[code]
+ i += num_vertices - 1
+ yield vertices[i]
+ i += 1
 
 _unit_rectangle = None
 #@classmethod
@@ -118,16 +116,18 @@
 		 
 		 [-offset, -1.0],
 		 [-1.0, -offset],
-		 [-1.0, 0.0]],
-		npy.float_)
-	 codes = npy.array(
-		[cls.MOVETO,
-		 cls.CURVE4,
-		 cls.CURVE4,
-		 cls.CURVE4,
-		 cls.CURVE4,
-		 cls.CLOSEPOLY],
-		cls.code_type)
+		 [-1.0, 0.0],
+
+ [-1.0, 0.0]],
+ npy.float_)
+
+ codes = cls.CURVE4 + npy.ones((len(vertices)))
+	 codes[0] = cls.MOVETO
+ codes[-1] = cls.CLOSEPOLY
+
 	 cls._unit_circle = Path(vertices, codes)
 	return cls._unit_circle
 unit_circle = classmethod(unit_circle)
+
+# MGDTODO: Add a transformed path that would automatically invalidate
+# itself when its transform changes
Modified: branches/transforms/lib/matplotlib/pbox.py
===================================================================
--- branches/transforms/lib/matplotlib/pbox.py	2007年09月19日 16:18:51 UTC (rev 3858)
+++ branches/transforms/lib/matplotlib/pbox.py	2007年09月19日 19:46:34 UTC (rev 3859)
@@ -1,5 +1,3 @@
-# MGDTODO: Just included verbatim for now
-
 class PBox(list):
 '''
 A left-bottom-width-height (lbwh) specification of a bounding box,
Modified: branches/transforms/lib/matplotlib/text.py
===================================================================
--- branches/transforms/lib/matplotlib/text.py	2007年09月19日 16:18:51 UTC (rev 3858)
+++ branches/transforms/lib/matplotlib/text.py	2007年09月19日 19:46:34 UTC (rev 3859)
@@ -231,7 +231,7 @@
 
 # now rotate the bbox
 
- cornersRotated = M(cornersHoriz)
+ cornersRotated = M.transform(cornersHoriz)
 
 txs = cornersRotated[:, 0]
 tys = cornersRotated[:, 1]
@@ -269,7 +269,7 @@
 	
 
 # now rotate the positions around the first x,y position
- xys = M(offsetLayout)
+ xys = M.transform(offsetLayout)
 	tx = xys[:, 0]
 	ty = xys[:, 1]
 	tx += offsetx
@@ -277,7 +277,7 @@
 
 # now inverse transform back to data coords
 	inverse_transform = self.get_transform().inverted()
- xys = inverse_transform(xys)
+ xys = inverse_transform.transform(xys)
 
 xs, ys = zip(*xys)
 
@@ -407,7 +407,7 @@
 return (x, y, self._text, self._color,
 self._verticalalignment, self._horizontalalignment,
 hash(self._fontproperties), self._rotation,
- self.get_transform().to_values(),
+ self.get_transform(),
 )
 
 def get_text(self):
Modified: branches/transforms/lib/matplotlib/transforms.py
===================================================================
--- branches/transforms/lib/matplotlib/transforms.py	2007年09月19日 16:18:51 UTC (rev 3858)
+++ branches/transforms/lib/matplotlib/transforms.py	2007年09月19日 19:46:34 UTC (rev 3859)
@@ -32,7 +32,8 @@
 for child in children:
 getattr(self, child)._parents.add(self)
 self._children = children
- 
+
+ 
 class BboxBase(TransformNode):
 '''
 This is the read-only part of a bounding-box
@@ -293,6 +294,7 @@
 return Bbox.from_lbrt(xmin, ymin, xmax, ymax)
 union = staticmethod(union)
 
+ 
 class TransformedBbox(BboxBase):
 def __init__(self, bbox, transform):
 assert isinstance(bbox, Bbox)
@@ -313,16 +315,20 @@
 
 def get_points(self):
 if self._points is None:
- self._points = self.transform(self.bbox.get_points())
+ self._points = self.transform.transform(self.bbox.get_points())
 return self._points
+
 
 class Transform(TransformNode):
 def __init__(self):
 TransformNode.__init__(self)
 
- def __call__(self, points):
+ def transform(self, points):
 raise NotImplementedError()
 
+ def transform_without_affine(self, points):
+ return self.transform(points), IDENTITY
+ 
 def __add__(self, other):
 if isinstance(other, Transform):
 return composite_transform_factory(self, other)
@@ -336,7 +342,7 @@
 "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.transform(npy.asarray([point]))[0]
 
 def has_inverse(self):
 raise NotImplementedError()
@@ -350,6 +356,7 @@
 def is_affine(self):
 return False
 
+ 
 class Affine2DBase(Transform):
 input_dims = 2
 output_dims = 2
@@ -390,7 +397,7 @@
 def get_matrix(self):
 raise NotImplementedError()
 
- def __call__(self, points):
+ def transform(self, points):
 """
 Applies the transformation to an array of 2D points and
 returns the result.
@@ -414,6 +421,11 @@
 points = npy.dot(mtx[0:2, 0:2], points)
 points = points + mtx[0:2, 2:]
 return points.transpose()
+
+ def transform_without_affine(self, points):
+ # MGDTODO: Should we copy the points here? I'd like to avoid it,
+ # if possible
+ return points, self
 
 def inverted(self):
 if self._inverted is None:
@@ -430,9 +442,6 @@
 
 
 class Affine2D(Affine2DBase):
- input_dims = 2
- output_dims = 2
- 
 def __init__(self, matrix = None):
 """
 Initialize an Affine transform from a 3x3 numpy float array.
@@ -535,40 +544,82 @@
 
 def is_affine(self):
 return True
+
+IDENTITY = Affine2D()
 
 class BlendedGenericTransform(Transform):
+ input_dims = 2
+ output_dims = 2
+
 def __init__(self, x_transform, y_transform):
 	# Here we ask: "Does it blend?"
 assert x_transform.is_separable()
 assert y_transform.is_separable()
-
+ assert x_transform.input_dims == x_transform.output_dims == 2
+ assert y_transform.input_dims == y_transform.output_dims == 2
+ 
 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:
+ def transform(self, points):
+ # MGDTODO: Optimize the case where one of these is
+ # an affine
+ x = self._x
+ y = self._y
+ if x == y and x.input_dims == 2:
 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)
+ if x.input_dims == 2:
+ x_points = x.transform(points)[:, 0]
+ else:
+ x_points = x.transform(points[:, 0])
 
-# def set_y_transform(self, y_transform):
-# self.replace_child(1, y_transform)
+ if y.input_dims == 2:
+ y_points = y.transform(points)[:, 1]
+ else:
+ y_points = y.transform(points[:, 1])
 
+ return npy.vstack((x_points, y_points)).transpose()
+
+ def inverted(self):
+ return BlendedGenericTransform(self._x.inverted(), self._y.inverted())
 
-class BlendedAffine2D(Affine2DBase, BlendedGenericTransform):
+ def is_separable(self):
+ return True
+ 
+ 
+class BlendedSeparableTransform(Transform):
+ input_dims = 2
+ output_dims = 2
+
 def __init__(self, x_transform, y_transform):
+	# Here we ask: "Does it blend?"
+ assert x_transform.is_separable()
+ assert y_transform.is_separable()
+ assert x_transform.input_dims == x.transform.output_dims == 1
+ assert y_transform.input_dims == y.transform.output_dims == 1
+ 
+ Transform.__init__(self)
+ self._x = x_transform
+ self._y = y_transform
+ self.set_children(['_x', '_y'])
+
+ def transform(self, points):
+ x_points = self._x(points[:, 0])
+ y_points = self._y(points[:, 1])
+ return npy.vstack((x_points[:, 0:1], y_points[:, 1:2])).transpose()
+ 
+ 
+class BlendedAffine2D(Affine2DBase, Transform):
+ def __init__(self, x_transform, y_transform):
 assert x_transform.is_affine()
 assert y_transform.is_affine()
- BlendedGenericTransform.__init__(self, x_transform, y_transform)
+ Transform.__init__(self)
+ self._x = x_transform
+ self._y = y_transform
+ self.set_children(['_x', '_y'])
 
 Affine2DBase.__init__(self)
 self._mtx = None
@@ -597,12 +648,14 @@
 # c to zero.
 self._mtx = npy.vstack((x_mtx[0], y_mtx[1], [0.0, 0.0, 1.0]))
 return self._mtx
- 
+
+ 
 def blended_transform_factory(x_transform, y_transform):
 if x_transform.is_affine() and y_transform.is_affine():
 return BlendedAffine2D(x_transform, y_transform)
 return BlendedGenericTransform(x_transform, y_transform)
 
+
 class CompositeGenericTransform(Transform):
 def __init__(self, a, b):
 assert a.output_dims == b.input_dims
@@ -614,9 +667,17 @@
 self._b = b
 self.set_children(['_a', '_b'])
 
- def __call__(self, points):
- return self._b(self._a(points))
+ def transform(self, points):
+ return self._b.transform(self._a.transform(points))
+
+ def inverted(self):
+ return CompositeGenericTransform(self._b.inverted(), self._a.inverted())
 
+ def is_separable(self):
+ return True
+ return self._a.is_separable() and self._b.is_separable()
+
+ 
 class CompositeAffine2D(Affine2DBase):
 def __init__(self, a, b):
 assert a.is_affine()
@@ -643,11 +704,32 @@
 self._b.get_matrix())
 return self._mtx
 
+ 
 def composite_transform_factory(a, b):
 if a.is_affine() and b.is_affine():
 return CompositeAffine2D(a, b)
 return CompositeGenericTransform(a, b)
+
+
+class LogTransform(Transform):
+ input_dims = 1
+ output_dims = 1
 
+ def transform(self, a):
+ m = npy.ma.masked_where(a < 0, a)
+ return npy.log10(m)
+
+
+class TestLogTransform(Transform):
+ input_dims = 2
+ output_dims = 2
+ def transform(self, xy):
+ return xy * 2
+
+ def inverted(self):
+ return self
+
+ 
 class BboxTransform(Affine2DBase):
 def __init__(self, boxin, boxout):
 assert isinstance(boxin, BboxBase)
@@ -688,6 +770,7 @@
 self._mtx = affine._mtx
 return self._mtx
 
+ 
 def nonsingular(vmin, vmax, expander=0.001, tiny=1e-15, increasing=True):
 '''
 Ensure the endpoints of a range are not too close together.
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2007年09月20日 18:00:34
Revision: 3869
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3869&view=rev
Author: mdboom
Date: 2007年09月20日 11:00:32 -0700 (2007年9月20日)
Log Message:
-----------
First baby step in getting arbitrary non-linear transformations into
the pipeline.
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/axes.py
 branches/transforms/lib/matplotlib/axis.py
 branches/transforms/lib/matplotlib/backends/backend_agg.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年09月20日 14:26:27 UTC (rev 3868)
+++ branches/transforms/lib/matplotlib/axes.py	2007年09月20日 18:00:32 UTC (rev 3869)
@@ -633,10 +633,16 @@
 self.transAxes = mtransforms.BboxTransform(
 mtransforms.Bbox.unit(), self.bbox)
 # self.set_transform(self.transAxes)
- self.transData = mtransforms.BboxTransform(
- self.viewLim, self.bbox)
+# self.transData = mtransforms.BboxTransform(
+# self.viewLim, self.bbox)
+ self.preDataTransform = mtransforms.BboxTransform(
+ self.viewLim, mtransforms.Bbox.unit())
+ self.dataTransform = mtransforms.TestLogTransform()
+ # self.dataTransform = mtransforms.Affine2D().scale(1.5)
+ self.transData = self.preDataTransform + self.dataTransform + mtransforms.BboxTransform(
+ mtransforms.Bbox.unit(), self.bbox)
+ 
 	 
-	 
 def get_position(self, original=False):
 'Return the axes rectangle left, bottom, width, height'
 if original:
Modified: branches/transforms/lib/matplotlib/axis.py
===================================================================
--- branches/transforms/lib/matplotlib/axis.py	2007年09月20日 14:26:27 UTC (rev 3868)
+++ branches/transforms/lib/matplotlib/axis.py	2007年09月20日 18:00:32 UTC (rev 3869)
@@ -1032,18 +1032,17 @@
 else:
 bbox = Bbox.union(bboxes)
 bottom = bbox.ymin
-
- self.label.set_position( (x, bottom-self.LABELPAD*self.figure.dpi / 72.0))
-
+ self.label.set_position( (x, bottom - self.LABELPAD*self.figure.dpi / 72.0))
+ 
 else:
 if not len(bboxes2):
 top = self.axes.bbox.ymax
 else:
 bbox = bbox_union(bboxes2)
 top = bbox.ymax
+ 
+ self.label.set_position( (x, top+self.LABELPAD*self.figure.dpi / 72.0))
 
- self.label.set_position( (x, top+self.LABELPAD*self.figure.dpi.get()/72.0))
-
 def _update_offset_text_position(self, bboxes, bboxes2):
 """
 Update the offset_text position based on the sequence of bounding
Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py
===================================================================
--- branches/transforms/lib/matplotlib/backends/backend_agg.py	2007年09月20日 14:26:27 UTC (rev 3868)
+++ branches/transforms/lib/matplotlib/backends/backend_agg.py	2007年09月20日 18:00:32 UTC (rev 3869)
@@ -84,7 +84,8 @@
 from matplotlib.font_manager import findfont
 from matplotlib.ft2font import FT2Font, LOAD_DEFAULT
 from matplotlib.mathtext import MathTextParser
-from matplotlib.transforms import Bbox
+from matplotlib.path import Path
+from matplotlib.transforms import Affine2D, Bbox
 
 from _backend_agg import RendererAgg as _RendererAgg
 
@@ -117,8 +118,8 @@
 				 debug=False)
 if __debug__: verbose.report('RendererAgg.__init__ _RendererAgg done',
 'debug-annoying')
- self.draw_path = self._renderer.draw_path
- self.draw_markers = self._renderer.draw_markers
+ #self.draw_path = self._renderer.draw_path
+ #self.draw_markers = self._renderer.draw_markers
 self.draw_image = self._renderer.draw_image
 self.copy_from_bbox = self._renderer.copy_from_bbox
 self.restore_region = self._renderer.restore_region
@@ -129,6 +130,17 @@
 if __debug__: verbose.report('RendererAgg.__init__ done',
 'debug-annoying')
 
+ # MGDTODO: This is a hack for now to allow for arbitrary transformations
+ def draw_path(self, gc, path, trans, rgbFace=None):
+ new_path, affine = path.transformed_without_affine(trans)
+ self._renderer.draw_path(gc, new_path, affine, rgbFace)
+
+ # MGDTODO: This is a hack for now to allow for arbitrary transformations
+ def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None):
+ assert marker_trans.is_affine()
+ new_path, affine = path.transformed_without_affine(trans)
+ self._renderer.draw_markers(gc, marker_path, marker_trans, new_path, affine, rgbFace)
+ 
 def draw_mathtext(self, gc, x, y, s, prop, angle):
 """
 Draw the math text using matplotlib.mathtext
Modified: branches/transforms/lib/matplotlib/lines.py
===================================================================
--- branches/transforms/lib/matplotlib/lines.py	2007年09月20日 14:26:27 UTC (rev 3868)
+++ branches/transforms/lib/matplotlib/lines.py	2007年09月20日 18:00:32 UTC (rev 3869)
@@ -1102,12 +1102,14 @@
 """
 return self._dashcapstyle
 
+ 
 def get_solid_capstyle(self):
 """
 Get the cap style for solid linestyles
 """
 return self._solidcapstyle
 
+ 
 def is_dashed(self):
 'return True if line is dashstyle'
 return self._linestyle in ('--', '-.', ':')
Modified: branches/transforms/lib/matplotlib/path.py
===================================================================
--- branches/transforms/lib/matplotlib/path.py	2007年09月20日 14:26:27 UTC (rev 3868)
+++ branches/transforms/lib/matplotlib/path.py	2007年09月20日 18:00:32 UTC (rev 3869)
@@ -70,6 +70,13 @@
 yield vertices[i]
 i += 1
 
+ def transformed(self, transform):
+ return Path(transform.transform(self.vertices), self.codes)
+
+ def transformed_without_affine(self, transform):
+ vertices, affine = transform.transform_without_affine(self.vertices)
+ return Path(vertices, self.codes), affine
+ 
 _unit_rectangle = None
 #@classmethod
 def unit_rectangle(cls):
Modified: branches/transforms/lib/matplotlib/text.py
===================================================================
--- branches/transforms/lib/matplotlib/text.py	2007年09月20日 14:26:27 UTC (rev 3868)
+++ branches/transforms/lib/matplotlib/text.py	2007年09月20日 18:00:32 UTC (rev 3869)
@@ -185,7 +185,8 @@
 
 xmin, ymin = thisx, thisy
 lines = self._text.split('\n')
- 
+
+ # MGDTODO: whs could be a numpy.array
 whs = []
 # Find full vertical extent of font,
 # including ascenders and descenders:
@@ -260,27 +261,21 @@
 else: offsety = ty - ymin
 
 xmin += offsetx
- xmax += offsetx
 ymin += offsety
- ymax += offsety
 
 bbox = Bbox.from_lbwh(xmin, ymin, width, height)
 
-	
-
 # now rotate the positions around the first x,y position
 xys = M.transform(offsetLayout)
-	tx = xys[:, 0]
-	ty = xys[:, 1]
-	tx += offsetx
-	ty += offsety
+ xys[:, 0] += offsetx
+ xys[:, 1] += offsety
 
 # now inverse transform back to data coords
 	inverse_transform = self.get_transform().inverted()
 xys = inverse_transform.transform(xys)
 
- xs, ys = zip(*xys)
-
+ xs, ys = xys[:, 0], xys[:, 1]
+ 
 ret = bbox, zip(lines, whs, xs, ys)
 self.cached[key] = ret
 return ret
@@ -331,15 +326,15 @@
 
 for line, wh, x, y in info:
 x, y = trans.transform_point((x, y))
-
+ 
 if renderer.flipy():
 canvasw, canvash = renderer.get_canvas_width_height()
 y = canvash-y
-
+ 
 renderer.draw_text(gc, x, y, line,
 self._fontproperties, angle,
 ismath=self.is_math_text(line))
-
+ 
 def get_color(self):
 "Return the color of the text"
 return self._color
@@ -407,7 +402,9 @@
 return (x, y, self._text, self._color,
 self._verticalalignment, self._horizontalalignment,
 hash(self._fontproperties), self._rotation,
- self.get_transform(),
+ # MGDTODO: Find a better way to determine if the
+ # transform as changed
+ str(self.get_transform())
 )
 
 def get_text(self):
Modified: branches/transforms/lib/matplotlib/transforms.py
===================================================================
--- branches/transforms/lib/matplotlib/transforms.py	2007年09月20日 14:26:27 UTC (rev 3868)
+++ branches/transforms/lib/matplotlib/transforms.py	2007年09月20日 18:00:32 UTC (rev 3869)
@@ -256,10 +256,10 @@
 self.invalidate()
 
 def transformed(self, transform):
- return Bbox(transform(self._points))
+ return Bbox(transform.transform(self._points))
 
 def inverse_transformed(self, transform):
- return Bbox(transform.inverted()(self._points))
+ return Bbox(transform.inverted().transform(self._points))
 
 def expanded(self, sw, sh):
 width = self.width
@@ -408,13 +408,13 @@
 # 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
+# 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()
@@ -563,6 +563,10 @@
 self._y = y_transform
 self.set_children(['_x', '_y'])
 
+ def __repr__(self):
+ return "BlendedGenericTransform(%s,%s)" % (self._x, self._y)
+ __str__ = __repr__
+ 
 def transform(self, points):
 # MGDTODO: Optimize the case where one of these is
 # an affine
@@ -590,28 +594,6 @@
 return True
 
 
-class BlendedSeparableTransform(Transform):
- input_dims = 2
- output_dims = 2
-
- def __init__(self, x_transform, y_transform):
-	# Here we ask: "Does it blend?"
- assert x_transform.is_separable()
- assert y_transform.is_separable()
- assert x_transform.input_dims == x.transform.output_dims == 1
- assert y_transform.input_dims == y.transform.output_dims == 1
- 
- Transform.__init__(self)
- self._x = x_transform
- self._y = y_transform
- self.set_children(['_x', '_y'])
-
- def transform(self, points):
- x_points = self._x(points[:, 0])
- y_points = self._y(points[:, 1])
- return npy.vstack((x_points[:, 0:1], y_points[:, 1:2])).transpose()
- 
- 
 class BlendedAffine2D(Affine2DBase, Transform):
 def __init__(self, x_transform, y_transform):
 assert x_transform.is_affine()
@@ -666,6 +648,10 @@
 self._a = a
 self._b = b
 self.set_children(['_a', '_b'])
+
+ def __repr__(self):
+ return "CompositeGenericTransform(%s, %s)" % (self._a, self._b)
+ __str__ = __repr__
 
 def transform(self, points):
 return self._b.transform(self._a.transform(points))
@@ -724,10 +710,21 @@
 input_dims = 2
 output_dims = 2
 def transform(self, xy):
- return xy * 2
+ marray = npy.ma.masked_where(xy <= 0.0, xy * 10.0)
+ return npy.log10(marray)
+ 
+ def inverted(self):
+ return TestInvertLogTransform()
 
+
+class TestInvertLogTransform(Transform):
+ input_dims = 2
+ output_dims = 2
+ def transform(self, xy):
+ return npy.power(10, xy) / 10.0
+ 
 def inverted(self):
- return self
+ return TestLogTransform()
 
 
 class BboxTransform(Affine2DBase):
@@ -825,7 +822,7 @@
 
 assert bbox.bounds == (10, 15, 10, 10)
 
- print npy.asarray(bbox)
+ assert tuple(npy.asarray(bbox).flatten()) == (10, 15, 20, 25)
 
 bbox.intervalx = (11, 21)
 bbox.intervaly = (16, 26)
@@ -859,29 +856,35 @@
 scale = Affine2D().scale(10, 20)
 assert scale.to_values() == (10, 0, 0, 20, 0, 0)
 rotation = Affine2D().rotate_deg(30)
- print rotation.to_values() == (0.86602540378443871, 0.49999999999999994,
+ assert rotation.to_values() == (0.86602540378443871, 0.49999999999999994,
 -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)
+ translated_points = translation.transform(points)
 assert (translated_points == [[11., 22.], [13., 24.], [15., 26.], [17., 28.]]).all()
- scaled_points = scale(points)
+ scaled_points = scale.transform(points)
 print scaled_points
- rotated_points = rotation(points)
+ rotated_points = rotation.transform(points)
 print rotated_points
 
- tpoints1 = rotation(translation(scale(points)))
+ tpoints1 = rotation.transform(translation.transform(scale.transform(points)))
 trans_sum = scale + translation + rotation
- tpoints2 = trans_sum(points)
- print tpoints1, tpoints2
- print tpoints1 == tpoints2
+ tpoints2 = trans_sum.transform(points)
 # Need to do some sort of fuzzy comparison here?
- # assert (tpoints1 == tpoints2).all()
+ assert (tpoints1.round() == tpoints2.round()).all()
 
+ print points
+ 
+ comp = TestLogTransform() + Affine2D().rotate_deg(15)
+ tpoints = comp.transform(points)
+ itpoints = comp.inverted().transform(tpoints)
+ print tpoints, itpoints
+ assert (points.round() == itpoints.round()).all()
+ 
 # Here are some timing tests
 points = npy.asarray([(random(), random()) for i in xrange(10000)])
- t = timeit.Timer("trans_sum(points)", "from __main__ import trans_sum, points")
+ t = timeit.Timer("trans_sum.transform(points)", "from __main__ import trans_sum, points")
 print "Time to transform 10000 x 10 points:", t.timeit(10)
 
 __all__ = ['Transform', 'Affine2D']
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2007年09月21日 16:52:54
Revision: 3872
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3872&view=rev
Author: mdboom
Date: 2007年09月21日 09:52:50 -0700 (2007年9月21日)
Log Message:
-----------
Further progress on arbitrary transformations -- zooming and panning
now works without any log-scale-specific hacks. (Though the
underlying model is slightly wrong.)
Added graphviz output support for debugging transformation trees.
Masked array handling much more robust.
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/axes.py
 branches/transforms/lib/matplotlib/backend_bases.py
 branches/transforms/lib/matplotlib/lines.py
 branches/transforms/lib/matplotlib/path.py
 branches/transforms/lib/matplotlib/transforms.py
Modified: branches/transforms/lib/matplotlib/axes.py
===================================================================
--- branches/transforms/lib/matplotlib/axes.py	2007年09月21日 15:33:18 UTC (rev 3871)
+++ branches/transforms/lib/matplotlib/axes.py	2007年09月21日 16:52:50 UTC (rev 3872)
@@ -637,10 +637,14 @@
 # self.viewLim, self.bbox)
 self.preDataTransform = mtransforms.BboxTransform(
 self.viewLim, mtransforms.Bbox.unit())
- self.dataTransform = mtransforms.TestLogTransform()
- # self.dataTransform = mtransforms.Affine2D().scale(1.5)
+# self.dataTransform = mtransforms.TestPolarTransform()
+# self.dataTransform = mtransforms.blended_transform_factory(
+# mtransforms.TestLogTransform(),
+# mtransforms.Affine2D())
+ self.dataTransform = mtransforms.Affine2D()
 self.transData = self.preDataTransform + self.dataTransform + mtransforms.BboxTransform(
 mtransforms.Bbox.unit(), self.bbox)
+ self.transData.make_graphviz(open("trans.dot", "w"))
 
 	 
 def get_position(self, original=False):
@@ -1523,7 +1527,7 @@
 'return the xaxis scale string: log or linear'
 	# MGDTODO
 # return self.scaled[self.transData.get_funcx().get_type()]
-	return 'linear'
+	return 'log'
 
 def set_xscale(self, value, basex = 10, subsx=None):
 """
Modified: branches/transforms/lib/matplotlib/backend_bases.py
===================================================================
--- branches/transforms/lib/matplotlib/backend_bases.py	2007年09月21日 15:33:18 UTC (rev 3871)
+++ branches/transforms/lib/matplotlib/backend_bases.py	2007年09月21日 16:52:50 UTC (rev 3872)
@@ -1655,60 +1655,30 @@
 #multiple button can get pressed during motion...
 if self._button_pressed==1:
 		inverse = trans.inverted()
- lastx, lasty = inverse.transform_point((lastx, lasty))
- x, y = inverse.transform_point( (event.x, event.y) )
- if a.get_xscale()=='log':
- dx=1-lastx/x
- else:
- dx=x-lastx
- if a.get_yscale()=='log':
- dy=1-lasty/y
- else:
- dy=y-lasty
-
- dx,dy=format_deltas(event,dx,dy)
-
- if a.get_xscale()=='log':
- xmin *= 1-dx
- xmax *= 1-dx
- else:
- xmin -= dx
- xmax -= dx
- if a.get_yscale()=='log':
- ymin *= 1-dy
- ymax *= 1-dy
- else:
- ymin -= dy
- ymax -= dy
+ dx, dy = event.x - lastx, event.y - lasty
+ dx, dy = format_deltas(event, dx, dy)
+ delta = npy.array([[dx, dy], [dx, dy]], npy.float_)
+ bbox = transforms.Bbox(a.bbox.get_points() - delta)
+ result = bbox.transformed(inverse)
 elif self._button_pressed==3:
 try:
+ inverse = trans.inverted()
 dx=(lastx-event.x)/float(a.bbox.width)
 dy=(lasty-event.y)/float(a.bbox.height)
- dx,dy=format_deltas(event,dx,dy)
- if a.get_aspect() != 'auto':
- dx = 0.5*(dx + dy)
- dy = dx
- alphax = pow(10.0,dx)
- alphay = pow(10.0,dy)#use logscaling, avoid singularities and smother scaling...
-		 inverse = trans.inverted()
- lastx, lasty = inverse.transform_point( (lastx, lasty) )
- if a.get_xscale()=='log':
- xmin = lastx*(xmin/lastx)**alphax
- xmax = lastx*(xmax/lastx)**alphax
- else:
- xmin = lastx+alphax*(xmin-lastx)
- xmax = lastx+alphax*(xmax-lastx)
- if a.get_yscale()=='log':
- ymin = lasty*(ymin/lasty)**alphay
- ymax = lasty*(ymax/lasty)**alphay
- else:
- ymin = lasty+alphay*(ymin-lasty)
- ymax = lasty+alphay*(ymax-lasty)
+ alphax = pow(10.0, dx)
+ alphay = pow(10.0, dy)
+ # MGDTODO: Make better use of numpy
+ lastx, lasty = inverse.transform_point((lastx, lasty))
+ xmin = (lastx + alphax * (xmin - lastx))
+ xmax = (lastx + alphax * (xmax - lastx))
+ ymin = (lasty + alphay * (ymin - lasty))
+ ymax = (lasty + alphay * (ymax - lasty))
+ result = transforms.Bbox.from_lbrt(xmin, ymin, xmax, ymax)
 except OverflowError:
 warnings.warn('Overflow while panning')
 return
- a.set_xlim(xmin, xmax)
- a.set_ylim(ymin, ymax)
+ a.set_xlim(*result.intervalx)
+ a.set_ylim(*result.intervaly)
 
 self.dynamic_update()
 
Modified: branches/transforms/lib/matplotlib/lines.py
===================================================================
--- branches/transforms/lib/matplotlib/lines.py	2007年09月21日 15:33:18 UTC (rev 3871)
+++ branches/transforms/lib/matplotlib/lines.py	2007年09月21日 16:52:50 UTC (rev 3872)
@@ -25,6 +25,53 @@
 (TICKLEFT, TICKRIGHT, TICKUP, TICKDOWN,
 CARETLEFT, CARETRIGHT, CARETUP, CARETDOWN) = range(8)
 
+def unmasked_index_ranges(mask, compressed = True):
+ '''
+ Calculate the good data ranges in a masked 1-D npy.array, based on mask.
+
+ Returns Nx2 npy.array with each row the start and stop indices
+ for slices of the compressed npy.array corresponding to each of N
+ uninterrupted runs of unmasked values.
+ If optional argument compressed is False, it returns the
+ start and stop indices into the original npy.array, not the
+ compressed npy.array.
+ Returns None if there are no unmasked values.
+
+ Example:
+
+ y = ma.array(npy.arange(5), mask = [0,0,1,0,0])
+ #ii = unmasked_index_ranges(y.mask())
+ ii = unmasked_index_ranges(ma.getmask(y))
+ # returns [[0,2,] [2,4,]]
+
+ y.compressed().filled()[ii[1,0]:ii[1,1]]
+ # returns npy.array [3,4,]
+ # (The 'filled()' method converts the masked npy.array to a numerix npy.array.)
+
+ #i0, i1 = unmasked_index_ranges(y.mask(), compressed=False)
+ i0, i1 = unmasked_index_ranges(ma.getmask(y), compressed=False)
+ # returns [[0,3,] [2,5,]]
+
+ y.filled()[ii[1,0]:ii[1,1]]
+ # returns npy.array [3,4,]
+
+ '''
+ m = npy.concatenate(((1,), mask, (1,)))
+ indices = npy.arange(len(mask) + 1)
+ mdif = m[1:] - m[:-1]
+ i0 = npy.compress(mdif == -1, indices)
+ i1 = npy.compress(mdif == 1, indices)
+ assert len(i0) == len(i1)
+ if len(i1) == 0:
+ return None
+ if not compressed:
+ return npy.concatenate((i0[:, npy.newaxis], i1[:, npy.newaxis]), axis=1)
+ seglengths = i1 - i0
+ breakpoints = npy.cumsum(seglengths)
+ ic0 = npy.concatenate(((0,), breakpoints[:-1]))
+ ic1 = breakpoints
+ return npy.concatenate((ic0[:, npy.newaxis], ic1[:, npy.newaxis]), axis=1)
+
 def segment_hits(cx,cy,x,y,radius):
 """Determine if any line segments are within radius of a point. Returns
 the list of line segments that are within that radius.
@@ -302,7 +349,7 @@
 self._picker = p
 
 def get_window_extent(self, renderer):
- xy = self.get_transform()(self._xy)
+ xy = self.get_transform().transform(self._xy)
 
 	x = xy[:, 0]
 	y = xy[:, 1]
@@ -343,9 +390,6 @@
 self._yorig = y
 self.recache()
 
- # MGDTODO: Masked data arrays are broken
- _masked_array_to_path_code_mapping = npy.array(
- [Path.LINETO, Path.MOVETO, Path.MOVETO], Path.code_type)
 def recache(self):
 #if self.axes is None: print 'recache no axes'
 #else: print 'recache units', self.axes.xaxis.units, self.axes.yaxis.units
@@ -363,24 +407,15 @@
 if len(x) != len(y):
 raise RuntimeError('xdata and ydata must be the same length')
 
-	self._xy = npy.vstack((npy.asarray(x, npy.float_),
-			 npy.asarray(y, npy.float_))).transpose()
+ x = x.reshape((len(x), 1))
+ y = y.reshape((len(y), 1))
+ 
+	self._xy = ma.concatenate((x, y), 1)
 	self._x = self._xy[:, 0] # just a view
 	self._y = self._xy[:, 1] # just a view
 self._logcache = None
-
- mx = ma.getmask(x)
- my = ma.getmask(y)
- mask = ma.mask_or(mx, my)
- codes = None
- if mask is not ma.nomask:
- m = npy.concatenate(((1,), mask, (1,)))
- mdif = m[1:] - m[:-1]
- mdif = npy.maximum((mdif[:-1] * -2), mask)
- codes = npy.take(
- self._masked_array_to_path_code_mapping,
- mdif)
- self._path = Path(self._xy, codes, closed=False)
+ # Masked arrays are now handled by the Path class itself
+ self._path = Path(self._xy, closed=False)
 # MGDTODO: If _draw_steps is removed, remove the following line also
 self._step_path = None
 
Modified: branches/transforms/lib/matplotlib/path.py
===================================================================
--- branches/transforms/lib/matplotlib/path.py	2007年09月21日 15:33:18 UTC (rev 3871)
+++ branches/transforms/lib/matplotlib/path.py	2007年09月21日 16:52:50 UTC (rev 3872)
@@ -1,4 +1,5 @@
 import numpy as npy
+from numpy import ma as ma
 
 class Path(object):
 # Path codes
@@ -21,10 +22,8 @@
 code_type = npy.uint8
 
 def __init__(self, vertices, codes=None, closed=True):
- vertices = npy.asarray(vertices, npy.float_)
-	assert vertices.ndim == 2
-	assert vertices.shape[1] == 2
- 
+ vertices = ma.asarray(vertices, npy.float_)
+
 	if codes is None:
 	 if closed:
 		codes = self.LINETO * npy.ones(
@@ -41,10 +40,27 @@
 assert codes.ndim == 1
 assert len(codes) == len(vertices)
 
+ # The path being passed in may have masked values. However,
+ # the backends are not expected to deal with masked arrays, so
+ # we must remove them from the array (using compressed), and
+ # add MOVETO commands to the codes array accordingly.
+ mask = ma.getmask(vertices)
+ if mask is not ma.nomask:
+ mask1d = ma.mask_or(mask[:, 0], mask[:, 1])
+ vertices = ma.compress(npy.invert(mask1d), vertices, 0)
+ codes = npy.where(npy.concatenate((mask1d[-1:], mask1d[:-1])),
+ self.MOVETO, codes)
+ codes = ma.masked_array(codes, mask=mask1d).compressed()
+ codes = npy.asarray(codes, self.code_type)
+
+ vertices = npy.asarray(vertices, npy.float_)
+
+ assert vertices.ndim == 2
+ assert vertices.shape[1] == 2
+	assert codes.ndim == 1
+ 
 self._codes = codes
 	self._vertices = vertices
- 
-	assert self._codes.ndim == 1
 
 def __repr__(self):
 	return "Path(%s, %s)" % (self.vertices, self.codes)
@@ -91,10 +107,11 @@
 def unit_regular_polygon(cls, numVertices):
 	path = cls._unit_regular_polygons.get(numVertices)
 	if path is None:
-	 theta = 2*npy.pi/numVertices * npy.arange(numVertices)
-	 # This is to make sure the polygon always "points-up"
+	 theta = 2*npy.pi/numVertices * npy.arange(numVertices).reshape((numVertices, 1))
+	 # This initial rotation is to make sure the polygon always
+ # "points-up"
 	 theta += npy.pi / 2.0
-	 verts = npy.vstack((npy.cos(theta), npy.sin(theta))).transpose()
+	 verts = npy.concatenate((npy.cos(theta), npy.sin(theta)))
 	 path = Path(verts)
 	 cls._unit_regular_polygons[numVertices] = path
 	return path
Modified: branches/transforms/lib/matplotlib/transforms.py
===================================================================
--- branches/transforms/lib/matplotlib/transforms.py	2007年09月21日 15:33:18 UTC (rev 3871)
+++ branches/transforms/lib/matplotlib/transforms.py	2007年09月21日 16:52:50 UTC (rev 3872)
@@ -5,6 +5,7 @@
 """
 
 import numpy as npy
+from numpy import ma as ma
 from numpy.linalg import inv
 from sets import Set
 
@@ -19,6 +20,7 @@
 class TransformNode(object):
 def __init__(self):
 self._parents = Set()
+ self._children = []
 
 def invalidate(self):
 self._do_invalidation()
@@ -33,7 +35,34 @@
 getattr(self, child)._parents.add(self)
 self._children = children
 
+ def make_graphviz(self, fobj):
+ def recurse(root):
+ fobj.write('%s [label="%s"];\n' %
+ (hash(root), root.__class__.__name__))
+ if isinstance(root, Affine2DBase):
+ fobj.write('%s [style=filled, color=".7 .7 .9"];\n' %
+ hash(root))
+ elif isinstance(root, BboxBase):
+ fobj.write('%s [style=filled, color=".9 .9 .7"];\n' %
+ hash(root))
+ for child_name in root._children:
+ child = getattr(root, child_name)
+ fobj.write("%s -> %s;\n" % (
+ hash(root),
+ hash(child)))
+ recurse(child)
 
+ fobj.write("digraph G {\n")
+ recurse(self)
+ fobj.write("}\n")
+ 
+ def is_affine(self):
+ return isinstance(self, Affine2DBase)
+
+ def is_bbox(self):
+ return isinstance(self, BboxBase)
+ 
+ 
 class BboxBase(TransformNode):
 '''
 This is the read-only part of a bounding-box
@@ -169,12 +198,6 @@
 return Bbox(points)
 from_lbrt = staticmethod(from_lbrt)
 
- def __copy__(self):
- return Bbox(self._points.copy())
-
- def __deepcopy__(self, memo):
- return Bbox(self._points.copy())
- 
 def __cmp__(self, other):
 # MGDTODO: Totally suboptimal
 if isinstance(other, Bbox) and (self._points == other._points).all():
@@ -274,6 +297,8 @@
 """
 Return the Bbox that bounds all bboxes
 """
+ # MGDTODO: There's got to be a way to utilize numpy here
+ # to make this faster...
 assert(len(bboxes))
 
 if len(bboxes) == 1:
@@ -297,7 +322,7 @@
 
 class TransformedBbox(BboxBase):
 def __init__(self, bbox, transform):
- assert isinstance(bbox, Bbox)
+ assert bbox.is_bbox()
 assert isinstance(transform, Transform)
 
 BboxBase.__init__(self)
@@ -353,9 +378,6 @@
 def is_separable(self):
 return False
 
- def is_affine(self):
- return False
-
 
 class Affine2DBase(Transform):
 input_dims = 2
@@ -416,9 +438,9 @@
 # print "".join(traceback.format_stack())
 # print points
 mtx = self.get_matrix()
- points = npy.asarray(points, npy.float_)
+ points = ma.asarray(points, npy.float_)
 points = points.transpose()
- points = npy.dot(mtx[0:2, 0:2], points)
+ points = ma.dot(mtx[0:2, 0:2], points)
 points = points + mtx[0:2, 2:]
 return points.transpose()
 
@@ -437,9 +459,6 @@
 mtx = self.get_matrix()
 return mtx[0, 1] == 0.0 and mtx[1, 0] == 0.0
 
- def is_affine(self):
- return True
-
 
 class Affine2D(Affine2DBase):
 def __init__(self, matrix = None):
@@ -469,12 +488,6 @@
 return 0
 return -1
 
- def __copy__(self):
- return Affine2D(self._mtx.copy())
- 
- def __deepcopy__(self, memo):
- return Affine2D(self._mtx.copy())
- 
 #@staticmethod
 def from_values(a, b, c, d, e, f):
 return Affine2D(Affine2D.matrix_from_values(a, b, c, d, e, f))
@@ -542,9 +555,31 @@
 mtx = self.get_matrix()
 return mtx[0, 1] == 0.0 and mtx[1, 0] == 0.0
 
- def is_affine(self):
- return True
 
+class IdentityTransform(Affine2DBase):
+ """
+ A special class that does the identity transform quickly.
+ """
+ _mtx = npy.identity(3)
+
+ def __cmp__(self, other):
+ if (isinstance(other, Affine2D) and
+ (other == IDENTITY)):
+ return 0
+ return -1
+
+ def get_matrix(self):
+ return _mtx
+ 
+ def transform(self, points):
+ return points
+
+ def transform_without_affine(self, points):
+ return points, self
+
+ def inverted(self):
+ return self
+ 
 IDENTITY = Affine2D()
 
 class BlendedGenericTransform(Transform):
@@ -553,10 +588,9 @@
 
 def __init__(self, x_transform, y_transform):
 	# Here we ask: "Does it blend?"
- assert x_transform.is_separable()
- assert y_transform.is_separable()
- assert x_transform.input_dims == x_transform.output_dims == 2
- assert y_transform.input_dims == y_transform.output_dims == 2
+ # MGDTODO: Turn these checks back on
+ # assert x_transform.is_separable()
+ # assert y_transform.is_separable()
 
 Transform.__init__(self)
 self._x = x_transform
@@ -576,16 +610,18 @@
 return self._x(points)
 
 if x.input_dims == 2:
- x_points = x.transform(points)[:, 0]
+ x_points = x.transform(points)[:, 0:1]
 else:
 x_points = x.transform(points[:, 0])
-
+ x_points = x_points.reshape((len(x_points), 1))
+ 
 if y.input_dims == 2:
- y_points = y.transform(points)[:, 1]
+ y_points = y.transform(points)[:, 1:]
 else:
 y_points = y.transform(points[:, 1])
+ y_points = y_points.reshape((len(y_points), 1))
 
- return npy.vstack((x_points, y_points)).transpose()
+ return ma.concatenate((x_points, y_points), 1)
 
 def inverted(self):
 return BlendedGenericTransform(self._x.inverted(), self._y.inverted())
@@ -598,6 +634,9 @@
 def __init__(self, x_transform, y_transform):
 assert x_transform.is_affine()
 assert y_transform.is_affine()
+ # MGDTODO: Turn these checks back on
+ # assert x_transform.is_separable()
+ # assert y_transform.is_separable()
 Transform.__init__(self)
 self._x = x_transform
 self._y = y_transform
@@ -649,6 +688,8 @@
 self._b = b
 self.set_children(['_a', '_b'])
 
+ self.take_shortcut = b.is_affine()
+
 def __repr__(self):
 return "CompositeGenericTransform(%s, %s)" % (self._a, self._b)
 __str__ = __repr__
@@ -656,11 +697,15 @@
 def transform(self, points):
 return self._b.transform(self._a.transform(points))
 
+ def transform_without_affine(self, points):
+ if self.take_shortcut:
+ return self._a.transform(points), self._b
+ return self.transform(points), IDENTITY
+ 
 def inverted(self):
 return CompositeGenericTransform(self._b.inverted(), self._a.inverted())
 
 def is_separable(self):
- return True
 return self._a.is_separable() and self._b.is_separable()
 
 
@@ -702,35 +747,81 @@
 output_dims = 1
 
 def transform(self, a):
- m = npy.ma.masked_where(a < 0, a)
+ m = ma.masked_where(a < 0, a)
 return npy.log10(m)
 
 
 class TestLogTransform(Transform):
- input_dims = 2
- output_dims = 2
+ input_dims = 1
+ output_dims = 1
 def transform(self, xy):
- marray = npy.ma.masked_where(xy <= 0.0, xy * 10.0)
- return npy.log10(marray)
+ marray = ma.masked_where(xy <= 0.0, xy * 10.0)
+ return (npy.log10(marray) * 0.5) + 0.5
 
 def inverted(self):
 return TestInvertLogTransform()
 
+ def is_separable(self):
+ return True
+ 
 
 class TestInvertLogTransform(Transform):
- input_dims = 2
- output_dims = 2
+ input_dims = 1
+ output_dims = 1
 def transform(self, xy):
- return npy.power(10, xy) / 10.0
+ return ma.power(10, (xy - 0.5) * 2.0) / 10.0
 
 def inverted(self):
 return TestLogTransform()
 
+ def is_separable(self):
+ return True
+
+
+class TestPolarTransform(Transform):
+ input_dims = 2
+ output_dims = 2
+
+ def transform(self, xy):
+ debug = len(xy) > 4
+ x = xy[:, 0:1]
+ y = xy[:, 1:]
+ x, y = ((y * npy.cos(x)) + 1.0) * 0.5, ((y * npy.sin(x)) + 1.0) * 0.5
+ if debug:
+ print npy.min(xy[:, 0:1]), npy.max(xy[:, 0:1]), npy.min(xy[:, 1:]), npy.max(xy[:, 1:])
+ print x.min(), x.max(), y.min(), y.max()
+ return ma.concatenate((x, y), 1)
+
+ def inverted(self):
+ return TestInvertPolarTransform()
 
+ def is_separable(self):
+ return False
+
+
+class TestInvertPolarTransform(Transform):
+ input_dims = 2
+ output_dims = 2
+
+ def transform(self, xy):
+ x = xy[:, 0:1]
+ y = xy[:, 1:]
+ r = ma.sqrt(ma.power(x, 2) + ma.power(y, 2))
+ theta = ma.arccos(x / r)
+ theta = ma.where(y < 0, 2 * npy.pi - theta, theta)
+ return ma.concatenate((theta / (npy.pi * 2), r), 1)
+
+ def inverted(self):
+ return TestInvertPolarTransform()
+ 
+ def is_separable(self):
+ return False
+ 
+ 
 class BboxTransform(Affine2DBase):
 def __init__(self, boxin, boxout):
- assert isinstance(boxin, BboxBase)
- assert isinstance(boxout, BboxBase)
+ assert boxin.is_bbox()
+ assert boxout.is_bbox()
 
 Affine2DBase.__init__(self)
 self._boxin = boxin
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2007年09月24日 16:53:40
Revision: 3884
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3884&view=rev
Author: mdboom
Date: 2007年09月24日 09:53:38 -0700 (2007年9月24日)
Log Message:
-----------
More progress. (Kind of a broken mess at the moment.)
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/axes.py
 branches/transforms/lib/matplotlib/axis.py
 branches/transforms/lib/matplotlib/ticker.py
 branches/transforms/lib/matplotlib/transforms.py
Added Paths:
-----------
 branches/transforms/lib/matplotlib/scale.py
Modified: branches/transforms/lib/matplotlib/axes.py
===================================================================
--- branches/transforms/lib/matplotlib/axes.py	2007年09月24日 15:11:58 UTC (rev 3883)
+++ branches/transforms/lib/matplotlib/axes.py	2007年09月24日 16:53:38 UTC (rev 3884)
@@ -25,6 +25,7 @@
 from matplotlib import patches as mpatches
 from matplotlib import pbox as mpbox
 from matplotlib import quiver as mquiver
+from matplotlib import scale as mscale
 from matplotlib import table as mtable
 from matplotlib import text as mtext
 from matplotlib import ticker as mticker
@@ -449,7 +450,6 @@
 **kwargs
 ):
 """
-
 Build an Axes instance in Figure with
 rect=[left, bottom, width,height in Figure coords
 
@@ -467,8 +467,8 @@
 navigate: True|False
 navigate_mode: the navigation toolbar button status: 'PAN', 'ZOOM', or None
 position: [left, bottom, width,height in Figure coords
- sharex : an Axes instance to share the x-axis with
- sharey : an Axes instance to share the y-axis with
+ sharex: an Axes instance to share the x-axis with
+ sharey: an Axes instance to share the y-axis with
 title: the title string
 visible: a boolean - whether the axes is visible
 xlabel: the xlabel
@@ -491,7 +491,7 @@
 self.set_adjustable('box')
 self.set_anchor('C')
 
- # must be set before set_figure
+ # MGDTODO: Check that the axes being shared are scalable
 self._sharex = sharex
 self._sharey = sharey
 	if sharex is not None:
@@ -508,7 +508,7 @@
 
 # this call may differ for non-sep axes, eg polar
 self._init_axis()
-
+ 
 if axisbg is None: axisbg = rcParams['axes.facecolor']
 self._axisbg = axisbg
 self._frameon = frameon
@@ -545,8 +545,8 @@
 "move this out of __init__ because non-separable axes don't use it"
 self.xaxis = maxis.XAxis(self)
 self.yaxis = maxis.YAxis(self)
+ self._update_transAxisXY()
 
-
 def sharex_foreign(self, axforeign):
 """
 You can share your x-axis view limits with another Axes in the
@@ -627,26 +627,17 @@
 set the dataLim and viewLim BBox attributes and the
 transData and transAxes Transformation attributes
 """
-	self.viewLim = mtransforms.Bbox.unit()
 	self.dataLim = mtransforms.Bbox.unit()
-	
+ self.viewLim = mtransforms.Bbox.unit()
 self.transAxes = mtransforms.BboxTransform(
 mtransforms.Bbox.unit(), self.bbox)
- # self.set_transform(self.transAxes)
-# self.transData = mtransforms.BboxTransform(
-# self.viewLim, self.bbox)
- self.preDataTransform = mtransforms.BboxTransform(
- self.viewLim, mtransforms.Bbox.unit())
-# self.dataTransform = mtransforms.TestPolarTransform()
-# self.dataTransform = mtransforms.blended_transform_factory(
-# mtransforms.TestLogTransform(),
-# mtransforms.Affine2D())
- self.dataTransform = mtransforms.Affine2D()
- self.transData = self.preDataTransform + self.dataTransform + mtransforms.BboxTransform(
- mtransforms.Bbox.unit(), self.bbox)
- self.transData.make_graphviz(open("trans.dot", "w"))
+ self.transAxisXY = mtransforms.TransformWrapper()
+ self.transData = self.transAxisXY + self.transAxes
+
+ def _update_transAxisXY(self):
+ self.transAxisXY.set(mtransforms.blended_transform_factory(
+ self.xaxis.get_transform(), self.yaxis.get_transform()))
 
-	 
 def get_position(self, original=False):
 'Return the axes rectangle left, bottom, width, height'
 if original:
@@ -1525,11 +1516,9 @@
 
 def get_xscale(self):
 'return the xaxis scale string: log or linear'
-	# MGDTODO
- # return self.scaled[self.transData.get_funcx().get_type()]
-	return 'log'
+	return self.xaxis.get_scale()
 
- def set_xscale(self, value, basex = 10, subsx=None):
+ def set_xscale(self, value, **kwargs):
 """
 SET_XSCALE(value, basex=10, subsx=None)
 
@@ -1547,27 +1536,9 @@
 
 ACCEPTS: ['log' | 'linear' ]
 """
-
- #if subsx is None: subsx = range(2, basex)
- assert(value.lower() in ('log', 'linear', ))
- if value == 'log':
-	 # MGDTODO
-# self.xaxis.set_major_locator(mticker.LogLocator(basex))
-# self.xaxis.set_major_formatter(mticker.LogFormatterMathtext(basex))
-# self.xaxis.set_minor_locator(mticker.LogLocator(basex,subsx))
-# self.transData.get_funcx().set_type(mtrans.LOG10)
-# minx, maxx = self.get_xlim()
-# if min(minx, maxx)<=0:
-# self.autoscale_view()
-	 pass
- elif value == 'linear':
- self.xaxis.set_major_locator(mticker.AutoLocator())
- self.xaxis.set_major_formatter(mticker.ScalarFormatter())
- self.xaxis.set_minor_locator(mticker.NullLocator())
- self.xaxis.set_minor_formatter(mticker.NullFormatter())
- # self.transData.get_funcx().set_type( mtrans.IDENTITY )
-	 self.transData.get_funcx().set_type( 0 ) # MGDTODO
-
+ self.xaxis.set_scale(value, **kwargs)
+ self._update_transAxisXY()
+ 
 def get_xticks(self):
 'Return the x ticks as a list of locations'
 return self.xaxis.get_ticklocs()
@@ -1655,9 +1626,8 @@
 
 def get_yscale(self):
 'return the yaxis scale string: log or linear'
- # return self.scaled[self.transData.get_funcy().get_type()]
-	return 'linear'
-
+ return self.yaxis.get_scale()
+ 
 def set_yscale(self, value, basey=10, subsy=None):
 """
 SET_YSCALE(value, basey=10, subsy=None)
@@ -1676,29 +1646,9 @@
 
 ACCEPTS: ['log' | 'linear']
 """
-
- #if subsy is None: subsy = range(2, basey)
- assert(value.lower() in ('log', 'linear', ))
-
- if value == 'log':
-	 # MGDTODO
-# self.yaxis.set_major_locator(mticker.LogLocator(basey))
-# self.yaxis.set_major_formatter(mticker.LogFormatterMathtext(basey))
-# self.yaxis.set_minor_locator(mticker.LogLocator(basey,subsy))
-# self.transData.get_funcy().set_type(mtrans.LOG10)
-# miny, maxy = self.get_ylim()
-# if min(miny, maxy)<=0:
-# self.autoscale_view()
-	 pass
-	 
- elif value == 'linear':
- self.yaxis.set_major_locator(mticker.AutoLocator())
- self.yaxis.set_major_formatter(mticker.ScalarFormatter())
- self.yaxis.set_minor_locator(mticker.NullLocator())
- self.yaxis.set_minor_formatter(mticker.NullFormatter())
- # self.transData.get_funcy().set_type( mtrans.IDENTITY ) MGDTODO
- self.transData.get_funcy().set_type( 0 )
-	 
+ self.yaxis.set_scale(value, basey, subsy)
+ self._update_transAxisXY()
+ 
 def get_yticks(self):
 'Return the y ticks as a list of locations'
 return self.yaxis.get_ticklocs()
Modified: branches/transforms/lib/matplotlib/axis.py
===================================================================
--- branches/transforms/lib/matplotlib/axis.py	2007年09月24日 15:11:58 UTC (rev 3883)
+++ branches/transforms/lib/matplotlib/axis.py	2007年09月24日 16:53:38 UTC (rev 3884)
@@ -12,14 +12,15 @@
 from lines import Line2D, TICKLEFT, TICKRIGHT, TICKUP, TICKDOWN
 from matplotlib import rcParams
 from patches import bbox_artist
-from ticker import NullFormatter, FixedFormatter, ScalarFormatter, LogFormatter
+from ticker import NullFormatter, FixedFormatter, ScalarFormatter, LogFormatter, LogFormatterMathtext
 from ticker import NullLocator, FixedLocator, LinearLocator, LogLocator, AutoLocator
 
 from font_manager import FontProperties
 from text import Text, TextWithDash, _process_text_args
 from transforms import Affine2D, Bbox, blended_transform_factory, interval_contains, \
- interval_contains_open
+ interval_contains_open, IntervalTransform
 from patches import bbox_artist
+from scale import LinearScale, LogScale
 
 import matplotlib.units as units
 #import pdb
@@ -479,7 +480,7 @@
 """
 LABELPAD = 5
 OFFSETTEXTPAD = 3
-
+ 
 def __str__(self):
 return str(self.__class__).split('.')[-1] \
 + "(%d,%d)"%self.axes.transAxes.xy_tup((0,0))
@@ -507,9 +508,38 @@
 self.majorTicks = []
 self.minorTicks = []
 self.pickradius = pickradius
-
+ self._transform = LinearScale(self.axes.viewLim, self.axis).get_transform()
+ self._scale = 'linear'
+ 
 self.cla()
 
+ def get_transform(self):
+ return self._transform
+
+ def get_scale(self):
+ return self._scale
+ 
+ def set_scale(self, value, base=10, subs=None):
+ # MGDTODO: Move these settings (ticker etc.) into the scale class itself
+ value = value.lower()
+ assert value.lower() in ('log', 'linear')
+ if value == 'linear':
+ self.set_major_locator(AutoLocator())
+ self.set_major_formatter(ScalarFormatter())
+ self.set_minor_locator(NullLocator())
+ self.set_minor_formatter(NullFormatter())
+ self._transform = LinearScale(self.axes.viewLim, self.axis).get_transform()
+ elif value == 'log':
+ self.set_major_locator(LogLocator(base))
+ self.set_major_formatter(LogFormatterMathtext(base))
+ self.set_minor_locator(LogLocator(base,subs))
+ # MGDTODO: Pass base along
+ self._transform = LogScale(self.axes.viewLim, self.axis).get_transform()
+ miny, maxy = getattr(self.axes.viewLim, 'interval' + self.axis)
+ if min(miny, maxy)<=0:
+ self.axes.autoscale_view()
+ self._scale = value
+ 
 def get_children(self):
 children = [self.label]
 children.extend(self.majorTicks)
@@ -595,7 +625,7 @@
 
 for tick, loc, label in zip(minorTicks, minorLocs, minorLabels):
 if tick is None: continue
- if not interval.contains(loc): continue
+ if not interval_contains(interval, loc): continue
 #if seen.has_key(loc): continue
 tick.update_position(loc)
 tick.set_label1(label)
@@ -952,7 +982,8 @@
 
 class XAxis(Axis):
 __name__ = 'xaxis'
-
+ axis = 'x'
+ 
 def contains(self,mouseevent):
 """Test whether the mouse event occured in the x axis.
 """
@@ -1134,7 +1165,8 @@
 
 class YAxis(Axis):
 __name__ = 'yaxis'
-
+ axis = 'y'
+ 
 def contains(self,mouseevent):
 """Test whether the mouse event occurred in the y axis.
 
Added: branches/transforms/lib/matplotlib/scale.py
===================================================================
--- branches/transforms/lib/matplotlib/scale.py	 (rev 0)
+++ branches/transforms/lib/matplotlib/scale.py	2007年09月24日 16:53:38 UTC (rev 3884)
@@ -0,0 +1,78 @@
+import numpy as npy
+from numpy import ma
+
+from transforms import Affine1D, IntervalTransform, Transform
+
+class ScaleBase(object):
+ pass
+
+class LinearScale(ScaleBase):
+ def __init__(self, viewLim, direction):
+ direction = 'interval' + direction
+ self._transform = IntervalTransform(viewLim, direction)
+
+ def get_transform(self):
+ return self._transform
+ 
+class LogScale(ScaleBase):
+ class LogTransform(Transform):
+ input_dims = 1
+ output_dims = 1
+ def __init__(self, viewLim, direction, base):
+ Transform.__init__(self)
+ self._base = base
+ self._viewLim = viewLim
+ self._direction = direction
+
+ def transform(self, a):
+ a, affine = self.transform_without_affine(a)
+ return affine.transform(a)
+ 
+ def transform_without_affine(self, a):
+ # MGDTODO: Support different bases
+ base = self._base
+ marray = ma.masked_where(a <= 0.0, a)
+ marray = npy.log10(marray)
+ minimum, maximum = getattr(self._viewLim, self._direction)
+ minimum, maximum = npy.log10([minimum, maximum])
+ print marray
+ print Affine1D.from_values(maximum - minimum, minimum).inverted()
+ print minimum, maximum
+ return marray, Affine1D.from_values(maximum - minimum, minimum).inverted()
+ 
+ def inverted(self):
+ return LogScale.InvertedLogTransform(self._viewLim, self._direction, self._base)
+
+ class InvertedLogTransform(Transform):
+ input_dims = 1
+ output_dims = 1
+ def __init__(self, viewLim, direction, base):
+ Transform.__init__(self)
+ self._base = base
+ self._viewLim = viewLim
+ self._direction = direction
+
+ def transform(self, a):
+ minimum, maximum = getattr(self._viewLim, self._direction)
+ Affine1D.from_values(maximum - minimum, minimum).transform(a)
+ return ma.power(10.0, a)
+
+ def inverted(self):
+ return LogScale.LogTransform(self._viewLim, self._direction, self._base)
+ 
+ def __init__(self, viewLim, direction, base=10):
+ direction = 'interval' + direction
+ self._transform = self.LogTransform(viewLim, direction, base)
+
+ def get_transform(self):
+ return self._transform
+
+ 
+_scale_mapping = {
+ 'linear': LinearScale,
+ 'log': LogScale
+ }
+def scale_factory(scale, viewLim, direction):
+ if scale is None:
+ scale = 'linear'
+ return _scale_mapping[scale](viewLim, direction)
Modified: branches/transforms/lib/matplotlib/ticker.py
===================================================================
--- branches/transforms/lib/matplotlib/ticker.py	2007年09月24日 15:11:58 UTC (rev 3883)
+++ branches/transforms/lib/matplotlib/ticker.py	2007年09月24日 16:53:38 UTC (rev 3884)
@@ -500,8 +500,6 @@
 
 def __call__(self, x, pos=None):
 'Return the format for tick val x at position pos'
- self.verify_intervals()
-
 b = self._base
 # only label the decades
 fx = math.log(x)/math.log(b)
@@ -890,10 +888,9 @@
 
 def __call__(self):
 'Return the locations of the ticks'
- self.verify_intervals()
 b=self._base
 
- vmin, vmax = self.viewInterval.get_bounds()
+ vmin, vmax = self.axis.get_view_interval()
 vmin = math.log(vmin)/math.log(b)
 vmax = math.log(vmax)/math.log(b)
 
@@ -922,16 +919,16 @@
 
 def autoscale(self):
 'Try to choose the view limits intelligently'
- self.verify_intervals()
-
- vmin, vmax = self.dataInterval.get_bounds()
+ vmin, vmax = self.axis.get_view_interval()
 if vmax<vmin:
 vmin, vmax = vmax, vmin
 
- minpos = self.dataInterval.minpos()
+# minpos = self.dataInterval.minpos()
 
- if minpos<=0:
- raise RuntimeError('No positive data to plot')
+# if minpos<=0:
+# raise RuntimeError('No positive data to plot')
+
+ minpos = max(vmin, 0.00001) #MGDTODO
 if vmin<=0:
 vmin = minpos
 if not is_decade(vmin,self._base): vmin = decade_down(vmin,self._base)
Modified: branches/transforms/lib/matplotlib/transforms.py
===================================================================
--- branches/transforms/lib/matplotlib/transforms.py	2007年09月24日 15:11:58 UTC (rev 3883)
+++ branches/transforms/lib/matplotlib/transforms.py	2007年09月24日 16:53:38 UTC (rev 3884)
@@ -9,7 +9,7 @@
 from numpy.linalg import inv
 from sets import Set
 
-DEBUG = True
+DEBUG = False
 
 # MGDTODO: This creates a ton of cyclical references. We may want to
 # consider using weak references
@@ -61,8 +61,8 @@
 
 def is_bbox(self):
 return isinstance(self, BboxBase)
+
 
- 
 class BboxBase(TransformNode):
 '''
 This is the read-only part of a bounding-box
@@ -378,11 +378,30 @@
 def is_separable(self):
 return False
 
- 
-class Affine2DBase(Transform):
+
+class TransformWrapper(Transform):
 input_dims = 2
 output_dims = 2
+ 
+ def set(self, child):
+ self.child = child
+ self.child._parents.add(self)
+ self.invalidate()
 
+ def transform(self, points):
+ return self.child.transform(points)
+
+ def transform_without_affine(points):
+ return self.child.transform_without_affine(points)
+ 
+ def inverted(self):
+ return self.child.inverted()
+
+ def is_separable(self):
+ return self.child.is_separable()
+ 
+ 
+class AffineBase(Transform):
 def __init__(self):
 Transform.__init__(self)
 self._inverted = None
@@ -400,11 +419,173 @@
 
 #@staticmethod
 def concat(a, b):
- return Affine2D(Affine2D._concat(a.get_matrix(), b.get_matrix()))
+ return Affine1D(Affine1D._concat(a.get_matrix(), b.get_matrix()))
 concat = staticmethod(concat)
+
+ def get_matrix(self):
+ raise NotImplementedError()
+
+ def transform_without_affine(self, points):
+ # MGDTODO: Should we copy the points here? I'd like to avoid it,
+ # if possible
+ return points, self
 
+
+class Affine1DBase(AffineBase):
+ input_dims = 1
+ output_dims = 1
+
+ def __init__(self):
+ AffineBase.__init__(self)
+ 
+ def __array__(self, *args, **kwargs):
+	return self.get_matrix()
+	
 def to_values(self):
 mtx = self.get_matrix()
+ return tuple(mtx[0])
+ 
+ #@staticmethod
+ def matrix_from_values(a, b):
+ affine = npy.zeros((2, 2), npy.float_)
+ affine[0, :] = (a, b)
+ affine[1, 1] = 1
+ return affine
+ matrix_from_values = staticmethod(matrix_from_values)
+
+ def transform(self, values):
+ """
+ Applies the transformation to an array of values and
+ returns the result.
+ """
+ # 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 = ma.asarray(values, npy.float_)
+ return points * mtx[0,0] + mtx[0,1]
+
+ def is_separable(self):
+ return True
+
+ def inverted(self):
+ if self._inverted is None:
+ mtx = self.get_matrix()
+ self._inverted = Affine1D(inv(mtx))
+ return self._inverted
+ 
+
+class Affine1D(Affine1DBase):
+ def __init__(self, matrix = None):
+ """
+ Initialize an Affine transform from a 2x2 numpy float array.
+
+ a b
+ 0 1
+ """
+ Affine1DBase.__init__(self)
+ if matrix is None:
+ matrix = npy.identity(2)
+ else:
+	 matrix = npy.asarray(matrix, npy.float_)
+ assert matrix.shape == (2, 2)
+ self._mtx = matrix
+
+ def __repr__(self):
+ return "Affine1D(%s)" % repr(self._mtx)
+ __str__ = __repr__
+
+ def __cmp__(self, other):
+ if (isinstance(other, Affine1D) and
+ (self.get_matrix() == other.get_matrix()).all()):
+ return 0
+ return -1
+ 
+ #@staticmethod
+ def from_values(a, b):
+ return Affine1D(Affine1D.matrix_from_values(a, b))
+ from_values = staticmethod(from_values)
+
+ def get_matrix(self):
+ return self._mtx
+
+ def set_matrix(self, mtx):
+ self._mtx = mtx
+ self.invalidate()
+
+ def set(self, other):
+ self._mtx = other.get_matrix()
+ self.invalidate()
+ 
+ #@staticmethod
+ def identity():
+ return Affine1D(npy.identity(2))
+ identity = staticmethod(identity)
+
+ def clear(self):
+ self._mtx = npy.identity(2)
+ self.invalidate()
+ return self
+ 
+ def translate(self, t):
+ self._mtx[0, 1] += t
+ self.invalidate()
+ return self
+
+ def scale(self, s):
+ self._mtx[0, 0] *= s
+ self.invalidate()
+ return self
+
+ def is_separable(self):
+ mtx = self.get_matrix()
+ return mtx[0, 1] == 0.0 and mtx[1, 0] == 0.0
+
+ 
+class IntervalTransform(Affine1DBase):
+ def __init__(self, bbox, direction):
+ Affine1DBase.__init__(self)
+ self._bbox = bbox
+ self._direction = direction
+ self.set_children(['_bbox'])
+ self._mtx = None
+ 
+ def __repr__(self):
+ return "IntervalTransform(%s)" % (getattr(self._bbox, self._direction))
+ __str__ = __repr__
+
+ def _do_invalidation(self):
+ print "IntervalTransform.invalidation", self._bbox
+ self._mtx = None
+ Affine1DBase._do_invalidation(self)
+
+ def get_matrix(self):
+ if self._mtx is None:
+ min, max = getattr(self._bbox, self._direction)
+ self._mtx = inv(npy.array([[max - min, min],
+ [0.0, 1.0]], npy.float_))
+ return self._mtx
+ 
+ 
+class Affine2DBase(AffineBase):
+ input_dims = 2
+ output_dims = 2
+
+ def __init__(self):
+ AffineBase.__init__(self)
+
+ def __array__(self, *args, **kwargs):
+	return self.get_matrix()
+ 
+ def to_values(self):
+ mtx = self.get_matrix()
 return tuple(mtx[:2].swapaxes(0, 1).flatten())
 
 #@staticmethod
@@ -416,9 +597,6 @@
 return affine
 matrix_from_values = staticmethod(matrix_from_values)
 
- def get_matrix(self):
- raise NotImplementedError()
- 
 def transform(self, points):
 """
 Applies the transformation to an array of 2D points and
@@ -444,11 +622,6 @@
 points = points + mtx[0:2, 2:]
 return points.transpose()
 
- def transform_without_affine(self, points):
- # MGDTODO: Should we copy the points here? I'd like to avoid it,
- # if possible
- return points, self
- 
 def inverted(self):
 if self._inverted is None:
 mtx = self.get_matrix()
@@ -476,7 +649,6 @@
 	 matrix = npy.asarray(matrix, npy.float_)
 assert matrix.shape == (3, 3)
 self._mtx = matrix
- self._inverted = None
 
 def __repr__(self):
 return "Affine2D(%s)" % repr(self._mtx)
@@ -545,12 +717,6 @@
 self.invalidate()
 return self
 
- def inverted(self):
- 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
@@ -602,12 +768,10 @@
 __str__ = __repr__
 
 def transform(self, points):
- # MGDTODO: Optimize the case where one of these is
- # an affine
 x = self._x
 y = self._y
 if x == y and x.input_dims == 2:
- return self._x(points)
+ return self._x.transform(points)
 
 if x.input_dims == 2:
 x_points = x.transform(points)[:, 0:1]
@@ -623,13 +787,69 @@
 
 return ma.concatenate((x_points, y_points), 1)
 
+ def transform_without_affine(self, points):
+ x = self._x
+ y = self._y
+ if x == y and x.input_dims == 2:
+ return self._x.transform_without_affine(points)
+
+ if x.input_dims == 2:
+ x_points, x_affine = x.transform_without_affine(points)
+ x_points = x_points[:, 0:1]
+ else:
+ x_points, x_affine = x.transform_without_affine(points[:, 0])
+ x_points = x_points.reshape((len(x_points), 1))
+ 
+ if y.input_dims == 2:
+ y_points, y_affine = y.transform_without_affine(points)
+ y_points = y_points[:, 1:]
+ else:
+ y_points, y_affine = y.transform_without_affine(points[:, 1])
+ y_points = y_points.reshape((len(y_points), 1))
+
+ return ma.concatenate((x_points, y_points), 1), blended_transform_factory(x_affine, y_affine)
+ 
 def inverted(self):
 return BlendedGenericTransform(self._x.inverted(), self._y.inverted())
 
 def is_separable(self):
 return True
+
+
+class BlendedAffine1D(Affine2DBase, Transform):
+ def __init__(self, x_transform, y_transform):
+ assert isinstance(x_transform, Affine1DBase)
+ assert isinstance(y_transform, Affine1DBase)
+
+ Transform.__init__(self)
+ self._x = x_transform
+ self._y = y_transform
+ self.set_children(['_x', '_y'])
+ 
+ Affine2DBase.__init__(self)
+ self._mtx = None
+
+ def __repr__(self):
+ return "BlendedAffine1D(%s,%s)" % (self._x, self._y)
+ __str__ = __repr__
+ 
+ def _do_invalidation(self):
+ self._mtx = None
+ Affine2DBase._do_invalidation(self)
+
+ def is_separable(self):
+ return True
+
+ def get_matrix(self):
+ if self._mtx is None:
+ x_mtx = self._x.get_matrix()
+ y_mtx = self._y.get_matrix()
+ self._mtx = npy.array([[x_mtx[0, 0], 0.0, x_mtx[0, 1]],
+ [0.0, y_mtx[0, 0], y_mtx[0, 1]],
+ [0.0, 0.0, 1.0]])
+ return self._mtx
+
 
- 
 class BlendedAffine2D(Affine2DBase, Transform):
 def __init__(self, x_transform, y_transform):
 assert x_transform.is_affine()
@@ -650,9 +870,8 @@
 __str__ = __repr__
 
 def _do_invalidation(self):
- if self._mtx is not None:
- self._mtx = None
- Affine2DBase._do_invalidation(self)
+ self._mtx = None
+ Affine2DBase._do_invalidation(self)
 
 def is_separable(self):
 return True
@@ -672,8 +891,10 @@
 
 
 def blended_transform_factory(x_transform, y_transform):
- if x_transform.is_affine() and y_transform.is_affine():
+ if isinstance(x_transform, Affine2DBase) and isinstance(y_transform, Affine2DBase):
 return BlendedAffine2D(x_transform, y_transform)
+ elif isinstance(x_transform, Affine1DBase) and isinstance(y_transform, Affine1DBase):
+ return BlendedAffine1D(x_transform, y_transform)
 return BlendedGenericTransform(x_transform, y_transform)
 
 
@@ -726,7 +947,7 @@
 
 def _do_invalidation(self):
 self._mtx = None
- return Affine2DBase._do_invalidation(self)
+ Affine2DBase._do_invalidation(self)
 
 def get_matrix(self):
 if self._mtx is None:
@@ -754,8 +975,8 @@
 class TestLogTransform(Transform):
 input_dims = 1
 output_dims = 1
- def transform(self, xy):
- marray = ma.masked_where(xy <= 0.0, xy * 10.0)
+ def transform(self, a):
+ marray = ma.masked_where(a <= 0.0, a * 10.0)
 return (npy.log10(marray) * 0.5) + 0.5
 
 def inverted(self):
@@ -768,8 +989,8 @@
 class TestInvertLogTransform(Transform):
 input_dims = 1
 output_dims = 1
- def transform(self, xy):
- return ma.power(10, (xy - 0.5) * 2.0) / 10.0
+ def transform(self, a):
+ return ma.power(10, (a - 0.5) * 2.0) / 10.0
 
 def inverted(self):
 return TestLogTransform()
@@ -782,18 +1003,31 @@
 input_dims = 2
 output_dims = 2
 
+ def __init__(self, limits):
+ assert limits.is_bbox()
+
+ Transform.__init__(self)
+ self._limits = limits
+ self.set_children(['_limits'])
+ 
 def transform(self, xy):
 debug = len(xy) > 4
- x = xy[:, 0:1]
- y = xy[:, 1:]
- x, y = ((y * npy.cos(x)) + 1.0) * 0.5, ((y * npy.sin(x)) + 1.0) * 0.5
- if debug:
- print npy.min(xy[:, 0:1]), npy.max(xy[:, 0:1]), npy.min(xy[:, 1:]), npy.max(xy[:, 1:])
- print x.min(), x.max(), y.min(), y.max()
- return ma.concatenate((x, y), 1)
+ limmin, limmax = self._limits.intervaly
+ mask = (xy[:, 1:] < limmin) | (xy[:, 1:] > limmax)
+ mask = ma.concatenate((mask, mask), 1)
+ masked_xy = npy.ma.masked_where(mask, xy)
+ x = masked_xy[:, 0:1]
+ y = masked_xy[:, 1:2]
+ if x.shape == () or y.shape == ():
+ return masked_xy
+ y = (y - limmin) / (limmax - limmin)
+ x, y = y * ma.cos(x), y * ma.sin(x)
+ result = ma.concatenate((x, y), 1)
+ result = result * 0.5 + 0.5
+ return result
 
 def inverted(self):
- return TestInvertPolarTransform()
+ return TestInvertPolarTransform(self._limits)
 
 def is_separable(self):
 return False
@@ -803,16 +1037,26 @@
 input_dims = 2
 output_dims = 2
 
+ def __init__(self, limits):
+ assert limits.is_bbox()
+
+ Transform.__init__(self)
+ self._limits = limits
+ self.set_children(['_limits'])
+ 
 def transform(self, xy):
+ limmin, limmax = self._limits.intervaly
+ xy = (xy - 0.5) * 2.0
 x = xy[:, 0:1]
 y = xy[:, 1:]
 r = ma.sqrt(ma.power(x, 2) + ma.power(y, 2))
 theta = ma.arccos(x / r)
 theta = ma.where(y < 0, 2 * npy.pi - theta, theta)
- return ma.concatenate((theta / (npy.pi * 2), r), 1)
+ r = r * (limmax - limmin) + limmin
+ return ma.concatenate((theta, r), 1)
 
 def inverted(self):
- return TestInvertPolarTransform()
+ return TestInvertPolarTransform(self._limits)
 
 def is_separable(self):
 return False
@@ -835,9 +1079,8 @@
 __str__ = __repr__
 
 def _do_invalidation(self):
- if self._mtx is not None:
- self._mtx = None
- Affine2DBase._do_invalidation(self)
+ self._mtx = None
+ Affine2DBase._do_invalidation(self)
 
 def is_separable(self):
 return True
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2007年09月24日 17:33:08
Revision: 3886
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3886&view=rev
Author: mdboom
Date: 2007年09月24日 10:33:03 -0700 (2007年9月24日)
Log Message:
-----------
Fixed log scaling again.
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/scale.py
 branches/transforms/lib/matplotlib/ticker.py
 branches/transforms/lib/matplotlib/transforms.py
Modified: branches/transforms/lib/matplotlib/scale.py
===================================================================
--- branches/transforms/lib/matplotlib/scale.py	2007年09月24日 16:54:37 UTC (rev 3885)
+++ branches/transforms/lib/matplotlib/scale.py	2007年09月24日 17:33:03 UTC (rev 3886)
@@ -23,6 +23,7 @@
 self._base = base
 self._viewLim = viewLim
 self._direction = direction
+ self.set_children(['_viewLim'])
 
 def transform(self, a):
 a, affine = self.transform_without_affine(a)
@@ -31,13 +32,9 @@
 def transform_without_affine(self, a):
 # MGDTODO: Support different bases
 base = self._base
- marray = ma.masked_where(a <= 0.0, a)
+ marray = ma.masked_where(a <= 0.0, a * 10.0)
 marray = npy.log10(marray)
- minimum, maximum = getattr(self._viewLim, self._direction)
- minimum, maximum = npy.log10([minimum, maximum])
- print marray
- print Affine1D.from_values(maximum - minimum, minimum).inverted()
- print minimum, maximum
+ minimum, maximum = npy.log10(getattr(self._viewLim, self._direction) * 10.0)
 return marray, Affine1D.from_values(maximum - minimum, minimum).inverted()
 
 def inverted(self):
@@ -51,11 +48,12 @@
 self._base = base
 self._viewLim = viewLim
 self._direction = direction
-
+ self.set_children(['_viewLim'])
+ 
 def transform(self, a):
- minimum, maximum = getattr(self._viewLim, self._direction)
- Affine1D.from_values(maximum - minimum, minimum).transform(a)
- return ma.power(10.0, a)
+ minimum, maximum = npy.log10(getattr(self._viewLim, self._direction) * 10.0)
+ a = Affine1D.from_values(maximum - minimum, minimum).transform(a)
+ return ma.power(10.0, a) / 10.0
 
 def inverted(self):
 return LogScale.LogTransform(self._viewLim, self._direction, self._base)
Modified: branches/transforms/lib/matplotlib/ticker.py
===================================================================
--- branches/transforms/lib/matplotlib/ticker.py	2007年09月24日 16:54:37 UTC (rev 3885)
+++ branches/transforms/lib/matplotlib/ticker.py	2007年09月24日 17:33:03 UTC (rev 3886)
@@ -928,15 +928,19 @@
 # if minpos<=0:
 # raise RuntimeError('No positive data to plot')
 
- minpos = max(vmin, 0.00001) #MGDTODO
- if vmin<=0:
- vmin = minpos
+ # MGDTODO: Find a good way to track minpos
+ if vmin <= 0.0:
+ vmin = 0.1
+ 
 if not is_decade(vmin,self._base): vmin = decade_down(vmin,self._base)
 if not is_decade(vmax,self._base): vmax = decade_up(vmax,self._base)
 if vmin==vmax:
 vmin = decade_down(vmin,self._base)
 vmax = decade_up(vmax,self._base)
- return mtransforms.nonsingular(vmin, vmax)
+ print vmin, vmax
+ result = mtransforms.nonsingular(vmin, vmax)
+ print result
+ return result
 
 class AutoLocator(MaxNLocator):
 def __init__(self):
Modified: branches/transforms/lib/matplotlib/transforms.py
===================================================================
--- branches/transforms/lib/matplotlib/transforms.py	2007年09月24日 16:54:37 UTC (rev 3885)
+++ branches/transforms/lib/matplotlib/transforms.py	2007年09月24日 17:33:03 UTC (rev 3886)
@@ -181,7 +181,7 @@
 def __init__(self, points):
 BboxBase.__init__(self)
 self._points = npy.asarray(points, npy.float_)
-
+ 
 #@staticmethod
 def unit():
 return Bbox.from_lbrt(0., 0., 1., 1.)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2007年09月25日 17:05:56
Revision: 3889
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3889&view=rev
Author: mdboom
Date: 2007年09月25日 10:04:51 -0700 (2007年9月25日)
Log Message:
-----------
Automaticall separate affine from non-affine transforms
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/axes.py
 branches/transforms/lib/matplotlib/axis.py
 branches/transforms/lib/matplotlib/backends/backend_agg.py
 branches/transforms/lib/matplotlib/lines.py
 branches/transforms/lib/matplotlib/path.py
 branches/transforms/lib/matplotlib/scale.py
 branches/transforms/lib/matplotlib/ticker.py
 branches/transforms/lib/matplotlib/transforms.py
Modified: branches/transforms/lib/matplotlib/axes.py
===================================================================
--- branches/transforms/lib/matplotlib/axes.py	2007年09月25日 12:15:22 UTC (rev 3888)
+++ branches/transforms/lib/matplotlib/axes.py	2007年09月25日 17:04:51 UTC (rev 3889)
@@ -545,7 +545,7 @@
 "move this out of __init__ because non-separable axes don't use it"
 self.xaxis = maxis.XAxis(self)
 self.yaxis = maxis.YAxis(self)
- self._update_transAxisXY()
+ self._update_transScale()
 
 def sharex_foreign(self, axforeign):
 """
@@ -631,12 +631,28 @@
 self.viewLim = mtransforms.Bbox.unit()
 self.transAxes = mtransforms.BboxTransform(
 mtransforms.Bbox.unit(), self.bbox)
- self.transAxisXY = mtransforms.TransformWrapper()
- self.transData = self.transAxisXY + self.transAxes
 
- def _update_transAxisXY(self):
- self.transAxisXY.set(mtransforms.blended_transform_factory(
+ # Transforms the x and y axis separately by a scale factor
+ # It is assumed that this part will have non-linear components
+ self.transScale = mtransforms.TransformWrapper(mtransforms.IdentityTransform())
+
+ # A (possibly non-linear) projection on the (already scaled) data
+ self.transProjection = mtransforms.IdentityTransform()
+
+ # An affine transformation on the data, generally to limit the
+ # range of the axes
+ self.transLimits = mtransforms.BboxTransform(
+ mtransforms.TransformedBbox(self.viewLim, self.transScale), mtransforms.Bbox.unit())
+ 
+ self.transData = self.transScale + self.transProjection + self.transLimits + self.transAxes
+
+
+ def _update_transScale(self):
+ self.transScale.set(
+ mtransforms.blended_transform_factory(
 self.xaxis.get_transform(), self.yaxis.get_transform()))
+
+ self.transData.make_graphviz(open("trans.dot", "w"))
 
 def get_position(self, original=False):
 'Return the axes rectangle left, bottom, width, height'
@@ -1537,7 +1553,7 @@
 ACCEPTS: ['log' | 'linear' ]
 """
 self.xaxis.set_scale(value, **kwargs)
- self._update_transAxisXY()
+ self._update_transScale()
 
 def get_xticks(self):
 'Return the x ticks as a list of locations'
@@ -1647,7 +1663,7 @@
 ACCEPTS: ['log' | 'linear']
 """
 self.yaxis.set_scale(value, basey, subsy)
- self._update_transAxisXY()
+ self._update_transScale()
 
 def get_yticks(self):
 'Return the y ticks as a list of locations'
Modified: branches/transforms/lib/matplotlib/axis.py
===================================================================
--- branches/transforms/lib/matplotlib/axis.py	2007年09月25日 12:15:22 UTC (rev 3888)
+++ branches/transforms/lib/matplotlib/axis.py	2007年09月25日 17:04:51 UTC (rev 3889)
@@ -508,16 +508,15 @@
 self.majorTicks = []
 self.minorTicks = []
 self.pickradius = pickradius
- self._transform = LinearScale(self.axes.viewLim, self.axis).get_transform()
- self._scale = 'linear'
+ self._scale = LinearScale()
 
 self.cla()
 
 def get_transform(self):
- return self._transform
-
+ return self._scale.get_transform()
+ 
 def get_scale(self):
- return self._scale
+ return self._scale.name
 
 def set_scale(self, value, base=10, subs=None):
 # MGDTODO: Move these settings (ticker etc.) into the scale class itself
@@ -528,17 +527,16 @@
 self.set_major_formatter(ScalarFormatter())
 self.set_minor_locator(NullLocator())
 self.set_minor_formatter(NullFormatter())
- self._transform = LinearScale(self.axes.viewLim, self.axis).get_transform()
+ self._scale = LinearScale()
 elif value == 'log':
 self.set_major_locator(LogLocator(base))
 self.set_major_formatter(LogFormatterMathtext(base))
 self.set_minor_locator(LogLocator(base,subs))
 # MGDTODO: Pass base along
- self._transform = LogScale(self.axes.viewLim, self.axis).get_transform()
+ self._scale = LogScale()
 miny, maxy = getattr(self.axes.viewLim, 'interval' + self.axis)
 if min(miny, maxy)<=0:
 self.axes.autoscale_view()
- self._scale = value
 
 def get_children(self):
 children = [self.label]
Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py
===================================================================
--- branches/transforms/lib/matplotlib/backends/backend_agg.py	2007年09月25日 12:15:22 UTC (rev 3888)
+++ branches/transforms/lib/matplotlib/backends/backend_agg.py	2007年09月25日 17:04:51 UTC (rev 3889)
@@ -132,14 +132,14 @@
 
 # MGDTODO: This is a hack for now to allow for arbitrary transformations
 def draw_path(self, gc, path, trans, rgbFace=None):
- new_path, affine = path.transformed_without_affine(trans)
- self._renderer.draw_path(gc, new_path, affine, rgbFace)
+ assert trans.is_affine()
+ self._renderer.draw_path(gc, path, trans, rgbFace)
 
 # MGDTODO: This is a hack for now to allow for arbitrary transformations
 def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None):
 assert marker_trans.is_affine()
- new_path, affine = path.transformed_without_affine(trans)
- self._renderer.draw_markers(gc, marker_path, marker_trans, new_path, affine, rgbFace)
+ assert trans.is_affine()
+ self._renderer.draw_markers(gc, marker_path, marker_trans, path, trans, rgbFace)
 
 def draw_mathtext(self, gc, x, y, s, prop, angle):
 """
Modified: branches/transforms/lib/matplotlib/lines.py
===================================================================
--- branches/transforms/lib/matplotlib/lines.py	2007年09月25日 12:15:22 UTC (rev 3888)
+++ branches/transforms/lib/matplotlib/lines.py	2007年09月25日 17:04:51 UTC (rev 3889)
@@ -17,7 +17,7 @@
 from cbook import iterable, is_string_like, is_numlike
 from colors import colorConverter
 from path import Path
-from transforms import Affine2D, Bbox
+from transforms import Affine2D, Bbox, TransformedPath
 
 from matplotlib import rcParams
 
@@ -416,8 +416,18 @@
 self._logcache = None
 # Masked arrays are now handled by the Path class itself
 self._path = Path(self._xy, closed=False)
+ self._transformed_path = TransformedPath(self._path, self.get_transform())
 # MGDTODO: If _draw_steps is removed, remove the following line also
 self._step_path = None
+
+ def set_transform(self, t):
+ """
+ set the Transformation instance used by this artist
+
+ ACCEPTS: a matplotlib.transform transformation instance
+ """
+ Artist.set_transform(self, t)
+ self._transformed_path = TransformedPath(self._path, self.get_transform())
 
 def _is_sorted(self, x):
 "return true if x is sorted"
@@ -486,10 +496,10 @@
 
 funcname = self._lineStyles.get(self._linestyle, '_draw_nothing')
 lineFunc = getattr(self, funcname)
- lineFunc(renderer, gc, self._path)
+ lineFunc(renderer, gc, *self._transformed_path.get_path_and_affine())
 	 
 	# MGDTODO: Deal with markers
- if self._marker is not None:
+ if self._marker is not None and False:
 gc = renderer.new_gc()
 self._set_gc_clip(gc)
 gc.set_foreground(self.get_markeredgecolor())
@@ -678,7 +688,7 @@
 self.set_linestyle('--')
 self._dashSeq = seq # TODO: offset ignored for now
 
- def _draw_nothing(self, renderer, gc, path):
+ def _draw_nothing(self, *args, **kwargs):
 pass
 
 
@@ -704,191 +714,191 @@
 	renderer.draw_path(gc, self._step_path, self.get_transform())
 
 
- def _draw_solid(self, renderer, gc, path):
+ def _draw_solid(self, renderer, gc, path, trans):
 gc.set_linestyle('solid')
-	renderer.draw_path(gc, path, self.get_transform())
+	renderer.draw_path(gc, path, trans)
 
 
- def _draw_dashed(self, renderer, gc, path):
+ def _draw_dashed(self, renderer, gc, path, trans):
 gc.set_linestyle('dashed')
 if self._dashSeq is not None:
 gc.set_dashes(0, self._dashSeq)
 
-	renderer.draw_path(gc, path, self.get_transform())
+	renderer.draw_path(gc, path, trans)
 
 
- def _draw_dash_dot(self, renderer, gc, path):
+ def _draw_dash_dot(self, renderer, gc, path, trans):
 gc.set_linestyle('dashdot')
-	renderer.draw_path(gc, path, self.get_transform())
+	renderer.draw_path(gc, path, trans)
 
 	 
- def _draw_dotted(self, renderer, gc, path):
+ def _draw_dotted(self, renderer, gc, path, trans):
 gc.set_linestyle('dotted')
-	renderer.draw_path(gc, path, self.get_transform())
+	renderer.draw_path(gc, path, trans)
 
 	
- def _draw_point(self, renderer, gc, path):
+ def _draw_point(self, renderer, gc, path, path_trans):
 w = renderer.points_to_pixels(self._markersize) * \
 	 self._point_size_reduction * 0.5
 rgbFace = self._get_rgb_face()
 	transform = Affine2D().scale(w)
 	renderer.draw_markers(
-	 gc, Path.unit_circle(), transform, path, self.get_transform(),
+	 gc, Path.unit_circle(), transform, path, path_trans,
 	 rgbFace)
 
 	
- def _draw_pixel(self, renderer, gc, path):
+ def _draw_pixel(self, renderer, gc, path, path_trans):
 	rgbFace = self._get_rgb_face()
 	transform = Affine2D().translate(-0.5, -0.5)
 	renderer.draw_markers(gc, Path.unit_rectangle, transform,
-			 path, self.get_transform(), rgbFace)
+			 path, path_trans, rgbFace)
 	
 	
- def _draw_circle(self, renderer, gc, path):
+ def _draw_circle(self, renderer, gc, path, path_trans):
 w = renderer.points_to_pixels(self._markersize) * 0.5
 rgbFace = self._get_rgb_face()
 	transform = Affine2D().scale(w, w)
 	renderer.draw_markers(
-	 gc, Path.unit_circle(), transform, path, self.get_transform(),
+	 gc, Path.unit_circle(), transform, path, path_trans,
 	 rgbFace)
 
 
 _triangle_path = Path([[0.0, 1.0], [-1.0, -1.0], [1.0, -1.0]])
- def _draw_triangle_up(self, renderer, gc, path):
+ def _draw_triangle_up(self, renderer, gc, path, path_trans):
 offset = 0.5*renderer.points_to_pixels(self._markersize)
 	transform = Affine2D().scale(offset, offset)
 rgbFace = self._get_rgb_face()
 	renderer.draw_markers(gc, self._triangle_path, transform,
-			 path, self.get_transform(), rgbFace)
+			 path, path_trans, rgbFace)
 
 
- def _draw_triangle_down(self, renderer, gc, path):
+ def _draw_triangle_down(self, renderer, gc, path, path_trans):
 offset = 0.5*renderer.points_to_pixels(self._markersize)
 	transform = Affine2D().scale(offset, -offset)
 rgbFace = self._get_rgb_face()
 	renderer.draw_markers(gc, self._triangle_path, transform,
-			 path, self.get_transform(), rgbFace)
+			 path, path_trans, rgbFace)
 
 	
- def _draw_triangle_left(self, renderer, gc, path):
+ def _draw_triangle_left(self, renderer, gc, path, path_trans):
 offset = 0.5*renderer.points_to_pixels(self._markersize)
 	transform = Affine2D().scale(offset, offset).rotate_deg(90)
 rgbFace = self._get_rgb_face()
 	renderer.draw_markers(gc, self._triangle_path, transform,
-			 path, self.get_transform(), rgbFace)
+			 path, path_trans, rgbFace)
 
 
- def _draw_triangle_right(self, renderer, gc, path):
+ def _draw_triangle_right(self, renderer, gc, path, path_trans):
 offset = 0.5*renderer.points_to_pixels(self._markersize)
 	transform = Affine2D().scale(offset, offset).rotate_deg(-90)
 rgbFace = self._get_rgb_face()
 	renderer.draw_markers(gc, self._triangle_path, transform,
-			 path, self.get_transform(), rgbFace)
+			 path, path_trans, rgbFace)
 
 
- def _draw_square(self, renderer, gc, path):
+ def _draw_square(self, renderer, gc, path, path_trans):
 side = renderer.points_to_pixels(self._markersize)
 	transform = Affine2D().translate(-0.5, -0.5).scale(side)
 rgbFace = self._get_rgb_face()
 	renderer.draw_markers(gc, Path.unit_rectangle(), transform,
-			 path, self.get_transform(), rgbFace)
+			 path, path_trans, rgbFace)
 
 	
- def _draw_diamond(self, renderer, gc, path):
+ def _draw_diamond(self, renderer, gc, path, path_trans):
 side = renderer.points_to_pixels(self._markersize)
 	transform = Affine2D().translate(0.5, 0.5).rotate_deg(45).scale(side)
 rgbFace = self._get_rgb_face()
 	renderer.draw_markers(gc, Path.unit_rectangle(), transform,
-			 path, self.get_transform(), rgbFace)
+			 path, path_trans, rgbFace)
 
 	
- def _draw_thin_diamond(self, renderer, gc, path):
+ def _draw_thin_diamond(self, renderer, gc, path, path_trans):
 offset = renderer.points_to_pixels(self._markersize)
 	transform = Affine2D().translate(0.5, 0.5) \
 	 .rotate_deg(45).scale(offset * 0.8, offset)
 rgbFace = self._get_rgb_face()
 	renderer.draw_markers(gc, Path.unit_rectangle(), transform,
-			 path, self.get_transform(), rgbFace)
+			 path, path_trans, rgbFace)
 
 	
- def _draw_pentagon(self, renderer, gc, path):
+ def _draw_pentagon(self, renderer, gc, path, path_trans):
 offset = 0.5 * renderer.points_to_pixels(self._markersize)
 	transform = Affine2D().scale(offset)
 	rgbFace = self._get_rgb_face()
 	renderer.draw_markers(gc, Path.unit_regular_polygon(5), transform,
-			 path, self.get_transform(), rgbFace)
+			 path, path_trans, rgbFace)
 
 	
- def _draw_hexagon1(self, renderer, gc, path):
+ def _draw_hexagon1(self, renderer, gc, path, path_trans):
 offset = 0.5 * renderer.points_to_pixels(self._markersize)
 	transform = Affine2D().scale(offset)
 	rgbFace = self._get_rgb_face()
 	renderer.draw_markers(gc, Path.unit_regular_polygon(6), transform,
-			 path, self.get_transform(), rgbFace)
+			 path, path_trans, rgbFace)
 
 	
- def _draw_hexagon2(self, renderer, gc, path):
+ def _draw_hexagon2(self, renderer, gc, path, path_trans):
 offset = 0.5 * renderer.points_to_pixels(self._markersize)
 	transform = Affine2D().scale(offset).rotate_deg(30)
 	rgbFace = self._get_rgb_face()
 	renderer.draw_markers(gc, Path.unit_regular_polygon(6), transform,
-			 path, self.get_transform(), rgbFace)
+			 path, path_trans, rgbFace)
 
 
 _line_marker_path = Path([[0.0, -1.0], [0.0, 1.0]], closed=False)
- def _draw_vline(self, renderer, gc, path):
+ def _draw_vline(self, renderer, gc, path, path_trans):
 offset = 0.5*renderer.points_to_pixels(self._markersize)
 	transform = Affine2D().scale(offset)
 	renderer.draw_markers(gc, self._line_marker_path, transform,
-			 path, self.get_transform())
+			 path, path_trans)
 
 		
- def _draw_hline(self, renderer, gc, path):
+ def _draw_hline(self, renderer, gc, path, path_trans):
 offset = 0.5*renderer.points_to_pixels(self._markersize)
 	transform = Affine2D().scale(offset).rotate_deg(90)
 	renderer.draw_markers(gc, self._line_marker_path, transform,
-			 path, self.get_transform())
+			 path, path_trans)
 
 		
 _tickhoriz_path = Path([[0.0, 0.5], [1.0, 0.5]], closed=False)
- def _draw_tickleft(self, renderer, gc, path):
+ def _draw_tickleft(self, renderer, gc, path, path_trans):
 offset = renderer.points_to_pixels(self._markersize)
 	marker_transform = Affine2D().scale(-offset, 1.0)
 	renderer.draw_markers(gc, self._tickhoriz_path, marker_transform,
-			 path, self.get_transform())
+			 path, path_trans)
 
 	
- def _draw_tickright(self, renderer, gc, path):
+ def _draw_tickright(self, renderer, gc, path, path_trans):
 offset = renderer.points_to_pixels(self._markersize)
 	marker_transform = Affine2D().scale(offset, 1.0)
 	renderer.draw_markers(gc, self._tickhoriz_path, marker_transform,
-			 path, self.get_transform())
+			 path, path_trans)
 
 	
 _tickvert_path = Path([[-0.5, 0.0], [-0.5, 1.0]], closed=False)
- def _draw_tickup(self, renderer, gc, path):
+ def _draw_tickup(self, renderer, gc, path, path_trans):
 offset = renderer.points_to_pixels(self._markersize)
 	marker_transform = Affine2D().scale(1.0, offset)
 	renderer.draw_markers(gc, self._tickvert_path, marker_transform,
-			 path, self.get_transform())
+			 path, path_trans)
 
 	
- def _draw_tickdown(self, renderer, gc, path):
+ def _draw_tickdown(self, renderer, gc, path, path_trans):
 offset = renderer.points_to_pixels(self._markersize)
 	marker_transform = Affine2D().scale(1.0, -offset)
 	renderer.draw_markers(gc, self._tickvert_path, marker_transform,
-			 path, self.get_transform())
+			 path, path_trans)
 
 
 _plus_path = Path([[-1.0, 0.0], [1.0, 0.0],
 		 [0.0, -1.0], [0.0, 1.0]],
 		 [Path.MOVETO, Path.LINETO,
 		 Path.MOVETO, Path.LINETO])
- def _draw_plus(self, renderer, gc, path):
+ def _draw_plus(self, renderer, gc, path, path_trans):
 offset = 0.5*renderer.points_to_pixels(self._markersize)
 	transform = Affine2D().scale(offset)
 	renderer.draw_markers(gc, self._plus_path, transform,
-			 path, self.get_transform())
+			 path, path_trans)
 
 
 _tri_path = Path([[0.0, 0.0], [0.0, -1.0],
@@ -897,61 +907,61 @@
 		 [Path.MOVETO, Path.LINETO,
 		 Path.MOVETO, Path.LINETO,
 		 Path.MOVETO, Path.LINETO])
- def _draw_tri_down(self, renderer, gc, path):
+ def _draw_tri_down(self, renderer, gc, path, path_trans):
 offset = 0.5*renderer.points_to_pixels(self._markersize)
 	transform = Affine2D().scale(offset)
 	renderer.draw_markers(gc, self._tri_path, transform,
-			 path, self.get_transform())
+			 path, path_trans)
 
 	
- def _draw_tri_up(self, renderer, gc, path):
+ def _draw_tri_up(self, renderer, gc, path, path_trans):
 offset = 0.5*renderer.points_to_pixels(self._markersize)
 	transform = Affine2D().scale(offset).rotate_deg(180)
 	renderer.draw_markers(gc, self._tri_path, transform,
-			 path, self.get_transform())
+			 path, path_trans)
 
 	
- def _draw_tri_left(self, renderer, gc, path):
+ def _draw_tri_left(self, renderer, gc, path, path_trans):
 	offset = 0.5*renderer.points_to_pixels(self._markersize)
 	transform = Affine2D().scale(offset).rotate_deg(90)
 	renderer.draw_markers(gc, self._tri_path, transform,
-			 path, self.get_transform())
+			 path, path_trans)
 
 	
- def _draw_tri_right(self, renderer, gc, path):
+ def _draw_tri_right(self, renderer, gc, path, path_trans):
 	offset = 0.5*renderer.points_to_pixels(self._markersize)
 	transform = Affine2D().scale(offset).rotate_deg(270)
 	renderer.draw_markers(gc, self._tri_path, transform,
-			 path, self.get_transform())
+			 path, path_trans)
 
 
 _caret_path = Path([[-1.0, 1.5], [0.0, 0.0], [1.0, 1.5]], closed=False)
- def _draw_caretdown(self, renderer, gc, path):
+ def _draw_caretdown(self, renderer, gc, path, path_trans):
 offset = 0.5*renderer.points_to_pixels(self._markersize)
 	transform = Affine2D().scale(offset)
 	renderer.draw_markers(gc, self._caret_path, transform,
-			 path, self.get_transform())
+			 path, path_trans)
 
 	
- def _draw_caretup(self, renderer, gc, path):
+ def _draw_caretup(self, renderer, gc, path, path_trans):
 offset = 0.5*renderer.points_to_pixels(self._markersize)
 	transform = Affine2D().scale(offset).rotate_deg(180)
 	renderer.draw_markers(gc, self._caret_path, transform,
-			 path, self.get_transform())
+			 path, path_trans)
 
 	
- def _draw_caretleft(self, renderer, gc, path):
+ def _draw_caretleft(self, renderer, gc, path, path_trans):
 offset = 0.5*renderer.points_to_pixels(self._markersize)
 	transform = Affine2D().scale(offset).rotate_deg(90)
 	renderer.draw_markers(gc, self._caret_path, transform,
-			 path, self.get_transform())
+			 path, path_trans)
 
 	
- def _draw_caretright(self, renderer, gc, path):
+ def _draw_caretright(self, renderer, gc, path, path_trans):
 offset = 0.5*renderer.points_to_pixels(self._markersize)
 	transform = Affine2D().scale(offset).rotate_deg(270)
 	renderer.draw_markers(gc, self._caret_path, transform,
-			 path, self.get_transform())
+			 path, path_trans)
 
 
 _x_path = Path([[-1.0, -1.0], [1.0, 1.0],
@@ -962,7 +972,7 @@
 offset = 0.5*renderer.points_to_pixels(self._markersize)
 	transform = Affine2D().scale(offset)
 	renderer.draw_markers(gc, self._x_path, transform,
-			 path, self.get_transform())
+			 path, path_trans)
 
 	
 def update_from(self, other):
Modified: branches/transforms/lib/matplotlib/path.py
===================================================================
--- branches/transforms/lib/matplotlib/path.py	2007年09月25日 12:15:22 UTC (rev 3888)
+++ branches/transforms/lib/matplotlib/path.py	2007年09月25日 17:04:51 UTC (rev 3889)
@@ -88,10 +88,6 @@
 
 def transformed(self, transform):
 return Path(transform.transform(self.vertices), self.codes)
-
- def transformed_without_affine(self, transform):
- vertices, affine = transform.transform_without_affine(self.vertices)
- return Path(vertices, self.codes), affine
 
 _unit_rectangle = None
 #@classmethod
@@ -152,6 +148,3 @@
 	 cls._unit_circle = Path(vertices, codes)
 	return cls._unit_circle
 unit_circle = classmethod(unit_circle)
-
-# MGDTODO: Add a transformed path that would automatically invalidate
-# itself when its transform changes
Modified: branches/transforms/lib/matplotlib/scale.py
===================================================================
--- branches/transforms/lib/matplotlib/scale.py	2007年09月25日 12:15:22 UTC (rev 3888)
+++ branches/transforms/lib/matplotlib/scale.py	2007年09月25日 17:04:51 UTC (rev 3889)
@@ -1,66 +1,54 @@
 import numpy as npy
 from numpy import ma
+from numpy.linalg import inv
 
-from transforms import Affine1D, IntervalTransform, Transform
+from transforms import Affine1DBase, IntervalTransform, Transform, \
+ composite_transform_factory, IdentityTransform
 
 class ScaleBase(object):
 pass
 
 class LinearScale(ScaleBase):
- def __init__(self, viewLim, direction):
- direction = 'interval' + direction
- self._transform = IntervalTransform(viewLim, direction)
-
 def get_transform(self):
- return self._transform
+ return IdentityTransform()
 
 class LogScale(ScaleBase):
 class LogTransform(Transform):
 input_dims = 1
 output_dims = 1
- def __init__(self, viewLim, direction, base):
+ def __init__(self, base):
 Transform.__init__(self)
 self._base = base
- self._viewLim = viewLim
- self._direction = direction
- self.set_children(['_viewLim'])
 
+ def is_separable(self):
+ return True
+ 
 def transform(self, a):
- a, affine = self.transform_without_affine(a)
- return affine.transform(a)
+ if len(a) > 10:
+ print "Log Transforming..."
+ return ma.log10(ma.masked_where(a <= 0.0, a * 10.0))
 
- def transform_without_affine(self, a):
- # MGDTODO: Support different bases
- base = self._base
- marray = ma.masked_where(a <= 0.0, a * 10.0)
- marray = npy.log10(marray)
- minimum, maximum = npy.log10(getattr(self._viewLim, self._direction) * 10.0)
- return marray, Affine1D.from_values(maximum - minimum, minimum).inverted()
- 
 def inverted(self):
- return LogScale.InvertedLogTransform(self._viewLim, self._direction, self._base)
+ return LogScale.InvertedLogTransform(self._base)
 
 class InvertedLogTransform(Transform):
 input_dims = 1
 output_dims = 1
- def __init__(self, viewLim, direction, base):
+ def __init__(self, base):
 Transform.__init__(self)
 self._base = base
- self._viewLim = viewLim
- self._direction = direction
- self.set_children(['_viewLim'])
+
+ def is_separable(self):
+ return True
 
 def transform(self, a):
- minimum, maximum = npy.log10(getattr(self._viewLim, self._direction) * 10.0)
- a = Affine1D.from_values(maximum - minimum, minimum).transform(a)
 return ma.power(10.0, a) / 10.0
 
 def inverted(self):
- return LogScale.LogTransform(self._viewLim, self._direction, self._base)
+ return LogScale.LogTransform(self._base)
 
- def __init__(self, viewLim, direction, base=10):
- direction = 'interval' + direction
- self._transform = self.LogTransform(viewLim, direction, base)
+ def __init__(self, base=10):
+ self._transform = self.LogTransform(base)
 
 def get_transform(self):
 return self._transform
Modified: branches/transforms/lib/matplotlib/ticker.py
===================================================================
--- branches/transforms/lib/matplotlib/ticker.py	2007年09月25日 12:15:22 UTC (rev 3888)
+++ branches/transforms/lib/matplotlib/ticker.py	2007年09月25日 17:04:51 UTC (rev 3889)
@@ -937,9 +937,7 @@
 if vmin==vmax:
 vmin = decade_down(vmin,self._base)
 vmax = decade_up(vmax,self._base)
- print vmin, vmax
 result = mtransforms.nonsingular(vmin, vmax)
- print result
 return result
 
 class AutoLocator(MaxNLocator):
Modified: branches/transforms/lib/matplotlib/transforms.py
===================================================================
--- branches/transforms/lib/matplotlib/transforms.py	2007年09月25日 12:15:22 UTC (rev 3888)
+++ branches/transforms/lib/matplotlib/transforms.py	2007年09月25日 17:04:51 UTC (rev 3889)
@@ -8,7 +8,10 @@
 from numpy import ma as ma
 from numpy.linalg import inv
 from sets import Set
+from weakref import WeakKeyDictionary
 
+from path import Path
+
 DEBUG = False
 
 # MGDTODO: This creates a ton of cyclical references. We may want to
@@ -22,45 +25,54 @@
 self._parents = Set()
 self._children = []
 
- def invalidate(self):
- self._do_invalidation()
+ def invalidate(self, which_child=None, affine_only=[]):
+ if which_child is None:
+ which_child = self
+ self._do_invalidation(which_child, affine_only)
+ # affine_only = affine_only and (self.is_affine() or self.is_bbox())
 for parent in self._parents:
- parent.invalidate()
+ parent.invalidate(self, affine_only + [self])
 
- def _do_invalidation(self):
- return False
-
+ def _do_invalidation(self, which_child, affine_only):
+ pass
+ 
 def set_children(self, children):
 for child in children:
 getattr(self, child)._parents.add(self)
 self._children = children
 
 def make_graphviz(self, fobj):
+ seen = Set()
+
 def recurse(root):
+ if root in seen:
+ return
+ seen.add(root)
 fobj.write('%s [label="%s"];\n' %
 (hash(root), root.__class__.__name__))
- if isinstance(root, Affine2DBase):
+ if root.is_affine():
 fobj.write('%s [style=filled, color=".7 .7 .9"];\n' %
 hash(root))
- elif isinstance(root, BboxBase):
+ elif root.is_bbox():
 fobj.write('%s [style=filled, color=".9 .9 .7"];\n' %
 hash(root))
 for child_name in root._children:
 child = getattr(root, child_name)
- fobj.write("%s -> %s;\n" % (
+ fobj.write('%s -> %s [label="%s"];\n' % (
 hash(root),
- hash(child)))
+ hash(child),
+ child_name))
 recurse(child)
- 
+
 fobj.write("digraph G {\n")
 recurse(self)
 fobj.write("}\n")
 
 def is_affine(self):
- return isinstance(self, Affine2DBase)
+ return False
 
 def is_bbox(self):
- return isinstance(self, BboxBase)
+ return False
 
 
 class BboxBase(TransformNode):
@@ -70,7 +82,10 @@
 
 def __init__(self):
 TransformNode.__init__(self)
- 
+
+ def is_bbox(self):
+ return True
+ 
 def __array__(self):
 return self.get_points()
 
@@ -125,63 +140,81 @@
 height = property(_get_height)
 
 def _get_bounds(self):
- return (self.xmin, self.ymin,
- self.xmax - self.xmin, self.ymax - self.ymin)
+ ((xmin, ymin), (xmax, ymax)) = self.get_points()
+ return (xmin, ymin, xmax - xmin, ymax - ymin)
 bounds = property(_get_bounds)
 
+ def _get_lbrt(self):
+ return self.get_points().flatten().copy()
+ lbrt = property(_get_lbrt)
+ 
 def get_points(self):
 return NotImplementedError()
-
+ 
 # MGDTODO: Optimize
 def containsx(self, x):
- return x >= self.xmin and x <= self.xmax
+ xmin, xmax = self.intervalx
+ return x >= xmin and x <= xmax
 
 def containsy(self, y):
- return y >= self.ymin and y <= self.ymax
+ ymin, ymax = self.intervaly
+ return y >= ymin and y <= 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)
+ xmin, xmax = other.intervalx
+ return self.containsx(xmin) \
+ or self.containsx(xmax)
 
 def overlapsy(self, other):
- return self.containsy(other.ymin) \
- or self.containsx(other.ymax)
+ ymin, ymax = other.intervaly
+ return self.containsy(ymin) \
+ or self.containsx(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
+ xmin, xmax = self.intervalx
+ return x > xmin and x < xmax
 
 def fully_containsy(self, y):
- return y > self.ymin and y < self.ymax
+ ymin, ymax = self.intervaly
+ return y > ymin and y < 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)
+ xmin, xmax = other.intervalx
+ return self.fully_containsx(xmin) \
+ or self.fully_containsx(xmax)
 
 def fully_overlapsy(self, other):
- return self.fully_containsy(other.ymin) \
- or self.fully_containsx(other.ymax)
+ ymin, ymax = other.intervaly
+ return self.fully_containsy(ymin) \
+ or self.fully_containsx(ymax)
 
 def fully_overlaps(self, other):
 return self.fully_overlapsx(other) and \
 self.fully_overlapsy(other)
 
+ def transformed(self, transform):
+ return Bbox(transform.transform(self.get_points()))
+
+ def inverse_transformed(self, transform):
+ return Bbox(transform.inverted().transform(self.get_points()))
 
+ 
 class Bbox(BboxBase):
 def __init__(self, points):
 BboxBase.__init__(self)
 self._points = npy.asarray(points, npy.float_)
- 
+
 #@staticmethod
 def unit():
 return Bbox.from_lbrt(0., 0., 1., 1.)
@@ -198,12 +231,6 @@
 return Bbox(points)
 from_lbrt = staticmethod(from_lbrt)
 
- def __cmp__(self, other):
- # 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)
 __str__ = __repr__
@@ -219,8 +246,7 @@
 		 [max(x.max(), self.xmax), max(y.max(), self.ymax)]],
 		 npy.float_)
 self.invalidate()
-
- # MGDTODO: Probably a more efficient ways to do this...
+ 
 def _set_xmin(self, val):
 self._points[0, 0] = val
 self.invalidate()
@@ -278,12 +304,6 @@
 self._points = other.get_points()
 self.invalidate()
 
- def transformed(self, transform):
- return Bbox(transform.transform(self._points))
-
- def inverse_transformed(self, transform):
- return Bbox(transform.inverted().transform(self._points))
- 
 def expanded(self, sw, sh):
 width = self.width
 height = self.height
@@ -324,6 +344,8 @@
 def __init__(self, bbox, transform):
 assert bbox.is_bbox()
 assert isinstance(transform, Transform)
+ assert transform.input_dims == 2
+ assert transform.output_dims == 2
 
 BboxBase.__init__(self)
 self.bbox = bbox
@@ -335,7 +357,7 @@
 return "TransformedBbox(%s, %s)" % (self.bbox, self.transform)
 __str__ = __repr__
 
- def _do_invalidation(self):
+ def _do_invalidation(self, which_child, affine_only):
 self._points = None
 
 def get_points(self):
@@ -347,13 +369,10 @@
 class Transform(TransformNode):
 def __init__(self):
 TransformNode.__init__(self)
- 
- def transform(self, points):
- raise NotImplementedError()
 
- def transform_without_affine(self, points):
- return self.transform(points), IDENTITY
- 
+ def is_separable(self):
+ return False
+ 
 def __add__(self, other):
 if isinstance(other, Transform):
 return composite_transform_factory(self, other)
@@ -366,39 +385,69 @@
 raise TypeError(
 "Can not add Transform to object of type '%s'" % type(other))
 
+ def transform(self, points):
+ raise NotImplementedError
+
+ def transform_affine(self, points):
+ raise NotImplementedError
+
+ def transform_non_affine(self, points):
+ raise NotImplementedError
+
+ def get_affine(self):
+ raise NotImplementedError
+ 
 def transform_point(self, point):
 return self.transform(npy.asarray([point]))[0]
- 
+
 def has_inverse(self):
 raise NotImplementedError()
 
 def inverted(self):
 raise NotImplementedError()
 
- def is_separable(self):
- return False
 
+class TransformWrapper(Transform):
+ def __init__(self, child):
+ assert isinstance(child, Transform)
+ 
+ Transform.__init__(self)
+ self.input_dims = child.input_dims
+ self.output_dims = child.output_dims
+ self._child = child
+ self.set_children(['_child'])
 
-class TransformWrapper(Transform):
- input_dims = 2
- output_dims = 2
- 
+ def __repr__(self):
+ return "TransformWrapper(%r)" % self._child
+ __str__ = __repr__
+ 
 def set(self, child):
- self.child = child
- self.child._parents.add(self)
+ assert child.input_dims == self.input_dims
+ assert child.output_dims == self.output_dims
+ self._child = child
+ self.set_children(['_child'])
 self.invalidate()
+ 
+ def is_separable(self):
+ return self._child.is_separable()
 
+ def is_affine(self):
+ return self._child.is_affine()
+ 
 def transform(self, points):
- return self.child.transform(points)
+ return self._child.transform(points)
 
- def transform_without_affine(points):
- return self.child.transform_without_affine(points)
+ def transform_affine(self, points):
+ return self._child.transform_affine(points)
+
+ def transform_non_affine(self, points):
+ return self._child.transform_non_affine(points)
+
+ def get_affine(self):
+ return self._child.get_affine()
 
 def inverted(self):
- return self.child.inverted()
-
- def is_separable(self):
- return self.child.is_separable()
+ return self._child.inverted()
 
 
 class AffineBase(Transform):
@@ -406,10 +455,13 @@
 Transform.__init__(self)
 self._inverted = None
 
+ def is_affine(self):
+ return True
+ 
 def __array__(self, *args, **kwargs):
 	return self.get_matrix()
 	
- def _do_invalidation(self):
+ def _do_invalidation(self, which_child, affine_only):
 self._inverted = None
 
 #@staticmethod
@@ -425,10 +477,14 @@
 def get_matrix(self):
 raise NotImplementedError()
 
- def transform_without_affine(self, points):
- # MGDTODO: Should we copy the points here? I'd like to avoid it,
- # if possible
- return points, self
+ def transform_affine(self, points):
+ return self.transform(points)
+
+ def transform_non_affine(self, points):
+ return points
+
+ def get_affine(self):
+ return self
 
 
 class Affine1DBase(AffineBase):
@@ -437,13 +493,16 @@
 
 def __init__(self):
 AffineBase.__init__(self)
- 
+
+ def is_separable(self):
+ return True
+ 
 def __array__(self, *args, **kwargs):
 	return self.get_matrix()
-	
+
 def to_values(self):
 mtx = self.get_matrix()
- return tuple(mtx[0])
+ return mtx[0]
 
 #@staticmethod
 def matrix_from_values(a, b):
@@ -472,9 +531,6 @@
 points = ma.asarray(values, npy.float_)
 return points * mtx[0,0] + mtx[0,1]
 
- def is_separable(self):
- return True
-
 def inverted(self):
 if self._inverted is None:
 mtx = self.get_matrix()
@@ -551,9 +607,12 @@
 
 class IntervalTransform(Affine1DBase):
 def __init__(self, bbox, direction):
+ assert direction in ('x', 'y')
+ assert bbox.is_bbox()
+ 
 Affine1DBase.__init__(self)
 self._bbox = bbox
- self._direction = direction
+ self._direction = "interval" + direction
 self.set_children(['_bbox'])
 self._mtx = None
 
@@ -561,10 +620,9 @@
 return "IntervalTransform(%s)" % (getattr(self._bbox, self._direction))
 __str__ = __repr__
 
- def _do_invalidation(self):
- print "IntervalTransform.invalidation", self._bbox
+ def _do_invalidation(self, which_child, affine_only):
 self._mtx = None
- Affine1DBase._do_invalidation(self)
+ Affine1DBase._do_invalidation(self, which_child, affine_only)
 
 def get_matrix(self):
 if self._mtx is None:
@@ -581,6 +639,10 @@
 def __init__(self):
 AffineBase.__init__(self)
 
+ def is_separable(self):
+ mtx = self.get_matrix()
+ return mtx[0, 1] == 0.0 and mtx[1, 0] == 0.0
+ 
 def __array__(self, *args, **kwargs):
 	return self.get_matrix()
 
@@ -627,10 +689,6 @@
 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
 
 
 class Affine2D(Affine2DBase):
@@ -728,6 +786,10 @@
 """
 _mtx = npy.identity(3)
 
+ def __repr__(self):
+ return "IdentityTransform()"
+ __str__ = __repr__
+ 
 def __cmp__(self, other):
 if (isinstance(other, Affine2D) and
 (other == IDENTITY)):
@@ -735,34 +797,44 @@
 return -1
 
 def get_matrix(self):
- return _mtx
+ return self._mtx
 
 def transform(self, points):
 return points
 
- def transform_without_affine(self, points):
- return points, self
+ def transform_affine(self, points):
+ return points
 
+ def transform_non_affine(self, points):
+ return points
+
+ def get_affine(self):
+ return self
+ 
 def inverted(self):
 return self
+
 
-IDENTITY = Affine2D()
- 
 class BlendedGenericTransform(Transform):
 input_dims = 2
 output_dims = 2
 
 def __init__(self, x_transform, y_transform):
 	# Here we ask: "Does it blend?"
- # MGDTODO: Turn these checks back on
- # assert x_transform.is_separable()
- # assert y_transform.is_separable()
+ assert x_transform.is_separable()
+ assert y_transform.is_separable()
 
 Transform.__init__(self)
 self._x = x_transform
 self._y = y_transform
 self.set_children(['_x', '_y'])
 
+ def is_affine(self):
+ return self._x.is_affine() and self._y.is_affine()
+ 
+ def is_separable(self):
+ return True
+ 
 def __repr__(self):
 return "BlendedGenericTransform(%s,%s)" % (self._x, self._y)
 __str__ = __repr__
@@ -787,33 +859,17 @@
 
 return ma.concatenate((x_points, y_points), 1)
 
- def transform_without_affine(self, points):
- x = self._x
- y = self._y
- if x == y and x.input_dims == 2:
- return self._x.transform_without_affine(points)
-
- if x.input_dims == 2:
- x_points, x_affine = x.transform_without_affine(points)
- x_points = x_points[:, 0:1]
- else:
- x_points, x_affine = x.transform_without_affine(points[:, 0])
- x_points = x_points.reshape((len(x_points), 1))
- 
- if y.input_dims == 2:
- y_points, y_affine = y.transform_without_affine(points)
- y_points = y_points[:, 1:]
- else:
- y_points, y_affine = y.transform_without_affine(points[:, 1])
- y_points = y_points.reshape((len(y_points), 1))
-
- return ma.concatenate((x_points, y_points), 1), blended_transform_factory(x_affine, y_affine)
+ def transform_affine(self, points):
+ return points
+ 
+ def transform_non_affine(self, points):
+ return self.transform(points)
+ 
+ def get_affine(self):
+ return IdentityTransform()
 
 def inverted(self):
 return BlendedGenericTransform(self._x.inverted(), self._y.inverted())
- 
- def is_separable(self):
- return True
 
 
 class BlendedAffine1D(Affine2DBase, Transform):
@@ -829,17 +885,17 @@
 Affine2DBase.__init__(self)
 self._mtx = None
 
+ def is_separable(self):
+ return True
+ 
 def __repr__(self):
 return "BlendedAffine1D(%s,%s)" % (self._x, self._y)
 __str__ = __repr__
 
- def _do_invalidation(self):
+ def _do_invalidation(self, which_child, affine_only):
 self._mtx = None
- Affine2DBase._do_invalidation(self)
+ Affine2DBase._do_invalidation(self, which_child, affine_only)
 
- def is_separable(self):
- return True
-
 def get_matrix(self):
 if self._mtx is None:
 x_mtx = self._x.get_matrix()
@@ -854,9 +910,9 @@
 def __init__(self, x_transform, y_transform):
 assert x_transform.is_affine()
 assert y_transform.is_affine()
- # MGDTODO: Turn these checks back on
- # assert x_transform.is_separable()
- # assert y_transform.is_separable()
+ assert x_transform.is_separable()
+ assert y_transform.is_separable()
+
 Transform.__init__(self)
 self._x = x_transform
 self._y = y_transform
@@ -865,17 +921,17 @@
 Affine2DBase.__init__(self)
 self._mtx = None
 
+ def is_separable(self):
+ return True
+ 
 def __repr__(self):
 return "BlendedAffine2D(%s,%s)" % (self._x, self._y)
 __str__ = __repr__
 
- def _do_invalidation(self):
+ def _do_invalidation(self, which_child, affine_only):
 self._mtx = None
- Affine2DBase._do_invalidation(self)
+ Affine2DBase._do_invalidation(self, which_child, affine_only)
 
- def is_separable(self):
- return True
-
 def get_matrix(self):
 if self._mtx is None:
 if self._x == self._y:
@@ -909,8 +965,12 @@
 self._b = b
 self.set_children(['_a', '_b'])
 
- self.take_shortcut = b.is_affine()
-
+ def is_affine(self):
+ return self._a.is_affine() and self._b.is_affine()
+ 
+ def is_separable(self):
+ return self._a.is_separable() and self._b.is_separable()
+ 
 def __repr__(self):
 return "CompositeGenericTransform(%s, %s)" % (self._a, self._b)
 __str__ = __repr__
@@ -918,20 +978,24 @@
 def transform(self, points):
 return self._b.transform(self._a.transform(points))
 
- def transform_without_affine(self, points):
- if self.take_shortcut:
- return self._a.transform(points), self._b
- return self.transform(points), IDENTITY
+ def transform_affine(self, points):
+ return self._b.transform_affine(self._a.transform_affine(points))
+
+ def transform_non_affine(self, points):
+ return self._b.transform_non_affine(self._a.transform_non_affine(points))
+
+ def get_affine(self):
+ return self._a.get_affine() + self._b.get_affine()
 
 def inverted(self):
 return CompositeGenericTransform(self._b.inverted(), self._a.inverted())
- 
- def is_separable(self):
- return self._a.is_separable() and self._b.is_separable()
 
 
 class CompositeAffine2D(Affine2DBase):
 def __init__(self, a, b):
+ assert a.output_dims == b.input_dims
+ self.input_dims = a.input_dims
+ self.output_dims = b.output_dims
 assert a.is_affine()
 assert b.is_affine()
 
@@ -945,9 +1009,9 @@
 return "CompositeAffine2D(%s, %s)" % (self._a, self._b)
 __str__ = __repr__
 
- def _do_invalidation(self):
+ def _do_invalidation(self, which_child, affine_only):
 self._mtx = None
- Affine2DBase._do_invalidation(self)
+ Affine2DBase._do_invalidation(self, which_child, affine_only)
 
 def get_matrix(self):
 if self._mtx is None:
@@ -958,7 +1022,9 @@
 
 
 def composite_transform_factory(a, b):
- if a.is_affine() and b.is_affine():
+ if isinstance(a, BboxTransform) and isinstance(b, BboxTransform):
+ return BboxTransform(a._boxin, b._boxout)
+ if isinstance(a, AffineBase) and isinstance(b, AffineBase):
 return CompositeAffine2D(a, b)
 return CompositeGenericTransform(a, b)
 
@@ -972,33 +1038,6 @@
 return npy.log10(m)
 
 
-class TestLogTransform(Transform):
- input_dims = 1
- output_dims = 1
- def transform(self, a):
- marray = ma.masked_where(a <= 0.0, a * 10.0)
- return (npy.log10(marray) * 0.5) + 0.5
- 
- def inverted(self):
- return TestInvertLogTransform()
-
- def is_separable(self):
- return True
- 
-
-class TestInvertLogTransform(Transform):
- input_dims = 1
- output_dims = 1
- def transform(self, a):
- return ma.power(10, (a - 0.5) * 2.0) / 10.0
- 
- def inverted(self):
- return TestLogTransform()
-
- def is_separable(self):
- return True
-
-
 class TestPolarTransform(Transform):
 input_dims = 2
 output_dims = 2
@@ -1078,9 +1117,9 @@
 return "BboxTransform(%s, %s)" % (self._boxin, self._boxout)
 __str__ = __repr__
 
- def _do_invalidation(self):
+ def _do_invalidation(self, which_child, affine_only):
 self._mtx = None
- Affine2DBase._do_invalidation(self)
+ Affine2DBase._do_invalidation(self, which_child, affine_only)
 
 def is_separable(self):
 return True
@@ -1101,7 +1140,38 @@
 self._mtx = affine._mtx
 return self._mtx
 
+
+class TransformedPath(TransformNode):
+ def __init__(self, path, transform):
+ assert isinstance(transform, Transform)
+ TransformNode.__init__(self)
+ 
+ self._path = path
+ self._transform = transform
+ self.set_children(['_transform'])
+ self._transformed_path = None
+ 
+ def _do_invalidation(self, which_child, affine_only):
+ if not (affine_only[0].is_affine() or affine_only[0].is_bbox()):
+ self._transformed_path = None
+ 
+ def get_path_and_affine(self):
+ if self._transformed_path is None:
+ vertices = self._transform.transform_non_affine(self._path.vertices)
+ self._transformed_path = Path(vertices, self._path.codes)
+ return self._transformed_path, self._transform.get_affine()
+
+ def get_path(self):
+ if self._transformed_path is None:
+ vertices = self._tranform.transform_non_affine(self._path.vertices)
+ self._transformed_path = Path(vertices, self._path.codes)
+ vertices = self._transform.transform_affine(self._transformed_path.vertices)
+ return Path(vertices, self._transformed_path.codes)
+
+ def get_affine(self):
+ return self._transform.get_affine()
 
+ 
 def nonsingular(vmin, vmax, expander=0.001, tiny=1e-15, increasing=True):
 '''
 Ensure the endpoints of a range are not too close together.
@@ -1128,6 +1198,7 @@
 vmin, vmax = vmax, vmin
 return vmin, vmax
 
+
 # MGDTODO: Optimize (perhaps in an extension)
 def interval_contains(interval, val):
 return interval[0] <= val and interval[1] >= val
@@ -1173,8 +1244,8 @@
 bbox = Bbox.from_lbwh(10, 11, 12, 13)
 assert bbox.bounds == (10, 11, 12, 13)
 
- bbox_copy = copy.copy(bbox)
- assert bbox == bbox_copy
+ bbox_copy = copy.deepcopy(bbox)
+ assert (bbox.lbrt == bbox_copy.lbrt).all()
 bbox_copy.max = (14, 15)
 assert bbox.bounds == (10, 11, 12, 13)
 assert bbox_copy.bounds == (10, 11, 4, 4)
@@ -1183,7 +1254,7 @@
 bbox2 = Bbox([[30., 35.], [40., 45.]])
 trans = BboxTransform(bbox1, bbox2)
 bbox3 = bbox1.transformed(trans)
- assert bbox3 == bbox2
+ assert (bbox3.lbrt == bbox2.lbrt).all()
 
 translation = Affine2D().translate(10, 20)
 assert translation.to_values() == (1, 0, 0, 1, 10, 20)
@@ -1210,12 +1281,6 @@
 
 print points
 
- comp = TestLogTransform() + Affine2D().rotate_deg(15)
- tpoints = comp.transform(points)
- itpoints = comp.inverted().transform(tpoints)
- print tpoints, itpoints
- assert (points.round() == itpoints.round()).all()
- 
 # Here are some timing tests
 points = npy.asarray([(random(), random()) for i in xrange(10000)])
 t = timeit.Timer("trans_sum.transform(points)", "from __main__ import trans_sum, points")
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2007年09月25日 18:29:47
Revision: 3890
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3890&view=rev
Author: mdboom
Date: 2007年09月25日 11:29:44 -0700 (2007年9月25日)
Log Message:
-----------
Minor speed improvements in new transformations.
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/path.py
 branches/transforms/lib/matplotlib/text.py
 branches/transforms/lib/matplotlib/transforms.py
Modified: branches/transforms/lib/matplotlib/path.py
===================================================================
--- branches/transforms/lib/matplotlib/path.py	2007年09月25日 17:04:51 UTC (rev 3889)
+++ branches/transforms/lib/matplotlib/path.py	2007年09月25日 18:29:44 UTC (rev 3890)
@@ -41,9 +41,10 @@
 assert len(codes) == len(vertices)
 
 # The path being passed in may have masked values. However,
- # the backends are not expected to deal with masked arrays, so
- # we must remove them from the array (using compressed), and
- # add MOVETO commands to the codes array accordingly.
+ # the backends (and any affine transformations in matplotlib
+ # itself), are not expected to deal with masked arrays, so we
+ # must remove them from the array (using compressed), and add
+ # MOVETO commands to the codes array accordingly.
 mask = ma.getmask(vertices)
 if mask is not ma.nomask:
 mask1d = ma.mask_or(mask[:, 0], mask[:, 1])
Modified: branches/transforms/lib/matplotlib/text.py
===================================================================
--- branches/transforms/lib/matplotlib/text.py	2007年09月25日 17:04:51 UTC (rev 3889)
+++ branches/transforms/lib/matplotlib/text.py	2007年09月25日 18:29:44 UTC (rev 3890)
@@ -402,9 +402,7 @@
 return (x, y, self._text, self._color,
 self._verticalalignment, self._horizontalalignment,
 hash(self._fontproperties), self._rotation,
- # MGDTODO: Find a better way to determine if the
- # transform as changed
- str(self.get_transform())
+ self.get_transform().get_id()
 )
 
 def get_text(self):
Modified: branches/transforms/lib/matplotlib/transforms.py
===================================================================
--- branches/transforms/lib/matplotlib/transforms.py	2007年09月25日 17:04:51 UTC (rev 3889)
+++ branches/transforms/lib/matplotlib/transforms.py	2007年09月25日 18:29:44 UTC (rev 3890)
@@ -21,24 +21,28 @@
 # relationships
 
 class TransformNode(object):
+ _gid = 0
+ 
 def __init__(self):
- self._parents = Set()
- self._children = []
+ self._parents = WeakKeyDictionary()
+ self._children = Set()
+ self._id = TransformNode._gid
 
- def invalidate(self, which_child=None, affine_only=[]):
- if which_child is None:
- which_child = self
- self._do_invalidation(which_child, affine_only)
- # affine_only = affine_only and (self.is_affine() or self.is_bbox())
- for parent in self._parents:
- parent.invalidate(self, affine_only + [self])
+ def invalidate(self, affine_only=None):
+ if affine_only is None:
+ affine_only = self.is_affine() or self.is_bbox()
+ if not self._do_invalidation(affine_only):
+ self._id = TransformNode._gid
+ TransformNode._gid += 1
+ for parent in self._parents.iterkeys():
+ parent.invalidate(affine_only)
 
- def _do_invalidation(self, which_child, affine_only):
- pass
+ def _do_invalidation(self, affine_only):
+ return False
 
 def set_children(self, children):
 for child in children:
- getattr(self, child)._parents.add(self)
+ getattr(self, child)._parents[self] = None
 self._children = children
 
 def make_graphviz(self, fobj):
@@ -74,7 +78,10 @@
 def is_bbox(self):
 return False
 
+ def get_id(self):
+ return self._id
 
+ 
 class BboxBase(TransformNode):
 '''
 This is the read-only part of a bounding-box
@@ -214,6 +221,7 @@
 def __init__(self, points):
 BboxBase.__init__(self)
 self._points = npy.asarray(points, npy.float_)
+ self._invalid = False
 
 #@staticmethod
 def unit():
@@ -235,6 +243,11 @@
 return 'Bbox(%s)' % repr(self._points)
 __str__ = __repr__
 
+ def _do_invalidation(self, affine_only):
+ result = self._invalid
+ self._invalid = True
+ return result
+ 
 def update_from_data(self, x, y, ignore=True):
 	if ignore:
 	 self._points = npy.array(
@@ -294,6 +307,7 @@
 bounds = property(BboxBase._get_bounds, _set_bounds)
 
 def get_points(self):
+ self._invalid = False
 return self._points
 
 def set_points(self, points):
@@ -348,21 +362,23 @@
 assert transform.output_dims == 2
 
 BboxBase.__init__(self)
- self.bbox = bbox
- self.transform = transform
- self.set_children(['bbox', 'transform'])
+ 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)
+ return "TransformedBbox(%s, %s)" % (self._bbox, self._transform)
 __str__ = __repr__
 
- def _do_invalidation(self, which_child, affine_only):
+ def _do_invalidation(self, affine_only):
+ result = self._points is None
 self._points = None
+ return result
 
 def get_points(self):
 if self._points is None:
- self._points = self.transform.transform(self.bbox.get_points())
+ self._points = self._transform.transform(self._bbox.get_points())
 return self._points
 
 
@@ -461,9 +477,6 @@
 def __array__(self, *args, **kwargs):
 	return self.get_matrix()
 	
- def _do_invalidation(self, which_child, affine_only):
- self._inverted = None
-
 #@staticmethod
 def _concat(a, b):
 return npy.dot(b, a)
@@ -477,9 +490,6 @@
 def get_matrix(self):
 raise NotImplementedError()
 
- def transform_affine(self, points):
- return self.transform(points)
-
 def transform_non_affine(self, points):
 return points
 
@@ -528,9 +538,11 @@
 # print "".join(traceback.format_stack())
 # print points
 mtx = self.get_matrix()
- points = ma.asarray(values, npy.float_)
+ points = npy.asarray(values, npy.float_)
 return points * mtx[0,0] + mtx[0,1]
 
+ transform_affine = transform
+ 
 def inverted(self):
 if self._inverted is None:
 mtx = self.get_matrix()
@@ -575,7 +587,7 @@
 def set_matrix(self, mtx):
 self._mtx = mtx
 self.invalidate()
-
+ 
 def set(self, other):
 self._mtx = other.get_matrix()
 self.invalidate()
@@ -620,9 +632,11 @@
 return "IntervalTransform(%s)" % (getattr(self._bbox, self._direction))
 __str__ = __repr__
 
- def _do_invalidation(self, which_child, affine_only):
+ def _do_invalidation(self, affine_only):
+ result = self._mtx is None
 self._mtx = None
- Affine1DBase._do_invalidation(self, which_child, affine_only)
+ self._inverted = None
+ return result
 
 def get_matrix(self):
 if self._mtx is None:
@@ -678,12 +692,14 @@
 # print "".join(traceback.format_stack())
 # print points
 mtx = self.get_matrix()
- points = ma.asarray(points, npy.float_)
+ points = npy.asarray(points, npy.float_)
 points = points.transpose()
- points = ma.dot(mtx[0:2, 0:2], points)
+ points = npy.dot(mtx[0:2, 0:2], points)
 points = points + mtx[0:2, 2:]
 return points.transpose()
 
+ transform_affine = transform
+ 
 def inverted(self):
 if self._inverted is None:
 mtx = self.get_matrix()
@@ -801,19 +817,12 @@
 
 def transform(self, points):
 return points
+ transform_affine = transform_non_affine = transform
 
- def transform_affine(self, points):
- return points
-
- def transform_non_affine(self, points):
- return points
-
 def get_affine(self):
 return self
+ inverted = get_affine
 
- def inverted(self):
- return self
-
 
 class BlendedGenericTransform(Transform):
 input_dims = 2
@@ -857,14 +866,12 @@
 y_points = y.transform(points[:, 1])
 y_points = y_points.reshape((len(y_points), 1))
 
- return ma.concatenate((x_points, y_points), 1)
-
+ return npy.concatenate((x_points, y_points), 1)
+ transform_non_affine = transform
+ 
 def transform_affine(self, points):
 return points
 
- def transform_non_affine(self, points):
- return self.transform(points)
- 
 def get_affine(self):
 return IdentityTransform()
 
@@ -892,9 +899,10 @@
 return "BlendedAffine1D(%s,%s)" % (self._x, self._y)
 __str__ = __repr__
 
- def _do_invalidation(self, which_child, affine_only):
+ def _do_invalidation(self, affine_only):
+ result = self._mtx is None
 self._mtx = None
- Affine2DBase._do_invalidation(self, which_child, affine_only)
+ self._inverted = None
 
 def get_matrix(self):
 if self._mtx is None:
@@ -928,9 +936,11 @@
 return "BlendedAffine2D(%s,%s)" % (self._x, self._y)
 __str__ = __repr__
 
- def _do_invalidation(self, which_child, affine_only):
+ def _do_invalidation(self, affine_only):
+ result = self._mtx is None
 self._mtx = None
- Affine2DBase._do_invalidation(self, which_child, affine_only)
+ self._inverted = None
+ return result
 
 def get_matrix(self):
 if self._mtx is None:
@@ -985,7 +995,7 @@
 return self._b.transform_non_affine(self._a.transform_non_affine(points))
 
 def get_affine(self):
- return self._a.get_affine() + self._b.get_affine()
+ return CompositeAffine2D(self._a.get_affine(), self._b.get_affine())
 
 def inverted(self):
 return CompositeGenericTransform(self._b.inverted(), self._a.inverted())
@@ -1009,9 +1019,11 @@
 return "CompositeAffine2D(%s, %s)" % (self._a, self._b)
 __str__ = __repr__
 
- def _do_invalidation(self, which_child, affine_only):
+ def _do_invalidation(self, affine_only):
+ result = self._mtx is None
 self._mtx = None
- Affine2DBase._do_invalidation(self, which_child, affine_only)
+ self._inverted = None
+ return result
 
 def get_matrix(self):
 if self._mtx is None:
@@ -1117,10 +1129,12 @@
 return "BboxTransform(%s, %s)" % (self._boxin, self._boxout)
 __str__ = __repr__
 
- def _do_invalidation(self, which_child, affine_only):
+ def _do_invalidation(self, affine_only):
+ result = self._mtx is None
 self._mtx = None
- Affine2DBase._do_invalidation(self, which_child, affine_only)
-
+ self._inverted = None
+ return result
+ 
 def is_separable(self):
 return True
 
@@ -1148,21 +1162,19 @@
 
 self._path = path
 self._transform = transform
- self.set_children(['_transform'])
 self._transformed_path = None
+ self._last_id = transform.get_id()
 
- def _do_invalidation(self, which_child, affine_only):
- if not (affine_only[0].is_affine() or affine_only[0].is_bbox()):
- self._transformed_path = None
- 
 def get_path_and_affine(self):
- if self._transformed_path is None:
+ if (self._transformed_path is None or
+ self._last_id != self._transform.get_id()):
 vertices = self._transform.transform_non_affine(self._path.vertices)
 self._transformed_path = Path(vertices, self._path.codes)
 return self._transformed_path, self._transform.get_affine()
 
 def get_path(self):
- if self._transformed_path is None:
+ if (self._transformed_path is None or
+ self._last_id != self._transform.get_id()):
 vertices = self._tranform.transform_non_affine(self._path.vertices)
 self._transformed_path = Path(vertices, self._path.codes)
 vertices = self._transform.transform_affine(self._transformed_path.vertices)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2007年09月25日 19:54:01
Revision: 3892
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3892&view=rev
Author: mdboom
Date: 2007年09月25日 12:53:56 -0700 (2007年9月25日)
Log Message:
-----------
Important bugfixes.
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/lines.py
 branches/transforms/lib/matplotlib/path.py
 branches/transforms/lib/matplotlib/transforms.py
Modified: branches/transforms/lib/matplotlib/lines.py
===================================================================
--- branches/transforms/lib/matplotlib/lines.py	2007年09月25日 19:08:51 UTC (rev 3891)
+++ branches/transforms/lib/matplotlib/lines.py	2007年09月25日 19:53:56 UTC (rev 3892)
@@ -499,7 +499,7 @@
 lineFunc(renderer, gc, *self._transformed_path.get_path_and_affine())
 	 
 	# MGDTODO: Deal with markers
- if self._marker is not None and False:
+ if self._marker is not None:
 gc = renderer.new_gc()
 self._set_gc_clip(gc)
 gc.set_foreground(self.get_markeredgecolor())
@@ -507,7 +507,7 @@
 gc.set_alpha(self._alpha)
 funcname = self._markers.get(self._marker, '_draw_nothing')
 markerFunc = getattr(self, funcname)
- markerFunc(renderer, gc, self._path)
+ markerFunc(renderer, gc, *self._transformed_path.get_path_and_affine())
 
 #renderer.close_group('line2d')
 
Modified: branches/transforms/lib/matplotlib/path.py
===================================================================
--- branches/transforms/lib/matplotlib/path.py	2007年09月25日 19:08:51 UTC (rev 3891)
+++ branches/transforms/lib/matplotlib/path.py	2007年09月25日 19:53:56 UTC (rev 3892)
@@ -65,7 +65,10 @@
 
 def __repr__(self):
 	return "Path(%s, %s)" % (self.vertices, self.codes)
-	 
+
+ def __len__(self):
+ return len(self._vertices)
+ 
 def _get_codes(self):
 	return self._codes
 codes = property(_get_codes)
@@ -108,7 +111,7 @@
 	 # This initial rotation is to make sure the polygon always
 # "points-up"
 	 theta += npy.pi / 2.0
-	 verts = npy.concatenate((npy.cos(theta), npy.sin(theta)))
+	 verts = npy.concatenate((npy.cos(theta), npy.sin(theta)), 1)
 	 path = Path(verts)
 	 cls._unit_regular_polygons[numVertices] = path
 	return path
Modified: branches/transforms/lib/matplotlib/transforms.py
===================================================================
--- branches/transforms/lib/matplotlib/transforms.py	2007年09月25日 19:08:51 UTC (rev 3891)
+++ branches/transforms/lib/matplotlib/transforms.py	2007年09月25日 19:53:56 UTC (rev 3892)
@@ -24,7 +24,10 @@
 _gid = 0
 
 def __init__(self):
- self._parents = WeakKeyDictionary()
+ # MGDTODO: I'd like to use a WeakKeyDictionary here, but it makes
+ # these instances uncopyable. As it stands, _parents grows
+ # unboundedly... Not a good idea.
+ self._parents = Set()
 self._children = Set()
 self._id = TransformNode._gid
 
@@ -34,7 +37,7 @@
 if not self._do_invalidation(affine_only):
 self._id = TransformNode._gid
 TransformNode._gid += 1
- for parent in self._parents.iterkeys():
+ for parent in self._parents:
 parent.invalidate(affine_only)
 
 def _do_invalidation(self, affine_only):
@@ -42,7 +45,7 @@
 
 def set_children(self, children):
 for child in children:
- getattr(self, child)._parents[self] = None
+ getattr(self, child)._parents.add(self)
 self._children = children
 
 def make_graphviz(self, fobj):
@@ -1034,8 +1037,8 @@
 
 
 def composite_transform_factory(a, b):
- if isinstance(a, BboxTransform) and isinstance(b, BboxTransform):
- return BboxTransform(a._boxin, b._boxout)
+# if isinstance(a, BboxTransform) and isinstance(b, BboxTransform):
+# return BboxTransform(a._boxin, b._boxout)
 if isinstance(a, AffineBase) and isinstance(b, AffineBase):
 return CompositeAffine2D(a, b)
 return CompositeGenericTransform(a, b)
@@ -1162,19 +1165,23 @@
 
 self._path = path
 self._transform = transform
+ self.set_children(['_transform'])
 self._transformed_path = None
- self._last_id = transform.get_id()
+
+ def _do_invalidation(self, affine_only):
+ if not affine_only:
+ self._transformed_path = None
+ return True
 
 def get_path_and_affine(self):
- if (self._transformed_path is None or
- self._last_id != self._transform.get_id()):
+ if self._transformed_path is None:
 vertices = self._transform.transform_non_affine(self._path.vertices)
 self._transformed_path = Path(vertices, self._path.codes)
+
 return self._transformed_path, self._transform.get_affine()
 
 def get_path(self):
- if (self._transformed_path is None or
- self._last_id != self._transform.get_id()):
+ if self._transformed_path is None:
 vertices = self._tranform.transform_non_affine(self._path.vertices)
 self._transformed_path = Path(vertices, self._path.codes)
 vertices = self._transform.transform_affine(self._transformed_path.vertices)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2007年09月26日 13:54:39
Revision: 3895
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3895&view=rev
Author: mdboom
Date: 2007年09月26日 06:53:53 -0700 (2007年9月26日)
Log Message:
-----------
Fix log limits. For minor speed improvements.
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/axes.py
 branches/transforms/lib/matplotlib/axis.py
 branches/transforms/lib/matplotlib/lines.py
 branches/transforms/lib/matplotlib/scale.py
 branches/transforms/lib/matplotlib/ticker.py
 branches/transforms/lib/matplotlib/transforms.py
Modified: branches/transforms/lib/matplotlib/axes.py
===================================================================
--- branches/transforms/lib/matplotlib/axes.py	2007年09月26日 13:41:15 UTC (rev 3894)
+++ branches/transforms/lib/matplotlib/axes.py	2007年09月26日 13:53:53 UTC (rev 3895)
@@ -1095,18 +1095,9 @@
 line._remove_method = lambda h: self.lines.remove(h)
 
 def _update_line_limits(self, line):
- xdata = line.get_xdata(orig=False)
- ydata = line.get_ydata(orig=False)
+ xydata = line.get_xydata()
+ self.update_datalim( xydata )
 
- if line.get_transform() != self.transData:
- xys = self._get_verts_in_data_coords(
- line.get_transform(), zip(xdata, ydata))
- xdata = npy.array([x for x,y in xys])
- ydata = npy.array([y for x,y in xys])
-
- self.update_datalim_numerix( xdata, ydata )
-
-
 def add_patch(self, p):
 """
 Add a patch to the list of Axes patches; the clipbox will be
@@ -1151,7 +1142,6 @@
 xys = npy.asarray(xys)
 self.update_datalim_numerix(xys[:, 0], xys[:, 1])
 
-
 def update_datalim_numerix(self, x, y):
 'Update the data lim bbox with seq of xy tups'
 # if no data is set currently, the bbox will ignore it's
Modified: branches/transforms/lib/matplotlib/axis.py
===================================================================
--- branches/transforms/lib/matplotlib/axis.py	2007年09月26日 13:41:15 UTC (rev 3894)
+++ branches/transforms/lib/matplotlib/axis.py	2007年09月26日 13:53:53 UTC (rev 3895)
@@ -334,6 +334,9 @@
 'return the Interval instance for this axis view limits'
 return self.axes.viewLim.intervalx
 
+ def get_minpos(self):
+ return self.axes.dataLim.minposx
+ 
 def get_data_interval(self):
 'return the Interval instance for this axis data limits'
 return self.axes.dataLim.intervalx
@@ -458,6 +461,9 @@
 'return the Interval instance for this axis view limits'
 return self.axes.viewLim.intervaly
 
+ def get_minpos(self):
+ return self.axes.dataLim.minposy
+ 
 def get_data_interval(self):
 'return the Interval instance for this axis data limits'
 return self.axes.dataLim.intervaly
@@ -518,7 +524,13 @@
 def get_scale(self):
 return self._scale.name
 
- def set_scale(self, value, base=10, subs=None):
+ def set_scale(self, value, basex=10, subsx=None, basey=10, subsy=None):
+ if self.axis_name == 'x':
+ base = basex
+ subs = subsx
+ else:
+ base = basey
+ subs = subsy
 # MGDTODO: Move these settings (ticker etc.) into the scale class itself
 value = value.lower()
 assert value.lower() in ('log', 'linear')
@@ -534,7 +546,7 @@
 self.set_minor_locator(LogLocator(base,subs))
 # MGDTODO: Pass base along
 self._scale = LogScale()
- miny, maxy = getattr(self.axes.viewLim, 'interval' + self.axis)
+ miny, maxy = getattr(self.axes.viewLim, 'interval' + self.axis_name)
 if min(miny, maxy)<=0:
 self.axes.autoscale_view()
 
@@ -980,7 +992,7 @@
 
 class XAxis(Axis):
 __name__ = 'xaxis'
- axis = 'x'
+ axis_name = 'x'
 
 def contains(self,mouseevent):
 """Test whether the mouse event occured in the x axis.
@@ -1156,6 +1168,9 @@
 'return the Interval instance for this axis view limits'
 return self.axes.viewLim.intervalx
 
+ def get_minpos(self):
+ return self.axes.dataLim.minposx
+ 
 def get_data_interval(self):
 'return the Interval instance for this axis data limits'
 return self.axes.dataLim.intervalx
@@ -1163,7 +1178,7 @@
 
 class YAxis(Axis):
 __name__ = 'yaxis'
- axis = 'y'
+ axis_name = 'y'
 
 def contains(self,mouseevent):
 """Test whether the mouse event occurred in the y axis.
@@ -1357,6 +1372,9 @@
 'return the Interval instance for this axis view limits'
 return self.axes.viewLim.intervaly
 
+ def get_minpos(self):
+ return self.axes.dataLim.minposy
+ 
 def get_data_interval(self):
 'return the Interval instance for this axis data limits'
 return self.axes.dataLim.intervaly
Modified: branches/transforms/lib/matplotlib/lines.py
===================================================================
--- branches/transforms/lib/matplotlib/lines.py	2007年09月26日 13:41:15 UTC (rev 3894)
+++ branches/transforms/lib/matplotlib/lines.py	2007年09月26日 13:53:53 UTC (rev 3895)
@@ -564,6 +564,9 @@
 return self._yorig
 return self._y
 
+ def get_xydata(self):
+ return self._xy
+ 
 def set_antialiased(self, b):
 """
 True if line should be drawin with antialiased rendering
Modified: branches/transforms/lib/matplotlib/scale.py
===================================================================
--- branches/transforms/lib/matplotlib/scale.py	2007年09月26日 13:41:15 UTC (rev 3894)
+++ branches/transforms/lib/matplotlib/scale.py	2007年09月26日 13:53:53 UTC (rev 3895)
@@ -13,6 +13,66 @@
 return IdentityTransform()
 
 class LogScale(ScaleBase):
+ class Log10Transform(Transform):
+ input_dims = 1
+ output_dims = 1
+ def __init__(self):
+ Transform.__init__(self)
+
+ def is_separable(self):
+ return True
+ 
+ def transform(self, a):
+ return ma.log10(ma.masked_where(a <= 0.0, a * 10.0))
+ 
+ def inverted(self):
+ return LogScale.InvertedLog10Transform()
+
+ class InvertedLog10Transform(Transform):
+ input_dims = 1
+ output_dims = 1
+ def __init__(self):
+ Transform.__init__(self)
+
+ def is_separable(self):
+ return True
+ 
+ def transform(self, a):
+ return ma.power(10.0, a) / 10.0
+
+ def inverted(self):
+ return LogScale.Log10Transform()
+
+ class Log2Transform(Transform):
+ input_dims = 1
+ output_dims = 1
+ def __init__(self):
+ Transform.__init__(self)
+
+ def is_separable(self):
+ return True
+ 
+ def transform(self, a):
+ return ma.log2(ma.masked_where(a <= 0.0, a * 2.0))
+ 
+ def inverted(self):
+ return LogScale.InvertedLog2Transform()
+
+ class InvertedLog2Transform(Transform):
+ input_dims = 1
+ output_dims = 1
+ def __init__(self):
+ Transform.__init__(self)
+
+ def is_separable(self):
+ return True
+ 
+ def transform(self, a):
+ return ma.power(2.0, a) / 2.0
+
+ def inverted(self):
+ return LogScale.Log2Transform()
+
 class LogTransform(Transform):
 input_dims = 1
 output_dims = 1
@@ -26,12 +86,12 @@
 def transform(self, a):
 if len(a) > 10:
 print "Log Transforming..."
- return ma.log10(ma.masked_where(a <= 0.0, a * 10.0))
+ return ma.log(ma.masked_where(a <= 0.0, a * self._base)) / npy.log(self._base)
 
 def inverted(self):
 return LogScale.InvertedLogTransform(self._base)
 
- class InvertedLogTransform(Transform):
+ class InvertedLog2Transform(Transform):
 input_dims = 1
 output_dims = 1
 def __init__(self, base):
@@ -42,14 +102,21 @@
 return True
 
 def transform(self, a):
- return ma.power(10.0, a) / 10.0
+ return ma.power(self._base, a) / self._base
 
 def inverted(self):
 return LogScale.LogTransform(self._base)
+ 
+ 
+ def __init__(self, base=10):
+ if base == 10.0:
+ self._transform = self.Log10Transform()
+ elif base == 2.0:
+ self._transform = self.Log2Transform()
+ # MGDTODO: Natural log etc.
+ else:
+ self._transform = self.LogTransform(base)
 
- def __init__(self, base=10):
- self._transform = self.LogTransform(base)
-
 def get_transform(self):
 return self._transform
 
Modified: branches/transforms/lib/matplotlib/ticker.py
===================================================================
--- branches/transforms/lib/matplotlib/ticker.py	2007年09月26日 13:41:15 UTC (rev 3894)
+++ branches/transforms/lib/matplotlib/ticker.py	2007年09月26日 13:53:53 UTC (rev 3895)
@@ -919,21 +919,21 @@
 
 def autoscale(self):
 'Try to choose the view limits intelligently'
- vmin, vmax = self.axis.get_view_interval()
+ vmin, vmax = self.axis.get_data_interval()
 if vmax<vmin:
 vmin, vmax = vmax, vmin
 
-# minpos = self.dataInterval.minpos()
+ minpos = self.axis.get_minpos()
 
-# if minpos<=0:
-# raise RuntimeError('No positive data to plot')
+ if minpos<=0:
+ raise RuntimeError('No positive data to plot')
 
- # MGDTODO: Find a good way to track minpos
- if vmin <= 0.0:
- vmin = 0.1
- 
+ if vmin <= minpos:
+ vmin = minpos
+
 if not is_decade(vmin,self._base): vmin = decade_down(vmin,self._base)
 if not is_decade(vmax,self._base): vmax = decade_up(vmax,self._base)
+
 if vmin==vmax:
 vmin = decade_down(vmin,self._base)
 vmax = decade_up(vmax,self._base)
Modified: branches/transforms/lib/matplotlib/transforms.py
===================================================================
--- branches/transforms/lib/matplotlib/transforms.py	2007年09月26日 13:41:15 UTC (rev 3894)
+++ branches/transforms/lib/matplotlib/transforms.py	2007年09月26日 13:53:53 UTC (rev 3895)
@@ -224,6 +224,7 @@
 def __init__(self, points):
 BboxBase.__init__(self)
 self._points = npy.asarray(points, npy.float_)
+ self._minpos = npy.array([0.0000001, 0.0000001])
 self._invalid = False
 
 #@staticmethod
@@ -252,15 +253,22 @@
 return result
 
 def update_from_data(self, x, y, ignore=True):
-	if ignore:
+ if ignore:
+ self._points = npy.array(
+ [[x.min(), y.min()], [x.max(), y.max()]],
+ npy.float_)
+ self._minpos = npy.array(
+ [npy.where(x > 0.0, x, npy.inf).min(), npy.where(y > 0.0, y, npy.inf).min()],
+ npy.float_)
+ else:
 	 self._points = npy.array(
-		[[x.min(), y.min()], [x.max(), y.max()]],
-		npy.float_)
-	else:
-	 self._points = npy.array(
 		[[min(x.min(), self.xmin), min(y.min(), self.ymin)],
 		 [max(x.max(), self.xmax), max(y.max(), self.ymax)]],
 		 npy.float_)
+ minpos = npy.array(
+ [npy.where(x > 0.0, x, npy.inf).min(), npy.where(y > 0.0, y, npy.inf).min()],
+ npy.float_)
+ self._minpos = npy.minimum(minpos, self._minpos)
 self.invalidate()
 
 def _set_xmin(self, val):
@@ -309,6 +317,18 @@
 self.invalidate()
 bounds = property(BboxBase._get_bounds, _set_bounds)
 
+ def _get_minpos(self):
+ return self._minpos
+ minpos = property(_get_minpos)
+
+ def _get_minposx(self):
+ return self._minpos[0]
+ minposx = property(_get_minposx)
+
+ def _get_minposy(self):
+ return self._minpos[1]
+ minposy = property(_get_minposy)
+ 
 def get_points(self):
 self._invalid = False
 return self._points
@@ -541,7 +561,7 @@
 # print "".join(traceback.format_stack())
 # print points
 mtx = self.get_matrix()
- points = npy.asarray(values, npy.float_)
+ # points = npy.asarray(values, npy.float_)
 return points * mtx[0,0] + mtx[0,1]
 
 transform_affine = transform
@@ -695,10 +715,15 @@
 # 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:]
+ if ma.isarray(points):
+ points = points.transpose()
+ points = ma.dot(mtx[0:2, 0:2], points)
+ points = points + mtx[0:2, 2:]
+ else:
+ 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()
 
 transform_affine = transform
@@ -869,7 +894,7 @@
 y_points = y.transform(points[:, 1])
 y_points = y_points.reshape((len(y_points), 1))
 
- return npy.concatenate((x_points, y_points), 1)
+ return ma.concatenate((x_points, y_points), 1)
 transform_non_affine = transform
 
 def transform_affine(self, points):
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2007年09月26日 14:09:29
Revision: 3897
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3897&view=rev
Author: mdboom
Date: 2007年09月26日 07:08:12 -0700 (2007年9月26日)
Log Message:
-----------
Fix log transforms a little.
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/scale.py
 branches/transforms/lib/matplotlib/transforms.py
Modified: branches/transforms/lib/matplotlib/scale.py
===================================================================
--- branches/transforms/lib/matplotlib/scale.py	2007年09月26日 13:55:41 UTC (rev 3896)
+++ branches/transforms/lib/matplotlib/scale.py	2007年09月26日 14:08:12 UTC (rev 3897)
@@ -73,6 +73,36 @@
 def inverted(self):
 return LogScale.Log2Transform()
 
+ class NaturalLogTransform(Transform):
+ input_dims = 1
+ output_dims = 1
+ def __init__(self):
+ Transform.__init__(self)
+
+ def is_separable(self):
+ return True
+ 
+ def transform(self, a):
+ return ma.log(ma.masked_where(a <= 0.0, a * npy.e))
+ 
+ def inverted(self):
+ return LogScale.InvertedNaturalLogTransform()
+
+ class InvertedNaturalLogTransform(Transform):
+ input_dims = 1
+ output_dims = 1
+ def __init__(self):
+ Transform.__init__(self)
+
+ def is_separable(self):
+ return True
+ 
+ def transform(self, a):
+ return ma.power(npy.e, a) / npy.e
+
+ def inverted(self):
+ return LogScale.Log2Transform()
+ 
 class LogTransform(Transform):
 input_dims = 1
 output_dims = 1
@@ -84,14 +114,12 @@
 return True
 
 def transform(self, a):
- if len(a) > 10:
- print "Log Transforming..."
 return ma.log(ma.masked_where(a <= 0.0, a * self._base)) / npy.log(self._base)
 
 def inverted(self):
 return LogScale.InvertedLogTransform(self._base)
 
- class InvertedLog2Transform(Transform):
+ class InvertedLogTransform(Transform):
 input_dims = 1
 output_dims = 1
 def __init__(self, base):
@@ -113,7 +141,8 @@
 self._transform = self.Log10Transform()
 elif base == 2.0:
 self._transform = self.Log2Transform()
- # MGDTODO: Natural log etc.
+ elif base == npy.e:
+ self._transform = self.NaturalLogTransform()
 else:
 self._transform = self.LogTransform(base)
 
Modified: branches/transforms/lib/matplotlib/transforms.py
===================================================================
--- branches/transforms/lib/matplotlib/transforms.py	2007年09月26日 13:55:41 UTC (rev 3896)
+++ branches/transforms/lib/matplotlib/transforms.py	2007年09月26日 14:08:12 UTC (rev 3897)
@@ -1069,15 +1069,6 @@
 return CompositeGenericTransform(a, b)
 
 
-class LogTransform(Transform):
- input_dims = 1
- output_dims = 1
- 
- def transform(self, a):
- m = ma.masked_where(a < 0, a)
- return npy.log10(m)
-
-
 class TestPolarTransform(Transform):
 input_dims = 2
 output_dims = 2
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2007年10月01日 11:45:06
Revision: 3905
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3905&view=rev
Author: mdboom
Date: 2007年10月01日 04:44:54 -0700 (2007年10月01日)
Log Message:
-----------
Move ticking/formatting defaults to scale.py. Speed improvements in transforms.py
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/axes.py
 branches/transforms/lib/matplotlib/axis.py
 branches/transforms/lib/matplotlib/backend_bases.py
 branches/transforms/lib/matplotlib/backends/backend_agg.py
 branches/transforms/lib/matplotlib/cbook.py
 branches/transforms/lib/matplotlib/lines.py
 branches/transforms/lib/matplotlib/path.py
 branches/transforms/lib/matplotlib/scale.py
 branches/transforms/lib/matplotlib/transforms.py
Modified: branches/transforms/lib/matplotlib/axes.py
===================================================================
--- branches/transforms/lib/matplotlib/axes.py	2007年10月01日 07:06:43 UTC (rev 3904)
+++ branches/transforms/lib/matplotlib/axes.py	2007年10月01日 11:44:54 UTC (rev 3905)
@@ -23,6 +23,7 @@
 from matplotlib import mlab
 from matplotlib import cm
 from matplotlib import patches as mpatches
+from matplotlib import path as mpath
 from matplotlib import pbox as mpbox
 from matplotlib import quiver as mquiver
 from matplotlib import scale as mscale
@@ -1461,7 +1462,7 @@
 self.axesPatch.set_facecolor(color)
 
 ### data limits, ticks, tick labels, and formatting
-
+ 
 def get_xlim(self):
 'Get the x axis range [xmin, xmax]'
 return self.viewLim.intervalx
@@ -1503,11 +1504,6 @@
 if xmin is None: xmin = old_xmin
 if xmax is None: xmax = old_xmax
 
-	# MGDTODO
-# if (self.transData.get_funcx().get_type()==mtrans.LOG10
-# and min(xmin, xmax)<=0):
-# raise ValueError('Cannot set nonpositive limits with log transform')
-
 xmin, xmax = mtransforms.nonsingular(xmin, xmax, increasing=False)
 
 	self.viewLim.intervalx = (xmin, xmax)
@@ -1516,7 +1512,7 @@
 	 # Call all of the other x-axes that are shared with this one
 	 for other in self._shared_x_axes.get_siblings(self):
 		if other is not self:
-		 other.set_xlim(self.viewLim.xmin, self.viewLim.xmax, emit=False)
+		 other.set_xlim(self.viewLim.intervalx, emit=False)
 	 
 return xmin, xmax
 
@@ -1634,7 +1630,7 @@
 'return the yaxis scale string: log or linear'
 return self.yaxis.get_scale()
 
- def set_yscale(self, value, basey=10, subsy=None):
+ def set_yscale(self, value, **kwargs):
 """
 SET_YSCALE(value, basey=10, subsy=None)
 
@@ -1652,7 +1648,7 @@
 
 ACCEPTS: ['log' | 'linear']
 """
- self.yaxis.set_scale(value, basey, subsy)
+ self.yaxis.set_scale(value, **kwargs)
 self._update_transScale()
 
 def get_yticks(self):
@@ -1788,6 +1784,32 @@
 """
 self._navigate_mode = b
 
+ def drag_pan(self, button, x, y, startx, starty, start_lim, start_trans):
+ if button == 1:
+ inverse = start_trans.inverted()
+ dx = startx - x
+ dy = starty - y
+ result = self.bbox.frozen().translated(dx, dy).transformed(inverse)
+ elif button == 3:
+ try:
+ inverse = start_trans.inverted()
+ dx = (startx - x) / float(self.bbox.width)
+ dy = (starty - y) / float(self.bbox.height)
+ xmin, ymin, xmax, ymax = start_lim.lbrt
+
+ alpha = npy.power(10.0, (dx, dy))
+ start = inverse.transform_point((startx, starty))
+ lim_points = start_lim.get_points()
+ result = start + alpha * (lim_points - start)
+ result = mtransforms.Bbox(result)
+ except OverflowError:
+ warnings.warn('Overflow while panning')
+ return
+ 
+ # MGDTODO: Could we do this with a single set_lim?
+ self.set_xlim(*result.intervalx)
+ self.set_ylim(*result.intervaly)
+ 
 def get_cursor_props(self):
 """return the cursor props as a linewidth, color tuple where
 linewidth is a float and color is an RGBA tuple"""
@@ -5658,8 +5680,253 @@
 self, fig,
 [self.figLeft, self.figBottom, self.figW, self.figH], **kwargs)
 
+######################################################################
+# New Polar Axes
+ 
+class PolarAxes(Axes):
+ class PolarTransform(mtransforms.Transform):
+ input_dims = 2
+ output_dims = 2
+ is_separable = False
 
+ def transform(self, tr):
+ xy = npy.zeros(tr.shape, npy.float_)
+ t = tr[:, 0:1]
+ r = tr[:, 1:2]
+ x = xy[:, 0:1]
+ y = xy[:, 1:2]
+ x += r * npy.cos(t)
+ y += r * npy.sin(t)
+ return xy
+ transform_non_affine = transform
 
+ def interpolate(self, a, steps):
+ steps = npy.floor(steps)
+ new_length = ((len(a) - 1) * steps) + 1
+ new_shape = list(a.shape)
+ new_shape[0] = new_length
+ result = npy.zeros(new_shape, a.dtype)
+
+ result[0] = a[0]
+ a0 = a[0:-1]
+ a1 = a[1: ]
+ delta = ((a1 - a0) / steps)
+ 
+ for i in range(1, int(steps)+1):
+ result[i::steps] = delta * i + a0
+
+ return result
+ 
+# def transform_path(self, path):
+# twopi = 2.0 * npy.pi
+# halfpi = 0.5 * npy.pi
+ 
+# vertices = path.vertices
+# t0 = vertices[0:-1, 0]
+# t1 = vertices[1: , 0]
+# td = npy.where(t1 > t0, t1 - t0, twopi - (t0 - t1))
+# maxtd = td.max()
+# interpolate = npy.ceil(maxtd / halfpi)
+# if interpolate > 1.0:
+# vertices = self.interpolate(vertices, interpolate)
+
+# vertices = self.transform(vertices)
+
+# result = npy.zeros((len(vertices) * 3 - 2, 2), npy.float_)
+# codes = mpath.Path.CURVE4 * npy.ones((len(vertices) * 3 - 2, ), mpath.Path.code_type)
+# result[0] = vertices[0]
+# codes[0] = mpath.Path.MOVETO
+
+# kappa = 4.0 * ((npy.sqrt(2.0) - 1.0) / 3.0)
+# kappa = 0.5
+ 
+# p0 = vertices[0:-1]
+# p1 = vertices[1: ]
+
+# x0 = p0[:, 0:1]
+# y0 = p0[:, 1: ]
+# b0 = ((y0 - x0) - y0) / ((x0 + y0) - x0)
+# a0 = y0 - b0*x0
+
+# x1 = p1[:, 0:1]
+# y1 = p1[:, 1: ]
+# b1 = ((y1 - x1) - y1) / ((x1 + y1) - x1)
+# a1 = y1 - b1*x1
+
+# x = -(a0-a1) / (b0-b1)
+# y = a0 + b0*x
+
+# xk = (x - x0) * kappa + x0
+# yk = (y - y0) * kappa + y0
+
+# result[1::3, 0:1] = xk
+# result[1::3, 1: ] = yk
+
+# xk = (x - x1) * kappa + x1
+# yk = (y - y1) * kappa + y1
+
+# result[2::3, 0:1] = xk
+# result[2::3, 1: ] = yk
+ 
+# result[3::3] = p1
+
+# print vertices[-2:]
+# print result[-2:]
+ 
+# return mpath.Path(result, codes)
+ 
+# twopi = 2.0 * npy.pi
+# halfpi = 0.5 * npy.pi
+ 
+# vertices = path.vertices
+# t0 = vertices[0:-1, 0]
+# t1 = vertices[1: , 0]
+# td = npy.where(t1 > t0, t1 - t0, twopi - (t0 - t1))
+# maxtd = td.max()
+# interpolate = npy.ceil(maxtd / halfpi)
+
+# print "interpolate", interpolate
+# if interpolate > 1.0:
+# vertices = self.interpolate(vertices, interpolate)
+ 
+# result = npy.zeros((len(vertices) * 3 - 2, 2), npy.float_)
+# codes = mpath.Path.CURVE4 * npy.ones((len(vertices) * 3 - 2, ), mpath.Path.code_type)
+# result[0] = vertices[0]
+# codes[0] = mpath.Path.MOVETO
+
+# kappa = 4.0 * ((npy.sqrt(2.0) - 1.0) / 3.0)
+# tkappa = npy.arctan(kappa)
+# hyp_kappa = npy.sqrt(kappa*kappa + 1.0)
+
+# t0 = vertices[0:-1, 0]
+# t1 = vertices[1: , 0]
+# r0 = vertices[0:-1, 1]
+# r1 = vertices[1: , 1]
+
+# td = npy.where(t1 > t0, t1 - t0, twopi - (t0 - t1))
+# td_scaled = td / (npy.pi * 0.5)
+# rd = r1 - r0
+# r0kappa = r0 * kappa * td_scaled
+# r1kappa = r1 * kappa * td_scaled
+# ravg_kappa = ((r1 + r0) / 2.0) * kappa * td_scaled
+
+# result[1::3, 0] = t0 + (tkappa * td_scaled)
+# result[1::3, 1] = r0*hyp_kappa
+# # result[1::3, 1] = r0 / npy.cos(tkappa * td_scaled) # npy.sqrt(r0*r0 + ravg_kappa*ravg_kappa)
+
+# result[2::3, 0] = t1 - (tkappa * td_scaled)
+# result[2::3, 1] = r1*hyp_kappa
+# # result[2::3, 1] = r1 / npy.cos(tkappa * td_scaled) # npy.sqrt(r1*r1 + ravg_kappa*ravg_kappa)
+ 
+# result[3::3, 0] = t1
+# result[3::3, 1] = r1
+
+# print vertices[:6], result[:6], t0[:6], t1[:6], td[:6], td_scaled[:6], tkappa
+# result = self.transform(result)
+# return mpath.Path(result, codes)
+# transform_path_non_affine = transform_path
+
+ def inverted(self):
+ return PolarAxes.InvertedPolarTransform()
+
+ class PolarAffine(mtransforms.Affine2DBase):
+ def __init__(self, limits):
+ mtransforms.Affine2DBase.__init__(self)
+ self._limits = limits
+ self.set_children(limits)
+ self._mtx = None
+
+ def get_matrix(self):
+ if self._invalid:
+ xmin, ymin, xmax, ymax = self._limits.lbrt
+ affine = mtransforms.Affine2D().rotate(xmin).scale(0.5 / ymax).translate(0.5, 0.5)
+ self._mtx = affine.get_matrix()
+ self._inverted = None
+ self._invalid = 0
+ return self._mtx
+ 
+ class InvertedPolarTransform(mtransforms.Transform):
+ input_dims = 2
+ output_dims = 2
+ is_separable = False
+
+ def transform(self, xy):
+ x = xy[:, 0:1]
+ y = xy[:, 1:]
+ r = npy.sqrt(x*x + y*y)
+ theta = npy.arccos(x / r)
+ theta = npy.where(y < 0, 2 * npy.pi - theta, theta)
+ return npy.concatenate((theta, r), 1)
+
+ def inverted(self):
+ return PolarAxes.PolarTransform()
+ 
+ def _set_lim_and_transforms(self):
+ """
+ set the dataLim and viewLim BBox attributes and the
+ transData and transAxes Transformation attributes
+ """
+	self.dataLim = mtransforms.Bbox.unit()
+ self.viewLim = mtransforms.Bbox.unit()
+ self.transAxes = mtransforms.BboxTransform(
+ mtransforms.Bbox.unit(), self.bbox)
+
+ # Transforms the x and y axis separately by a scale factor
+ # It is assumed that this part will have non-linear components
+ self.transScale = mtransforms.TransformWrapper(mtransforms.IdentityTransform())
+
+ # A (possibly non-linear) projection on the (already scaled) data
+ self.transProjection = self.PolarTransform()
+
+ # An affine transformation on the data, generally to limit the
+ # range of the axes
+ self.transProjectionAffine = self.PolarAffine(self.viewLim)
+ 
+ self.transData = self.transScale + self.transProjection + \
+ self.transProjectionAffine + self.transAxes
+
+ def drag_pan(self, button, x, y, startx, starty, start_lim, start_trans):
+ if button == 1:
+ inverse = start_trans.inverted()
+ startt, startr = inverse.transform_point((startx, starty))
+ t, r = inverse.transform_point((x, y))
+
+ scale = r / startr
+ self.set_ylim(start_lim.ymin, start_lim.ymax / scale)
+
+ dt0 = t - startt
+ dt1 = startt - t
+ if abs(dt1) < abs(dt0):
+ dt = abs(dt1) * sign(dt0) * -1.0
+ else:
+ dt = dt0 * -1.0
+ self.set_xlim(start_lim.xmin - dt, start_lim.xmin - dt + npy.pi*2.0)
+ 
+ def set_rmax(self, rmax):
+ self.viewLim.maxy = rmax
+ 
+class PolarSubplot(SubplotBase, PolarAxes):
+ """
+ Create a polar subplot with
+
+ PolarSubplot(numRows, numCols, plotNum)
+
+ where plotNum=1 is the first plot number and increasing plotNums
+ fill rows first. max(plotNum)==numRows*numCols
+
+ You can leave out the commas if numRows<=numCols<=plotNum<10, as
+ in
+
+ Subplot(211) # 2 rows, 1 column, first (upper) plot
+ """
+ def __str__(self):
+ return "PolarSubplot(%gx%g)"%(self.figW,self.figH)
+ def __init__(self, fig, *args, **kwargs):
+ SubplotBase.__init__(self, fig, *args)
+ PolarAxes.__init__(
+ self, fig,
+ [self.figLeft, self.figBottom, self.figW, self.figH], **kwargs)
+ 
 martist.kwdocd['Axes'] = martist.kwdocd['Subplot'] = martist.kwdoc(Axes)
 """
 # this is some discarded code I was using to find the minimum positive
Modified: branches/transforms/lib/matplotlib/axis.py
===================================================================
--- branches/transforms/lib/matplotlib/axis.py	2007年10月01日 07:06:43 UTC (rev 3904)
+++ branches/transforms/lib/matplotlib/axis.py	2007年10月01日 11:44:54 UTC (rev 3905)
@@ -20,7 +20,7 @@
 from transforms import Affine2D, Bbox, blended_transform_factory, interval_contains, \
 interval_contains_open, IntervalTransform
 from patches import bbox_artist
-from scale import LinearScale, LogScale
+from scale import scale_factory
 
 import matplotlib.units as units
 #import pdb
@@ -514,41 +514,19 @@
 self.majorTicks = []
 self.minorTicks = []
 self.pickradius = pickradius
- self._scale = LinearScale()
 
 self.cla()
-
+ self.set_scale('linear')
+ 
 def get_transform(self):
 return self._scale.get_transform()
- 
+
 def get_scale(self):
 return self._scale.name
 
- def set_scale(self, value, basex=10, subsx=None, basey=10, subsy=None):
- if self.axis_name == 'x':
- base = basex
- subs = subsx
- else:
- base = basey
- subs = subsy
- # MGDTODO: Move these settings (ticker etc.) into the scale class itself
- value = value.lower()
- assert value.lower() in ('log', 'linear')
- if value == 'linear':
- self.set_major_locator(AutoLocator())
- self.set_major_formatter(ScalarFormatter())
- self.set_minor_locator(NullLocator())
- self.set_minor_formatter(NullFormatter())
- self._scale = LinearScale()
- elif value == 'log':
- self.set_major_locator(LogLocator(base))
- self.set_major_formatter(LogFormatterMathtext(base))
- self.set_minor_locator(LogLocator(base,subs))
- # MGDTODO: Pass base along
- self._scale = LogScale()
- miny, maxy = getattr(self.axes.viewLim, 'interval' + self.axis_name)
- if min(miny, maxy)<=0:
- self.axes.autoscale_view()
+ def set_scale(self, value, **kwargs):
+ self._scale = scale_factory(value, self, **kwargs)
+ self._scale.set_default_locators_and_formatters(self)
 
 def get_children(self):
 children = [self.label]
Modified: branches/transforms/lib/matplotlib/backend_bases.py
===================================================================
--- branches/transforms/lib/matplotlib/backend_bases.py	2007年10月01日 07:06:43 UTC (rev 3904)
+++ branches/transforms/lib/matplotlib/backend_bases.py	2007年10月01日 11:44:54 UTC (rev 3905)
@@ -1483,7 +1483,7 @@
 self._lastCursor = cursors.SELECT_REGION
 if self._xypress:
 x, y = event.x, event.y
- lastx, lasty, a, ind, lim, trans= self._xypress[0]
+ lastx, lasty, a, ind, lim, trans = self._xypress[0]
 self.draw_rubberband(event, x, y, lastx, lasty)
 elif (self._active=='PAN' and
 self._lastCursor != cursors.MOVE):
@@ -1558,10 +1558,7 @@
 self._xypress=[]
 for i, a in enumerate(self.canvas.figure.get_axes()):
 if x is not None and y is not None and a.in_axes(x, y) and a.get_navigate():
- xmin, xmax = a.get_xlim()
- ymin, ymax = a.get_ylim()
- lim = xmin, xmax, ymin, ymax
- self._xypress.append((x, y, a, i, lim, copy.deepcopy(a.transData)))
+ self._xypress.append((x, y, a, i, a.viewLim.frozen(), a.transData.frozen()))
 self.canvas.mpl_disconnect(self._idDrag)
 self._idDrag=self.canvas.mpl_connect('motion_notify_event', self.drag_pan)
 
@@ -1585,10 +1582,7 @@
 self._xypress=[]
 for i, a in enumerate(self.canvas.figure.get_axes()):
 if x is not None and y is not None and a.in_axes(x, y) and a.get_navigate():
- xmin, xmax = a.get_xlim()
- ymin, ymax = a.get_ylim()
- lim = xmin, xmax, ymin, ymax
- self._xypress.append(( x, y, a, i, lim, copy.deepcopy(a.transData) ))
+ self._xypress.append(( x, y, a, i, a.viewLim.frozen(), a.transData.frozen()))
 
 self.press(event)
 
@@ -1648,38 +1642,12 @@
 dx=dx/abs(dx)*abs(dy)
 return (dx,dy)
 
- for cur_xypress in self._xypress:
- lastx, lasty, a, ind, lim, trans = cur_xypress
- xmin, xmax, ymin, ymax = lim
+ for lastx, lasty, a, ind, old_lim, old_trans in self._xypress:
 #safer to use the recorded button at the press than current button:
 #multiple button can get pressed during motion...
- if self._button_pressed==1:
-		inverse = trans.inverted()
- dx, dy = event.x - lastx, event.y - lasty
- dx, dy = format_deltas(event, dx, dy)
- delta = npy.array([[dx, dy], [dx, dy]], npy.float_)
- bbox = transforms.Bbox(a.bbox.get_points() - delta)
- result = bbox.transformed(inverse)
- elif self._button_pressed==3:
- try:
- inverse = trans.inverted()
- dx=(lastx-event.x)/float(a.bbox.width)
- dy=(lasty-event.y)/float(a.bbox.height)
- alphax = pow(10.0, dx)
- alphay = pow(10.0, dy)
- # MGDTODO: Make better use of numpy
- lastx, lasty = inverse.transform_point((lastx, lasty))
- xmin = (lastx + alphax * (xmin - lastx))
- xmax = (lastx + alphax * (xmax - lastx))
- ymin = (lasty + alphay * (ymin - lasty))
- ymax = (lasty + alphay * (ymax - lasty))
- result = transforms.Bbox.from_lbrt(xmin, ymin, xmax, ymax)
- except OverflowError:
- warnings.warn('Overflow while panning')
- return
- a.set_xlim(*result.intervalx)
- a.set_ylim(*result.intervaly)
-
+ dx, dy = event.x - lastx, event.y - lasty
+ dx, dy = format_deltas(event, dx, dy)
+ a.drag_pan(self._button_pressed, lastx + dx, lasty + dy, lastx, lasty, old_lim, old_trans)
 self.dynamic_update()
 
 def release_zoom(self, event):
Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py
===================================================================
--- branches/transforms/lib/matplotlib/backends/backend_agg.py	2007年10月01日 07:06:43 UTC (rev 3904)
+++ branches/transforms/lib/matplotlib/backends/backend_agg.py	2007年10月01日 11:44:54 UTC (rev 3905)
@@ -130,16 +130,16 @@
 if __debug__: verbose.report('RendererAgg.__init__ done',
 'debug-annoying')
 
- # MGDTODO: This is a hack for now to allow for arbitrary transformations
+ # MGDTODO: Just adding helpful asserts. This can be removed in the future
 def draw_path(self, gc, path, trans, rgbFace=None):
- assert trans.is_affine()
- self._renderer.draw_path(gc, path, trans, rgbFace)
+ assert trans.is_affine
+ self._renderer.draw_path(gc, path, trans.frozen(), rgbFace)
 
- # MGDTODO: This is a hack for now to allow for arbitrary transformations
+ # MGDTODO: Just adding helpful asserts. This can be removed in the future
 def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None):
- assert marker_trans.is_affine()
- assert trans.is_affine()
- self._renderer.draw_markers(gc, marker_path, marker_trans, path, trans, rgbFace)
+ assert marker_trans.is_affine
+ assert trans.is_affine
+ self._renderer.draw_markers(gc, marker_path, marker_trans.frozen(), path, trans.frozen(), rgbFace)
 
 def draw_mathtext(self, gc, x, y, s, prop, angle):
 """
Modified: branches/transforms/lib/matplotlib/cbook.py
===================================================================
--- branches/transforms/lib/matplotlib/cbook.py	2007年10月01日 07:06:43 UTC (rev 3904)
+++ branches/transforms/lib/matplotlib/cbook.py	2007年10月01日 11:44:54 UTC (rev 3905)
@@ -7,10 +7,11 @@
 import time, datetime
 import numpy as npy
 
-try: set
+try:
+ set = set
 except NameError:
 from sets import Set as set
-
+ 
 major, minor1, minor2, s, tmp = sys.version_info
 
 
Modified: branches/transforms/lib/matplotlib/lines.py
===================================================================
--- branches/transforms/lib/matplotlib/lines.py	2007年10月01日 07:06:43 UTC (rev 3904)
+++ branches/transforms/lib/matplotlib/lines.py	2007年10月01日 11:44:54 UTC (rev 3905)
@@ -496,7 +496,7 @@
 
 funcname = self._lineStyles.get(self._linestyle, '_draw_nothing')
 lineFunc = getattr(self, funcname)
- lineFunc(renderer, gc, *self._transformed_path.get_path_and_affine())
+ lineFunc(renderer, gc, *self._transformed_path.get_transformed_path_and_affine())
 	 
 	# MGDTODO: Deal with markers
 if self._marker is not None:
@@ -507,7 +507,7 @@
 gc.set_alpha(self._alpha)
 funcname = self._markers.get(self._marker, '_draw_nothing')
 markerFunc = getattr(self, funcname)
- markerFunc(renderer, gc, *self._transformed_path.get_path_and_affine())
+ markerFunc(renderer, gc, *self._transformed_path.get_transformed_path_and_affine())
 
 #renderer.close_group('line2d')
 
Modified: branches/transforms/lib/matplotlib/path.py
===================================================================
--- branches/transforms/lib/matplotlib/path.py	2007年10月01日 07:06:43 UTC (rev 3904)
+++ branches/transforms/lib/matplotlib/path.py	2007年10月01日 11:44:54 UTC (rev 3905)
@@ -1,6 +1,8 @@
 import numpy as npy
 from numpy import ma as ma
 
+KAPPA = 4.0 * (npy.sqrt(2) - 1) / 3.0
+
 class Path(object):
 # Path codes
 STOP = 0 # 1 vertex
@@ -122,7 +124,7 @@
 def unit_circle(cls):
 	# MGDTODO: Optimize?
 	if cls._unit_circle is None:
-	 offset = 4.0 * (npy.sqrt(2) - 1) / 3.0
+ offset = KAPPA
 	 vertices = npy.array(
 		[[-1.0, 0.0],
 		 
Modified: branches/transforms/lib/matplotlib/scale.py
===================================================================
--- branches/transforms/lib/matplotlib/scale.py	2007年10月01日 07:06:43 UTC (rev 3904)
+++ branches/transforms/lib/matplotlib/scale.py	2007年10月01日 11:44:54 UTC (rev 3905)
@@ -2,25 +2,38 @@
 from numpy import ma
 from numpy.linalg import inv
 
+from ticker import NullFormatter, FixedFormatter, ScalarFormatter, \
+ LogFormatter, LogFormatterMathtext
+from ticker import NullLocator, FixedLocator, LinearLocator, LogLocator, AutoLocator
 from transforms import Affine1DBase, IntervalTransform, Transform, \
 composite_transform_factory, IdentityTransform
 
 class ScaleBase(object):
- pass
+ def set_default_locators_and_formatters(self, axis):
+ raise NotImplementedError
+ 
+class LinearScale(ScaleBase):
+ name = 'linear'
+ 
+ def __init__(self, axis, **kwargs):
+ pass
 
-class LinearScale(ScaleBase):
+ def set_default_locators_and_formatters(self, axis):
+ axis.set_major_locator(AutoLocator())
+ axis.set_major_formatter(ScalarFormatter())
+ axis.set_minor_locator(NullLocator())
+ axis.set_minor_formatter(NullFormatter())
+ 
 def get_transform(self):
 return IdentityTransform()
 
 class LogScale(ScaleBase):
+ name = 'log'
+ 
 class Log10Transform(Transform):
 input_dims = 1
 output_dims = 1
- def __init__(self):
- Transform.__init__(self)
-
- def is_separable(self):
- return True
+ is_separable = True
 
 def transform(self, a):
 return ma.log10(ma.masked_where(a <= 0.0, a * 10.0))
@@ -31,11 +44,7 @@
 class InvertedLog10Transform(Transform):
 input_dims = 1
 output_dims = 1
- def __init__(self):
- Transform.__init__(self)
-
- def is_separable(self):
- return True
+ is_separable = True
 
 def transform(self, a):
 return ma.power(10.0, a) / 10.0
@@ -46,11 +55,7 @@
 class Log2Transform(Transform):
 input_dims = 1
 output_dims = 1
- def __init__(self):
- Transform.__init__(self)
-
- def is_separable(self):
- return True
+ is_separable = True
 
 def transform(self, a):
 return ma.log2(ma.masked_where(a <= 0.0, a * 2.0))
@@ -61,11 +66,7 @@
 class InvertedLog2Transform(Transform):
 input_dims = 1
 output_dims = 1
- def __init__(self):
- Transform.__init__(self)
-
- def is_separable(self):
- return True
+ is_separable = True
 
 def transform(self, a):
 return ma.power(2.0, a) / 2.0
@@ -76,12 +77,8 @@
 class NaturalLogTransform(Transform):
 input_dims = 1
 output_dims = 1
- def __init__(self):
- Transform.__init__(self)
-
- def is_separable(self):
- return True
- 
+ is_separable = True
+ 
 def transform(self, a):
 return ma.log(ma.masked_where(a <= 0.0, a * npy.e))
 
@@ -91,12 +88,8 @@
 class InvertedNaturalLogTransform(Transform):
 input_dims = 1
 output_dims = 1
- def __init__(self):
- Transform.__init__(self)
-
- def is_separable(self):
- return True
- 
+ is_separable = True
+ 
 def transform(self, a):
 return ma.power(npy.e, a) / npy.e
 
@@ -106,12 +99,11 @@
 class LogTransform(Transform):
 input_dims = 1
 output_dims = 1
+ is_separable = True
+ 
 def __init__(self, base):
 Transform.__init__(self)
 self._base = base
-
- def is_separable(self):
- return True
 
 def transform(self, a):
 return ma.log(ma.masked_where(a <= 0.0, a * self._base)) / npy.log(self._base)
@@ -122,21 +114,27 @@
 class InvertedLogTransform(Transform):
 input_dims = 1
 output_dims = 1
+ is_separable = True
+ 
 def __init__(self, base):
 Transform.__init__(self)
 self._base = base
 
- def is_separable(self):
- return True
- 
 def transform(self, a):
 return ma.power(self._base, a) / self._base
 
 def inverted(self):
 return LogScale.LogTransform(self._base)
+
 
- 
- def __init__(self, base=10):
+ def __init__(self, axis, **kwargs):
+ if axis.axis_name == 'x':
+ base = kwargs.pop('basex')
+ subs = kwargs.pop('subsx')
+ else:
+ base = kwargs.pop('basey')
+ subs = kwargs.pop('subsy')
+ 
 if base == 10.0:
 self._transform = self.Log10Transform()
 elif base == 2.0:
@@ -145,16 +143,30 @@
 self._transform = self.NaturalLogTransform()
 else:
 self._transform = self.LogTransform(base)
+
+ self._base = base
+ self._subs = subs
+
+ def set_default_locators_and_formatters(self, axis):
+ axis.set_major_locator(LogLocator(self._base))
+ axis.set_major_formatter(LogFormatterMathtext(self._base))
+ axis.set_minor_locator(LogLocator(self._base, self._subs))
+ axis.set_minor_formatter(NullFormatter())
 
 def get_transform(self):
 return self._transform
 
 
 _scale_mapping = {
- 'linear': LinearScale,
- 'log': LogScale
+ 'linear' : LinearScale,
+ 'log' : LogScale
 }
-def scale_factory(scale, viewLim, direction):
+def scale_factory(scale, axis, **kwargs):
+ scale = scale.lower()
 if scale is None:
 scale = 'linear'
- return _scale_mapping[scale](viewLim, direction)
+
+ if not _scale_mapping.has_key(scale):
+ raise ValueError("Unknown scale type '%s'" % scale)
+ 
+ return _scale_mapping[scale](axis, **kwargs)
Modified: branches/transforms/lib/matplotlib/transforms.py
===================================================================
--- branches/transforms/lib/matplotlib/transforms.py	2007年10月01日 07:06:43 UTC (rev 3904)
+++ branches/transforms/lib/matplotlib/transforms.py	2007年10月01日 11:44:54 UTC (rev 3905)
@@ -7,49 +7,57 @@
 import numpy as npy
 from numpy import ma as ma
 from numpy.linalg import inv
-from sets import Set
-from weakref import WeakKeyDictionary
 
+from copy import deepcopy
+from math import sqrt
+from weakref import ref, WeakKeyDictionary
+
+import cbook
 from path import Path
 
 DEBUG = False
 
-# MGDTODO: This creates a ton of cyclical references. We may want to
-# consider using weak references
-
 # MGDTODO: deep copying is probably incorrect wrt the parent/child
 # relationships
 
 class TransformNode(object):
 _gid = 0
+
+ is_affine = False
+ is_bbox = False
 
 def __init__(self):
- # MGDTODO: I'd like to use a WeakKeyDictionary here, but it makes
- # these instances uncopyable. As it stands, _parents grows
- # unboundedly... Not a good idea.
- self._parents = Set()
- self._children = Set()
+ self._parents = WeakKeyDictionary()
 self._id = TransformNode._gid
+ TransformNode._gid += 1
+ self._invalid = 1
+ self._children = []
 
- def invalidate(self, affine_only=None):
- if affine_only is None:
- affine_only = self.is_affine() or self.is_bbox()
- if not self._do_invalidation(affine_only):
- self._id = TransformNode._gid
- TransformNode._gid += 1
- for parent in self._parents:
- parent.invalidate(affine_only)
-
- def _do_invalidation(self, affine_only):
- return False
+ def invalidate(self):
+ if self._invalid:
+ return
 
- def set_children(self, children):
+ value = (self.is_affine or self.is_bbox) and 2 or 1
+ stack = [self]
+
+ while len(stack):
+ root = stack.pop()
+ if root._invalid == 0:
+ root._id = TransformNode._gid
+ TransformNode._gid += 1
+ root._invalid = value
+ stack.extend(root._parents.keys())
+
+ def set_children(self, *children):
 for child in children:
- getattr(self, child)._parents.add(self)
+ child._parents[self] = None
 self._children = children
 
+ def frozen(self):
+ return self
+ 
 def make_graphviz(self, fobj):
- seen = Set()
+ seen = cbook.set()
 
 def recurse(root):
 if root in seen:
@@ -57,30 +65,22 @@
 seen.add(root)
 fobj.write('%s [label="%s"];\n' %
 (hash(root), root.__class__.__name__))
- if root.is_affine():
+ if root.is_affine:
 fobj.write('%s [style=filled, color=".7 .7 .9"];\n' %
 hash(root))
- elif root.is_bbox():
+ elif root.is_bbox:
 fobj.write('%s [style=filled, color=".9 .9 .7"];\n' %
 hash(root))
- for child_name in root._children:
- child = getattr(root, child_name)
- fobj.write('%s -> %s [label="%s"];\n' % (
+ for child in root._children:
+ fobj.write('%s -> %s;\n' % (
 hash(root),
- hash(child),
- child_name))
+ hash(child)))
 recurse(child)
 
 fobj.write("digraph G {\n")
 recurse(self)
 fobj.write("}\n")
- 
- def is_affine(self):
- return False
 
- def is_bbox(self):
- return False
-
 def get_id(self):
 return self._id
 
@@ -89,13 +89,14 @@
 '''
 This is the read-only part of a bounding-box
 '''
+ is_bbox = True
 
 def __init__(self):
 TransformNode.__init__(self)
 
- def is_bbox(self):
- return True
- 
+ def frozen(self):
+ return Bbox(self.get_points().copy())
+ 
 def __array__(self):
 return self.get_points()
 
@@ -225,7 +226,6 @@
 BboxBase.__init__(self)
 self._points = npy.asarray(points, npy.float_)
 self._minpos = npy.array([0.0000001, 0.0000001])
- self._invalid = False
 
 #@staticmethod
 def unit():
@@ -247,11 +247,6 @@
 return 'Bbox(%s)' % repr(self._points)
 __str__ = __repr__
 
- def _do_invalidation(self, affine_only):
- result = self._invalid
- self._invalid = True
- return result
- 
 def update_from_data(self, x, y, ignore=True):
 if ignore:
 self._points = npy.array(
@@ -330,7 +325,7 @@
 minposy = property(_get_minposy)
 
 def get_points(self):
- self._invalid = False
+ self._invalid = 0
 return self._points
 
 def set_points(self, points):
@@ -349,6 +344,9 @@
 a = npy.array([[-deltaw, -deltah], [deltaw, deltah]])
 return Bbox(self._points + a)
 
+ def translated(self, tx, ty):
+ return Bbox(self._points + (tx, ty))
+ 
 #@staticmethod
 def union(bboxes):
 """
@@ -362,24 +360,22 @@
 return bboxes[0]
 
 bbox = bboxes[0]
- xmin = bbox.xmin
- ymin = bbox.ymin
- xmax = bbox.xmax
- ymax = bbox.ymax
+ xmin0, ymin0, xmax0, ymax0 = bbox.bounds
 
 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)
+ xmin, ymin, xmax, ymax = bbox.bounds
+ xmin0 = min(xmin0, xmin)
+ ymin0 = min(ymin0, ymin)
+ xmax0 = max(xmax0, xmax)
+ ymax0 = max(ymax0, ymax)
 
- return Bbox.from_lbrt(xmin, ymin, xmax, ymax)
+ return Bbox.from_lbrt(xmin0, ymin0, xmax0, ymax0)
 union = staticmethod(union)
 
 
 class TransformedBbox(BboxBase):
 def __init__(self, bbox, transform):
- assert bbox.is_bbox()
+ assert bbox.is_bbox
 assert isinstance(transform, Transform)
 assert transform.input_dims == 2
 assert transform.output_dims == 2
@@ -387,31 +383,26 @@
 BboxBase.__init__(self)
 self._bbox = bbox
 self._transform = transform
- self.set_children(['_bbox', '_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, affine_only):
- result = self._points is None
- self._points = None
- return result
-
 def get_points(self):
- if self._points is None:
+ if self._invalid:
 self._points = self._transform.transform(self._bbox.get_points())
+ self._invalid = 0
 return self._points
-
 
+ 
 class Transform(TransformNode):
+ is_separable = False
+ 
 def __init__(self):
 TransformNode.__init__(self)
 
- def is_separable(self):
- return False
- 
 def __add__(self, other):
 if isinstance(other, Transform):
 return composite_transform_factory(self, other)
@@ -428,17 +419,26 @@
 raise NotImplementedError
 
 def transform_affine(self, points):
- raise NotImplementedError
+ return points
 
 def transform_non_affine(self, points):
- raise NotImplementedError
+ return self.transform(points)
 
 def get_affine(self):
- raise NotImplementedError
+ return IdentityTransform()
 
 def transform_point(self, point):
 return self.transform(npy.asarray([point]))[0]
 
+ def transform_path(self, path):
+ return Path(self.transform(path.vertices), path.codes)
+
+ def transform_path_affine(self, path):
+ return path
+
+ def transform_path_non_affine(self, path):
+ return Path(self.transform_non_affine(path.vertices), path.codes)
+ 
 def has_inverse(self):
 raise NotImplementedError()
 
@@ -454,24 +454,35 @@
 self.input_dims = child.input_dims
 self.output_dims = child.output_dims
 self._child = child
- self.set_children(['_child'])
+ self.set_children(child)
 
 def __repr__(self):
 return "TransformWrapper(%r)" % self._child
 __str__ = __repr__
- 
+
+ def frozen(self):
+ return self._child.frozen()
+ 
 def set(self, child):
 assert child.input_dims == self.input_dims
 assert child.output_dims == self.output_dims
 self._child = child
- self.set_children(['_child'])
+ self.set_children(child)
+ self._invalid = 0
 self.invalidate()
+ self._invalid = 0
 
- def is_separable(self):
- return self._child.is_separable()
+ def _get_is_separable(self):
+ return self._child.is_separable
+ is_separable = property(_get_is_separable)
 
- def is_affine(self):
- return self._child.is_affine()
+ def _get_is_affine(self):
+ return self._child.is_affine
+ is_affine = property(_get_is_affine)
+
+ def get_matrix(self):
+ assert self._child.is_affine
+ return self._child.get_matrix()
 
 def transform(self, points):
 return self._child.transform(points)
@@ -482,6 +493,15 @@
 def transform_non_affine(self, points):
 return self._child.transform_non_affine(points)
 
+ def transform_path(self, path):
+ return self._child.transform_path(path)
+
+ def transform_path_affine(self, path):
+ return self._child.transform_path_affine(path)
+
+ def transform_path_non_affine(self, path):
+ return self._child.transform_path_non_affine(path)
+ 
 def get_affine(self):
 return self._child.get_affine()
 
@@ -490,13 +510,12 @@
 
 
 class AffineBase(Transform):
+ is_affine = True
+ 
 def __init__(self):
 Transform.__init__(self)
 self._inverted = None
 
- def is_affine(self):
- return True
- 
 def __array__(self, *args, **kwargs):
 	return self.get_matrix()
 	
@@ -507,7 +526,7 @@
 
 #@staticmethod
 def concat(a, b):
- return Affine1D(Affine1D._concat(a.get_matrix(), b.get_matrix()))
+ return Affine1D(npy.dot(b.get_matrix(), a.get_matrix()))
 concat = staticmethod(concat)
 
 def get_matrix(self):
@@ -516,6 +535,12 @@
 def transform_non_affine(self, points):
 return points
 
+ def transform_path_affine(self, path):
+ return self.transform_path(path)
+
+ def transform_path_non_affine(self, path):
+ return path
+ 
 def get_affine(self):
 return self
 
@@ -523,12 +548,13 @@
 class Affine1DBase(AffineBase):
 input_dims = 1
 output_dims = 1
+ is_separable = True
 
 def __init__(self):
 AffineBase.__init__(self)
 
- def is_separable(self):
- return True
+ def frozen(self):
+ return Affine1D(self.get_matrix().copy())
 
 def __array__(self, *args, **kwargs):
 	return self.get_matrix()
@@ -539,10 +565,7 @@
 
 #@staticmethod
 def matrix_from_values(a, b):
- affine = npy.zeros((2, 2), npy.float_)
- affine[0, :] = (a, b)
- affine[1, 1] = 1
- return affine
+ return npy.array([[a, b], [0.0, 1.0]], npy.float_)
 matrix_from_values = staticmethod(matrix_from_values)
 
 def transform(self, values):
@@ -561,15 +584,16 @@
 # print "".join(traceback.format_stack())
 # print points
 mtx = self.get_matrix()
- # points = npy.asarray(values, npy.float_)
+ points = npy.asarray(values, npy.float_)
 return points * mtx[0,0] + mtx[0,1]
 
 transform_affine = transform
 
 def inverted(self):
- if self._inverted is None:
+ if self._inverted is None or self._invalid:
 mtx = self.get_matrix()
 self._inverted = Affine1D(inv(mtx))
+ self._invalid = 0
 return self._inverted
 
 
@@ -605,6 +629,7 @@
 from_values = staticmethod(from_values)
 
 def get_matrix(self):
+ self._invalid = 0
 return self._mtx
 
 def set_matrix(self, mtx):
@@ -635,37 +660,29 @@
 self.invalidate()
 return self
 
- def is_separable(self):
- mtx = self.get_matrix()
- return mtx[0, 1] == 0.0 and mtx[1, 0] == 0.0
-
 
 class IntervalTransform(Affine1DBase):
 def __init__(self, bbox, direction):
 assert direction in ('x', 'y')
- assert bbox.is_bbox()
+ assert bbox.is_bbox
 
 Affine1DBase.__init__(self)
 self._bbox = bbox
 self._direction = "interval" + direction
- self.set_children(['_bbox'])
+ self.set_children(bbox)
 self._mtx = None
 
 def __repr__(self):
 return "IntervalTransform(%s)" % (getattr(self._bbox, self._direction))
 __str__ = __repr__
 
- def _do_invalidation(self, affine_only):
- result = self._mtx is None
- self._mtx = None
- self._inverted = None
- return result
-
 def get_matrix(self):
- if self._mtx is None:
+ if self._invalid:
 min, max = getattr(self._bbox, self._direction)
 self._mtx = inv(npy.array([[max - min, min],
 [0.0, 1.0]], npy.float_))
+ self._inverted = None
+ self._invalid = 0
 return self._mtx
 
 
@@ -676,6 +693,9 @@
 def __init__(self):
 AffineBase.__init__(self)
 
+ def frozen(self):
+ return Affine2D(self.get_matrix().copy())
+ 
 def is_separable(self):
 mtx = self.get_matrix()
 return mtx[0, 1] == 0.0 and mtx[1, 0] == 0.0
@@ -689,11 +709,7 @@
 
 #@staticmethod
 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
+ return npy.array([[a, c, e], [b, d, f], [0.0, 0.0, 1.0]], npy.float_)
 matrix_from_values = staticmethod(matrix_from_values)
 
 def transform(self, points):
@@ -715,7 +731,7 @@
 # print "".join(traceback.format_stack())
 # print points
 mtx = self.get_matrix()
- if ma.isarray(points):
+ if ma.isMaskedArray(points):
 points = points.transpose()
 points = ma.dot(mtx[0:2, 0:2], points)
 points = points + mtx[0:2, 2:]
@@ -729,9 +745,10 @@
 transform_affine = transform
 
 def inverted(self):
- if self._inverted is None:
+ if self._inverted is None or self._invalid:
 mtx = self.get_matrix()
 self._inverted = Affine2D(inv(mtx))
+ self._invalid = 0
 return self._inverted
 
 
@@ -768,6 +785,7 @@
 from_values = staticmethod(from_values)
 
 def get_matrix(self):
+ self._invalid = 0
 return self._mtx
 
 def set_matrix(self, mtx):
@@ -791,8 +809,8 @@
 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)
+ rotate_mtx = npy.array([[a, -b, 0.0], [b, a, 0.0], [0.0, 0.0, 1.0]], npy.float_)
+ self._mtx = npy.dot(rotate_mtx, self._mtx)
 self.invalidate()
 return self
 
@@ -806,30 +824,33 @@
 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)
+ translate_mtx = npy.array([[1.0, 0.0, tx], [0.0, 1.0, ty], [0.0, 0.0, 1.0]], npy.float_)
+ self._mtx = npy.dot(translate_mtx, self._mtx)
 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.)
- self._mtx = self._concat(self._mtx, scale_mtx)
+ scale_mtx = npy.array([[sx, 0.0, 0.0], [0.0, sy, 0.0], [0.0, 0.0, 1.0]], npy.float_)
+ self._mtx = npy.dot(scale_mtx, self._mtx)
 self.invalidate()
 return self
 
- def is_separable(self):
+ def _get_is_separable(self):
 mtx = self.get_matrix()
 return mtx[0, 1] == 0.0 and mtx[1, 0] == 0.0
+ is_separable = property(_get_is_separable)
 
-
 class IdentityTransform(Affine2DBase):
 """
 A special class that does the identity transform quickly.
 """
 _mtx = npy.identity(3)
 
+ def frozen(self):
+ return self
+ 
 def __repr__(self):
 return "IdentityTransform()"
 __str__ = __repr__
@@ -847,6 +868,10 @@
 return points
 transform_affine = transform_non_affine = transform
 
+ def transform_path(self, path):
+ return path
+ transform_path_affine = transform_path_non_affine = transform_path
+ 
 def get_affine(self):
 return self
 inverted = get_affine
@@ -855,33 +880,37 @@
 class BlendedGenericTransform(Transform):
 input_dims = 2
 output_dims = 2
+ is_separable = True
 
 def __init__(self, x_transform, y_transform):
 	# Here we ask: "Does it blend?"
- assert x_transform.is_separable()
- assert y_transform.is_separable()
+ # MGDTODO: Reinvoke these asserts?
+ # assert x_transform.is_separable()
+ # assert y_transform.is_separable()
 
 Transform.__init__(self)
 self._x = x_transform
 self._y = y_transform
- self.set_children(['_x', '_y'])
+ self.set_children(x_transform, y_transform)
 
- def is_affine(self):
- return self._x.is_affine() and self._y.is_affine()
- 
- def is_separable(self):
- return True
- 
+ def _get_is_affine(self):
+ return self._x.is_affine and self._y.is_affine
+ is_affine = property(_get_is_affine)
+
+ def frozen(self):
+ return blended_transform_factory(self._x.frozen(), self._y.frozen())
+ 
 def __repr__(self):
 return "BlendedGenericTransform(%s,%s)" % (self._x, self._y)
 __str__ = __repr__
- 
+
 def transform(self, points):
 x = self._x
 y = self._y
- if x == y and x.input_dims == 2:
- return self._x.transform(points)
 
+ if x is y and x.input_dims == 2:
+ return x.transform(points)
+
 if x.input_dims == 2:
 x_points = x.transform(points)[:, 0:1]
 else:
@@ -895,11 +924,12 @@
 y_points = y_points.reshape((len(y_points), 1))
 
 return ma.concatenate((x_points, y_points), 1)
+
 transform_non_affine = transform
- 
+
 def transform_affine(self, points):
 return points
- 
+ 
 def get_affine(self):
 return IdentityTransform()
 
@@ -908,6 +938,8 @@
 
 
 class BlendedAffine1D(Affine2DBase, Transform):
+ is_separable = True
+ 
 def __init__(self, x_transform, y_transform):
 assert isinstance(x_transform, Affine1DBase)
 assert isinstance(y_transform, Affine1DBase)
@@ -915,63 +947,50 @@
 Transform.__init__(self)
 self._x = x_transform
 self._y = y_transform
- self.set_children(['_x', '_y'])
+ self.set_children(x_transform, y_transform)
 
 Affine2DBase.__init__(self)
 self._mtx = None
 
- def is_separable(self):
- return True
- 
 def __repr__(self):
 return "BlendedAffine1D(%s,%s)" % (self._x, self._y)
 __str__ = __repr__
 
- def _do_invalidation(self, affine_only):
- result = self._mtx is None
- self._mtx = None
- self._inverted = None
-
 def get_matrix(self):
- if self._mtx is None:
+ if self._invalid:
 x_mtx = self._x.get_matrix()
 y_mtx = self._y.get_matrix()
 self._mtx = npy.array([[x_mtx[0, 0], 0.0, x_mtx[0, 1]],
 [0.0, y_mtx[0, 0], y_mtx[0, 1]],
 [0.0, 0.0, 1.0]])
+ self._inverted = None
+ self._invalid = 0
 return self._mtx
 
 
 class BlendedAffine2D(Affine2DBase, Transform):
+ is_separable = True
+ 
 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_affine
+ assert y_transform.is_affine
+ assert x_transform.is_separable
+ assert y_transform.is_separable
 
 Transform.__init__(self)
 self._x = x_transform
 self._y = y_transform
- self.set_children(['_x', '_y'])
+ self.set_children(x_transform, y_transform)
 
 Affine2DBase.__init__(self)
 self._mtx = None
 
- def is_separable(self):
- return True
- 
 def __repr__(self):
 return "BlendedAffine2D(%s,%s)" % (self._x, self._y)
 __str__ = __repr__
 
- def _do_invalidation(self, affine_only):
- result = self._mtx is None
- self._mtx = None
- self._inverted = None
- return result
-
 def get_matrix(self):
- if self._mtx is None:
+ if self._invalid:
 if self._x == self._y:
 self._mtx = self._x.get_matrix()
 else:
@@ -981,6 +1000,8 @@
 # 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]))
+ self._inverted = None
+ self._invalid = 0
 return self._mtx
 
 
@@ -1001,18 +1022,31 @@
 Transform.__init__(self)
 self._a = a
 self._b = b
- self.set_children(['_a', '_b'])
+ self.set_children(a, b)
+ self._mtx = None
 
- def is_affine(self):
- return self._a.is_affine() and self._b.is_affine()
+ def frozen(self):
+ return composite_transform_factory(self._a.frozen(), self._b.frozen())
 
- def is_separable(self):
+ def _get_is_affine(self):
+ return self._a.is_affine and self._b.is_affine
+ is_affine = property(_get_is_affine)
+ 
+ def _get_is_separable(self):
 return self._a.is_separable() and self._b.is_separable()
+ is_separable = property(_get_is_separable)
 
 def __repr__(self):
 return "CompositeGenericTransform(%s, %s)" % (self._a, self._b)
 __str__ = __repr__
- 
+
+ def get_matrix(self):
+ if self._invalid:
+ assert self._a.is_affine and self._b.is_affine
+ self._mtx = npy.dot(self._b.get_matrix(), self._a.get_matrix())
+ self._invalid = 0
+ return self._mtx
+ 
 def transform(self, points):
 return self._b.transform(self._a.transform(points))
 
@@ -1022,6 +1056,15 @@
 def transform_non_affine(self, points):
 return self._b.transform_non_affine(self._a.transform_non_affine(points))
 
+ def transform_path(self, path):
+ return self._b.transform_path(self._a.transform_path(path))
+
+ def transform_path_affine(self, path):
+ return self._b.transform_path_affine(self._a.transform_path_affine(path))
+
+ def transform_path_non_affine(self, path):
+ return self._b.transform_path_non_affine(self._a.transform_path_non_affine(path))
+ 
 def get_affine(self):
 return CompositeAffine2D(self._a.get_affine(), self._b.get_affine())
 
@@ -1034,113 +1077,46 @@
 assert a.output_dims == b.input_dims
 self.input_dims = a.input_dims
 self.output_dims = b.output_dims
- assert a.is_affine()
- assert b.is_affine()
+ assert a.is_affine
+ assert b.is_affine
 
 Affine2DBase.__init__(self)
 self._a = a
 self._b = b
- self.set_children(['_a', '_b'])
+ self.set_children(a, b)
 self._mtx = None
 
 def __repr__(self):
 return "CompositeAffine2D(%s, %s)" % (self._a, self._b)
 __str__ = __repr__
 
- def _do_invalidation(self, affine_only):
- result = self._mtx is None
- self._mtx = None
- self._inverted = None
- return result
- 
 def get_matrix(self):
- if self._mtx is None:
- self._mtx = self._concat(
- self._a.get_matrix(),
- self._b.get_matrix())
+ if self._invalid:
+ self._mtx = npy.dot(
+ self._b.get_matrix(),
+ self._a.get_matrix())
+ self._inverted = None
+ self._invalid = 0
 return self._mtx
 
 
 def composite_transform_factory(a, b):
-# if isinstance(a, BboxTransform) and isinstance(b, BboxTransform):
-# return BboxTransform(a._boxin, b._boxout)
 if isinstance(a, AffineBase) and isinstance(b, AffineBase):
 return CompositeAffine2D(a, b)
 return CompositeGenericTransform(a, b)
-
-
-class TestPolarTransform(Transform):
- input_dims = 2
- output_dims = 2
-
- def __init__(self, limits):
- assert limits.is_bbox()
-
- Transform.__init__(self)
- self._limits = limits
- self.set_children(['_limits'])
 
- def transform(self, xy):
- debug = len(xy) > 4
- limmin, limmax = self._limits.intervaly
- mask = (xy[:, 1:] < limmin) | (xy[:, 1:] > limmax)
- mask = ma.concatenate((mask, mask), 1)
- masked_xy = npy.ma.masked_where(mask, xy)
- x = masked_xy[:, 0:1]
- y = masked_xy[:, 1:2]
- if x.shape == () or y.shape == ():
- return masked_xy
- y = (y - limmin) / (limmax - limmin)
- x, y = y * ma.cos(x), y * ma.sin(x)
- result = ma.concatenate((x, y), 1)
- result = result * 0.5 + 0.5
- return result
-
- def inverted(self):
- return TestInvertPolarTransform(self._limits)
 
- def is_separable(self):
- return False
-
-
-class TestInvertPolarTransform(Transform):
- input_dims = 2
- output_dims = 2
-
- def __init__(self, limits):
- assert limits.is_bbox()
-
- Transform.__init__(self)
- self._limits = limits
- self.set_children(['_limits'])
- 
- def transform(self, xy):
- limmin, limmax = self._limits.intervaly
- xy = (xy - 0.5) * 2.0
- x = xy[:, 0:1]
- y = xy[:, 1:]
- r = ma.sqrt(ma.power(x, 2) + ma.power(y, 2))
- theta = ma.arccos(x / r)
- theta = ma.where(y < 0, 2 * npy.pi - theta, theta)
- r = r * (limmax - limmin) + limmin
- return ma.concatenate((theta, r), 1)
-
- def inverted(self):
- return TestInvertPolarTransform(self._limits)
- 
- def is_separable(self):
- return False
- 
- 
 class BboxTransform(Affine2DBase):
+ is_separable = True
+
 def __init__(self, boxin, boxout):
- assert boxin.is_bbox()
- assert boxout.is_bbox()
+ assert boxin.is_bbox
+ assert boxout.is_bbox
 
 Affine2DBase.__init__(self)
 self._boxin = boxin
 self._boxout = boxout
- self.set_children(['_boxin', '_boxout'])
+ self.set_children(boxin, boxout)
 self._mtx = None
 self._inverted = None
 
@@ -1148,29 +1124,17 @@
 return "BboxTransform(%s, %s)" % (self._boxin, self._boxout)
 __str__ = __repr__
 
- def _do_invalidation(self, affine_only):
- result = self._mtx is None
- self._mtx = None
- self._inverted = None
- return result
- 
- def is_separable(self):
- return True
-
 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
-
- # MGDTODO: Optimize
- affine = Affine2D() \
- .translate(-boxin.xmin, -boxin.ymin) \
- .scale(x_scale, y_scale) \
- .translate(boxout.xmin, boxout.ymin)
-
- self._mtx = affine._mtx
+ if self._invalid:
+ inl, inb, inw, inh = self._boxin.bounds
+ outl, outb, outw, outh = self._boxout.bounds
+ x_scale = outw / inw
+ y_scale = outh / inh
+ self._mtx = npy.array([[x_scale, 0.0 , (-inl*x_scale+outl)],
+ [0.0 , y_scale, (-inb*y_scale+outb)],
+ [0.0 , 0.0 , 1.0 ]],
+ npy.float_)
+ self._inverted = None
 return self._mtx
 
 
@@ -1181,27 +1145,20 @@
 
 self._path = path
 self._transform = transform
- self.set_children(['_transform'])
+ self.set_children(transform)
 self._transformed_path = None
 
- def _do_invalidation(self, affine_only):
- if not affine_only:
- self._transformed_path = None
- return True
- 
- def get_path_and_affine(self):
- if self._transformed_path is None:
- vertices = self._transform.transform_non_affine(self._path.vertices)
- self._transformed_path = Path(vertices, self._path.codes)
-
+ def get_transformed_path_and_affine(self):
+ if self._invalid == 1 or self._transformed_path is None:
+ self._transformed_path = self._transform.transform_path_non_affine(self._path)
+ self._invalid = 0
 return self._transformed_path, self._transform.get_affine()
 
- def get_path(self):
- if self._transformed_path is None:
- vertices = self._tranform.transform_non_affine(self._path.vertices)
- self._transformed_path = Path(vertices, self._path.codes)
- vertices = self._transform.transform_affine(self._transformed_path.vertices)
- return Path(vertices, self._transformed_path.codes)
+ def get_fully_transformed_path(self):
+ if self._invalid == 1 or self._transformed_path is None:
+ self._transformed_path = self._transform.transform_path_non_affine(self._path)
+ self._invalid = 0
+ return self._transform.transform_path_affine(self._transformed_path)
 
 def get_affine(self):
 return self._transform.get_affine()
...
 
[truncated message content]
From: <md...@us...> - 2007年10月04日 19:12:31
Revision: 3915
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3915&view=rev
Author: mdboom
Date: 2007年10月04日 12:12:20 -0700 (2007年10月04日)
Log Message:
-----------
Merged from trunk (a somewhat hairy manual merge this time). Fixed
bug (on this branch only) where inverted axes were broken.
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/axes.py
 branches/transforms/lib/matplotlib/backends/backend_qt.py
 branches/transforms/lib/matplotlib/backends/backend_qt4.py
 branches/transforms/lib/matplotlib/backends/backend_qt4agg.py
 branches/transforms/lib/matplotlib/backends/backend_qtagg.py
 branches/transforms/lib/matplotlib/transforms.py
Modified: branches/transforms/lib/matplotlib/axes.py
===================================================================
--- branches/transforms/lib/matplotlib/axes.py	2007年10月04日 18:57:27 UTC (rev 3914)
+++ branches/transforms/lib/matplotlib/axes.py	2007年10月04日 19:12:20 UTC (rev 3915)
@@ -498,6 +498,9 @@
 self.set_label(label)
 self.set_figure(fig)
 
+ self._invertedx = False
+ self._invertedy = False
+
 # this call may differ for non-sep axes, eg polar
 self._init_axis()
 
@@ -1422,10 +1425,25 @@
 
 ### data limits, ticks, tick labels, and formatting
 
+ def invert_xaxis(self, invert=True):
+ "Invert the x-axis if 'invert' is True."
+ self._invertedx = invert
+
+ def xaxis_inverted(self):
+ 'Returns True if the x-axis is inverted.'
+ return self._invertedx
+
 def get_xlim(self):
- 'Get the x axis range [xmin, xmax]'
- return self.viewLim.intervalx
+ """Get the x-axis range [xmin, xmax]
 
+ NOTE: The returned values are always [xmin, xmax] such that
+ xmin < xmax; regardless of whether or not the axes are inverted.
+ """
+ bound1, bound2 = self.viewLim.intervalx
+ if ( self._invertedx ):
+ return bound2, bound1
+ else:
+ return bound1, bound2
 
 def set_xlim(self, xmin=None, xmax=None, emit=True, **kwargs):
 """
@@ -1463,9 +1481,21 @@
 if xmin is None: xmin = old_xmin
 if xmax is None: xmax = old_xmax
 
- xmin, xmax = mtransforms.nonsingular(xmin, xmax, increasing=False)
+ # provided for backwards compatability
+ if ( xmax < xmin ):
+ # swap the values so that xmin < xmax and set inverted flag
+ tmp = xmin
+ xmin = xmax
+ xmax = tmp
+ self.invert_xaxis( True )
 
-	self.viewLim.intervalx = (xmin, xmax)
+ if ( self._invertedx ):
+ xmax, xmin = mtransforms.nonsingular(xmax, xmin, increasing=False)
+ self.viewLim.intervalx = (xmax, xmin)
+ else:
+ xmin, xmax = mtransforms.nonsingular(xmin, xmax, increasing=False)
+ self.viewLim.intervalx = (xmin, xmax)
+
 if emit:
 	 self.callbacks.process('xlim_changed', self)
 	 # Call all of the other x-axes that are shared with this one
@@ -1534,10 +1564,26 @@
 return self.xaxis.set_ticklabels(labels, fontdict, **kwargs)
 set_xticklabels.__doc__ = cbook.dedent(set_xticklabels.__doc__) % martist.kwdocd
 
+ def invert_yaxis(self, invert=True):
+ "Invert the y-axis if 'invert' is True."
+ self._invertedy = invert
+
+ def yaxis_inverted(self):
+ 'Returns True if the y-axis is inverted.'
+ return self._invertedy
+
 def get_ylim(self):
- 'Get the y axis range [ymin, ymax]'
- return self.viewLim.intervaly
+ """Get the y-axis range [xmin, xmax]
 
+ NOTE: The returned values are always [ymin, ymax] such that
+ ymin < ymax; regardless of whether or not the axes are inverted.
+ """
+ bound1, bound2 = self.viewLim.intervaly
+ if ( self._invertedy ):
+ return bound2, bound1
+ else:
+ return bound1, bound2
+
 def set_ylim(self, ymin=None, ymax=None, emit=True, **kwargs):
 """
 set_ylim(self, *args, **kwargs):
@@ -1572,8 +1618,21 @@
 if ymin is None: ymin = old_ymin
 if ymax is None: ymax = old_ymax
 
- ymin, ymax = mtransforms.nonsingular(ymin, ymax, increasing=False)
-	self.viewLim.intervaly = (ymin, ymax)
+ # provided for backwards compatability
+ if ( ymax < ymin ):
+ # swap the values so that ymin < ymax and set inverted flag
+ tmp = ymin
+ ymin = ymax
+ ymax = tmp
+ self.invert_yaxis( True )
+
+ if ( self._invertedy ):
+ ymax, ymin = mtransforms.nonsingular(ymax, ymin, increasing=False)
+ self.viewLim.intervaly = (ymax, ymin)
+ else:
+ ymin, ymax = mtransforms.nonsingular(ymin, ymax, increasing=False)
+ self.viewLim.intervaly = (ymin, ymax)
+
 if emit:
 	 self.callbacks.process('ylim_changed', self)
 	 # Call all of the other y-axes that are shared with this one
@@ -1582,7 +1641,6 @@
 		 other.set_ylim(self.viewLim.ymin, self.viewLim.ymax, emit=False)
 
 self.figure.canvas.draw_idle()
- 
 return ymin, ymax
 
 def get_yscale(self):
Modified: branches/transforms/lib/matplotlib/backends/backend_qt.py
===================================================================
--- branches/transforms/lib/matplotlib/backends/backend_qt.py	2007年10月04日 18:57:27 UTC (rev 3914)
+++ branches/transforms/lib/matplotlib/backends/backend_qt.py	2007年10月04日 19:12:20 UTC (rev 3915)
@@ -136,10 +136,35 @@
 def resizeEvent( self, event ):
 if DEBUG: print 'resize (%d x %d)' % (event.size().width(), event.size().height())
 qt.QWidget.resizeEvent( self, event )
+ w = event.size().width()
+ h = event.size().height()
+ if DEBUG: print "FigureCanvasQt.resizeEvent(", w, ",", h, ")"
+ dpival = self.figure.dpi.get()
+ winch = w/dpival
+ hinch = h/dpival
+ self.figure.set_size_inches( winch, hinch )
+ self.draw()
 
 def resize( self, w, h ):
+ # Pass through to Qt to resize the widget.
 qt.QWidget.resize( self, w, h )
 
+ # Resize the figure by converting pixels to inches.
+ pixelPerInch = self.figure.dpi.get()
+ wInch = w / pixelPerInch
+ hInch = h / pixelPerInch
+ self.figure.set_size_inches( wInch, hInch )
+
+ # Redraw everything.
+ self.draw()
+
+ def sizeHint( self ):
+ w, h = self.get_width_height()
+ return qt.QSize( w, h )
+
+ def minumumSizeHint( self ):
+ return qt.QSize( 10, 10 )
+
 def _get_key( self, event ):
 if event.key() < 256:
 key = event.text().latin1()
Modified: branches/transforms/lib/matplotlib/backends/backend_qt4.py
===================================================================
--- branches/transforms/lib/matplotlib/backends/backend_qt4.py	2007年10月04日 18:57:27 UTC (rev 3914)
+++ branches/transforms/lib/matplotlib/backends/backend_qt4.py	2007年10月04日 19:12:20 UTC (rev 3915)
@@ -135,10 +135,35 @@
 def resizeEvent( self, event ):
 if DEBUG: print 'resize (%d x %d)' % (event.size().width(), event.size().height())
 QtGui.QWidget.resizeEvent( self, event )
+ w = event.size().width()
+ h = event.size().height()
+ if DEBUG: print "FigureCanvasQtAgg.resizeEvent(", w, ",", h, ")"
+ dpival = self.figure.dpi.get()
+ winch = w/dpival
+ hinch = h/dpival
+ self.figure.set_size_inches( winch, hinch )
+ self.draw()
 
 def resize( self, w, h ):
+ # Pass through to Qt to resize the widget.
 QtGui.QWidget.resize( self, w, h )
 
+ # Resize the figure by converting pixels to inches.
+ pixelPerInch = self.figure.dpi.get()
+ wInch = w / pixelPerInch
+ hInch = h / pixelPerInch
+ self.figure.set_size_inches( wInch, hInch )
+
+ # Redraw everything.
+ self.draw()
+
+ def sizeHint( self ):
+ w, h = self.get_width_height()
+ return QtCore.QSize( w, h )
+
+ def minumumSizeHint( self ):
+ return QtCore.QSize( 10, 10 )
+
 def _get_key( self, event ):
 if event.key() < 256:
 key = str(event.text())
Modified: branches/transforms/lib/matplotlib/backends/backend_qt4agg.py
===================================================================
--- branches/transforms/lib/matplotlib/backends/backend_qt4agg.py	2007年10月04日 18:57:27 UTC (rev 3914)
+++ branches/transforms/lib/matplotlib/backends/backend_qt4agg.py	2007年10月04日 19:12:20 UTC (rev 3915)
@@ -65,14 +65,6 @@
 
 def resizeEvent( self, e ):
 FigureCanvasQT.resizeEvent( self, e )
- w = e.size().width()
- h = e.size().height()
- if DEBUG: print "FigureCanvasQtAgg.resizeEvent(", w, ",", h, ")"
- dpival = self.figure.dpi.get()
- winch = w/dpival
- hinch = h/dpival
- self.figure.set_size_inches( winch, hinch )
- self.draw()
 
 def drawRectangle( self, rect ):
 self.rect = rect
Modified: branches/transforms/lib/matplotlib/backends/backend_qtagg.py
===================================================================
--- branches/transforms/lib/matplotlib/backends/backend_qtagg.py	2007年10月04日 18:57:27 UTC (rev 3914)
+++ branches/transforms/lib/matplotlib/backends/backend_qtagg.py	2007年10月04日 19:12:20 UTC (rev 3915)
@@ -64,14 +64,6 @@
 
 def resizeEvent( self, e ):
 FigureCanvasQT.resizeEvent( self, e )
- w = e.size().width()
- h = e.size().height()
- if DEBUG: print "FigureCanvasQtAgg.resizeEvent(", w, ",", h, ")"
- dpival = self.figure.dpi.get()
- winch = w/dpival
- hinch = h/dpival
- self.figure.set_size_inches( winch, hinch )
- self.draw()
 
 def drawRectangle( self, rect ):
 self.rect = rect
Modified: branches/transforms/lib/matplotlib/transforms.py
===================================================================
--- branches/transforms/lib/matplotlib/transforms.py	2007年10月04日 18:57:27 UTC (rev 3914)
+++ branches/transforms/lib/matplotlib/transforms.py	2007年10月04日 19:12:20 UTC (rev 3915)
@@ -1951,10 +1951,12 @@
 
 # MGDTODO: Optimize (perhaps in an extension)
 def interval_contains(interval, val):
- return interval[0] <= val and interval[1] >= val
+ return ((interval[0] <= val and interval[1] >= val) or
+ (interval[1] <= val and interval[0] >= val))
 
 def interval_contains_open(interval, val):
- return interval[0] < val and interval[1] > val
+ return ((interval[0] < val and interval[1] > val) or
+ (interval[1] < val and interval[0] > val))
 
 if __name__ == '__main__':
 import copy
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2007年10月15日 13:49:52
Revision: 3947
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3947&view=rev
Author: mdboom
Date: 2007年10月15日 06:49:25 -0700 (2007年10月15日)
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
+ 
 #@staticmethod
 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.
From: <md...@us...> - 2007年10月16日 14:17:56
Revision: 3955
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3955&view=rev
Author: mdboom
Date: 2007年10月16日 07:17:53 -0700 (2007年10月16日)
Log Message:
-----------
First pass at PS backend updates.
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/backend_bases.py
 branches/transforms/lib/matplotlib/backends/backend_ps.py
 branches/transforms/lib/matplotlib/cbook.py
 branches/transforms/lib/matplotlib/collections.py
 branches/transforms/lib/matplotlib/lines.py
 branches/transforms/lib/matplotlib/path.py
 branches/transforms/lib/matplotlib/transforms.py
Modified: branches/transforms/lib/matplotlib/backend_bases.py
===================================================================
--- branches/transforms/lib/matplotlib/backend_bases.py	2007年10月16日 13:45:59 UTC (rev 3954)
+++ branches/transforms/lib/matplotlib/backend_bases.py	2007年10月16日 14:17:53 UTC (rev 3955)
@@ -49,7 +49,62 @@
 trans is an affine transform applied to the path.
 """
 raise NotImplementedError
-	
+
+ def draw_path_collection(self, master_transform, cliprect, clippath,
+ clippath_trans, paths, all_transforms, offsets,
+ offsetTrans, facecolors, edgecolors, linewidths,
+ linestyles, antialiaseds):
+ """
+ MGDTODO: Document me. Explain that often the backend will not
+ want to override this.
+ """
+ Npaths = len(paths)
+ Noffsets = len(offsets)
+ N = max(Npaths, Noffsets)
+ Ntransforms = min(len(all_transforms), N)
+ Nfacecolors = len(facecolors)
+ Nedgecolors = len(edgecolors)
+ Nlinewidths = len(linewidths)
+ Nlinestyles = len(linestyles)
+ Naa = len(antialiaseds)
+
+ if (Nfacecolors == 0 and Nedgecolors == 0) or N == 0:
+ return
+ 
+ ttransforms = []
+ for i in range(Ntransforms):
+ transform = all_transforms[i]
+ if transform is None:
+ transform = transforms.IdentityTransform()
+ ttransforms.append((transform + master_transform).frozen())
+
+ toffsets = offsetTrans.transform(offsets)
+ 
+ gc = self.new_gc()
+ gc.set_clip_rectangle(cliprect)
+ if clippath is not None:
+ clippath = transforms.TransformedPath(clippath, clippath_trans)
+ gc.set_clippath(clippath)
+ 
+ if Nfacecolors == 0:
+ rgbFace = None
+
+ print linewidths, edgecolors
+ 
+ for i in xrange(N):
+ path = paths[i % Npaths]
+ xo, yo = toffsets[i % Noffsets]
+ transform = ttransforms[i % Ntransforms].frozen().translate(xo, yo)
+ if Nfacecolors:
+ rgbFace = facecolors[i % Nfacecolors]
+ if Nedgecolors:
+ gc.set_foreground(edgecolors[i % Nedgecolors])
+ gc.set_linewidth(linewidths[i % Nlinewidths])
+ gc.set_dashes(*linestyles[i % Nlinestyles])
+ gc.set_antialiased(antialiaseds[i % Naa])
+
+ self.draw_path(gc, path, transform, rgbFace)
+ 
 def get_image_magnification(self):
 """
 Get the factor by which to magnify images passed to draw_image.
@@ -78,328 +133,6 @@
 """
 return False
 
- ######################################################################
- ## OLD API IS BELOW
- ## These functions no longer need to be implemented in the backends --
- ## they now perform all of their functions in terms of the new API.
- 
-# def draw_arc(self, gc, rgbFace, x, y, width, height, angle1, angle2,
-# rotation):
-# """
-# Draw an arc using GraphicsContext instance gcEdge, centered at x,y,
-# with width and height and angles from 0.0 to 360.0
-# 0 degrees is at 3-o'clock
-# positive angles are anti-clockwise
-# draw rotated 'rotation' degrees anti-clockwise about x,y
-
-# If the color rgbFace is not None, fill the arc with it.
-# """
-# raise NotImplementedError
-
-# def draw_line_collection(self, segments, transform, clipbox,
-# colors, linewidths, linestyle, antialiaseds,
-# offsets, transOffset):
-# """
-# This is a function for optimized line drawing. If you need to draw
-# many line segments with similar properties, it is faster to avoid the
-# overhead of all the object creation etc. The lack of total
-# configurability is compensated for with efficiency. Hence we don't use
-# a GC and many of the line props it supports. See
-# matplotlib.collections for more details.
-
-# segments is a sequence of ( line0, line1, line2), where linen =
-# is an Mx2 array with columns x, y. Each line can be a
-# different length
-
-# transform is used to Transform the lines
-
-# clipbox is a xmin, ymin, width, height clip rect
-
-# colors is a tuple of RGBA tuples
-
-# linewidths is a tuple of linewidths
-# *** really should be called 'dashes' not 'linestyle', since
-# we call gc.set_dashes() not gc.set_linestyle() ***
-
-# linestyle is an (offset, onoffseq) tuple or None,None for solid
-
-# antialiseds is a tuple of ones or zeros indicating whether the
-# segment should be aa or not
-
-# offsets, if not None, is an Nx2 array of x,y offsets to
-# translate the lines by after transform is used to transform
-# the offset coords
-
-# This function could be overridden in the backend to possibly implement
-# faster drawing, but it is already much faster than using draw_lines()
-# by itself.
-# """
-
-# newstyle = getattr(self, 'draw_markers', None) is not None
-# identity = transforms.identity_transform()
-# gc = self.new_gc()
-# if clipbox is not None:
-# gc.set_clip_rectangle(clipbox.get_bounds())
-# gc.set_dashes(*linestyle)
-
-# Nc = len(colors)
-# Nlw = len(linewidths)
-# Naa = len(antialiaseds)
-# Nsegments = len(segments)
-
-# usingOffsets = offsets is not None
-# Noffsets = 0
-# if usingOffsets:
-# Noffsets = offsets.shape[0]
-# offsets = transOffset.numerix_xy(offsets)
-
-# for i in xrange(max(Noffsets, Nsegments)):
-# color = colors[i % Nc]
-# rgb = color[0], color[1], color[2]
-# alpha = color[-1]
-
-# gc.set_foreground(rgb, isRGB=True)
-# gc.set_alpha( alpha )
-# gc.set_linewidth( linewidths[i % Nlw] )
-# gc.set_antialiased( antialiaseds[i % Naa] )
-# seg = segments[i % Nsegments]
-# if not len(seg): continue
-# xy = transform.numerix_xy(seg)
-# if usingOffsets:
-# xy = xy + offsets[i % Noffsets]
-
-# if newstyle: self.draw_lines(gc, xy[:,0], xy[:,1], identity)
-# else: self.draw_lines(gc, xy[:,0], xy[:,1])
-
-# def draw_line(self, gc, x1, y1, x2, y2):
-# """
-# Draw a single line from x1,y1 to x2,y2
-# """
-# raise NotImplementedError
-
-# def draw_lines(self, gc, x, y, transform=None):
-# """
-# x and y are equal length arrays, draw lines connecting each
-# point in x, y
-# """
-# raise NotImplementedError
-
-# def draw_point(self, gc, x, y):
-# """
-# Draw a single point at x,y
-# Where 'point' is a device-unit point (or pixel), not a matplotlib point
-# """
-# raise NotImplementedError
-
-# def draw_quad_mesh(self, meshWidth, meshHeight, colors,
-# xCoords, yCoords, clipbox,
-# transform, offsets, transOffset, showedges):
-# """
-# Draw a quadrilateral mesh
-# See documentation in QuadMesh class in collections.py for details
-# """
-# # print "draw_quad_mesh not found, using function in backend_bases"
-# verts = npy.zeros(((meshWidth * meshHeight), 4, 2), npy.float32)
-# indices = npy.arange((meshWidth + 1) * (meshHeight + 1))
-# indices = npy.compress((indices + 1) % (meshWidth + 1), indices)
-# indices = indices[:(meshWidth * meshHeight)]
-# verts[:, 0, 0] = npy.take(xCoords, indices)
-# verts[:, 0, 1] = npy.take(yCoords, indices)
-# verts[:, 1, 0] = npy.take(xCoords, (indices + 1))
-# verts[:, 1, 1] = npy.take(yCoords, (indices + 1))
-# verts[:, 2, 0] = npy.take(xCoords, (indices + meshWidth + 2))
-# verts[:, 2, 1] = npy.take(yCoords, (indices + meshWidth + 2))
-# verts[:, 3, 0] = npy.take(xCoords, (indices + meshWidth + 1))
-# verts[:, 3, 1] = npy.take(yCoords, (indices + meshWidth + 1))
-# if (showedges):
-# edgecolors = colors
-# else:
-# edgecolors = (0, 0, 0, 0),
-# self.draw_poly_collection(verts, transform,
-# clipbox, colors, edgecolors,
-# (0.25,), (0,), offsets, transOffset)
-
-# def draw_poly_collection(
-# self, verts, transform, clipbox, facecolors, edgecolors,
-# linewidths, antialiaseds, offsets, transOffset):
-# """
-# Draw a polygon collection
-
-# verts are a sequence of polygon vectors, where each polygon
-# vector is a sequence of x,y tuples of vertices
-
-# facecolors and edgecolors are a sequence of RGBA tuples
-# linewidths are a sequence of linewidths
-# antialiaseds are a sequence of 0,1 integers whether to use aa
-
-# If a linewidth is zero or an edgecolor alpha is zero, the
-# line will be omitted; similarly, the fill will be omitted
-# if the facecolor alpha is zero.
-# """
-# ## line and/or fill OK
-# Nface = len(facecolors)
-# Nedge = len(edgecolors)
-# Nlw = len(linewidths)
-# Naa = len(antialiaseds)
-
-# usingOffsets = offsets is not None
-# Noffsets = 0
-# Nverts = len(verts)
-# if usingOffsets:
-# Noffsets = len(offsets)
-
-# N = max(Noffsets, Nverts)
-
-# gc = self.new_gc()
-# if clipbox is not None:
-# gc.set_clip_rectangle(clipbox.get_bounds())
-
-
-# for i in xrange(N):
-# polyverts = ma.filled(verts[i % Nverts], npy.nan)
-# if npy.any(npy.isnan(polyverts)):
-# continue
-# linewidth = linewidths[i % Nlw]
-# rf,gf,bf,af = facecolors[i % Nface]
-# re,ge,be,ae = edgecolors[i % Nedge]
-# if af==0:
-# if ae==0 or linewidth == 0:
-# continue
-# rgbFace = None
-# alpha = ae
-# else:
-# rgbFace = rf,gf,bf
-# if ae==0:
-# alpha = af
-# gc.set_linewidth(0)
-# else:
-# # the draw_poly interface can't handle separate alphas for
-# # edge and face so we'll just use the maximum
-# alpha = max(af,ae)
-# gc.set_foreground( (re,ge,be), isRGB=True)
-# gc.set_linewidth( linewidths[i % Nlw] )
-# #print 'verts', zip(thisxverts, thisyverts)
-
-# gc.set_antialiased( antialiaseds[i % Naa] ) # Used for fill only?
-# gc.set_alpha( alpha )
-# tverts = transform.seq_xy_tups(polyverts)
-# if usingOffsets:
-# xo,yo = transOffset.xy_tup(offsets[i % Noffsets])
-# tverts = [(x+xo,y+yo) for x,y in tverts]
-
-# self.draw_polygon(gc, rgbFace, tverts)
-
-# def draw_polygon(self, gc, rgbFace, points):
-# """
-# Draw a polygon using the GraphicsContext instance gc.
-# points is a len vertices tuple, each element
-# giving the x,y coords a vertex
-
-# If the color rgbFace is not None, fill the polygon with it
-# """
-# raise NotImplementedError
-
-# def draw_rectangle(self, gcEdge, rgbFace, x, y, width, height):
-# """
-# Draw a non-filled rectangle using the GraphicsContext instance gcEdge,
-# with lower left at x,y with width and height.
-
-# If rgbFace is not None, fill the rectangle with it.
-# """
-# 	warnings.warn("draw_rectangle called", warnings.PendingDeprecationWarning)
-# 	transform = transforms.Affine2D().scale(width, height).translate(x, y)
-# 	self.draw_path(gcEdge, Path.unit_rectangle(), transform, rgbFace)
-	
-# def draw_regpoly_collection(
-# self, clipbox, offsets, transOffset, verts, sizes,
-# facecolors, edgecolors, linewidths, antialiaseds):
-# """
-# Draw a regular poly collection
-
-# offsets - is a sequence is x,y tuples
-# transOffset - maps this to display coords
-
-# verts - are the vertices of the regular polygon at the origin
-
-# sizes are the area of the circle that circumscribes the
-# polygon in points^2
-
-# facecolors and edgecolors are a sequence of RGBA tuples
-# linewidths are a sequence of linewidths
-# antialiaseds are a sequence of 0,1 integers whether to use aa
-# """
-# ## line and/or fill OK
-# gc = self.new_gc()
-# if clipbox is not None:
-# gc.set_clip_rectangle(clipbox.get_bounds())
-
-# xverts, yverts = zip(*verts)
-# xverts = npy.asarray(xverts)
-# yverts = npy.asarray(yverts)
-
-# Nface = len(facecolors)
-# Nedge = len(edgecolors)
-# Nlw = len(linewidths)
-# Naa = len(antialiaseds)
-# Nsizes = len(sizes)
-
-# for i, loc in enumerate(offsets):
-# xo,yo = transOffset.xy_tup(loc)
-# #print 'xo, yo', loc, (xo, yo)
-# scale = sizes[i % Nsizes]
-
-# thisxverts = scale*xverts + xo
-# thisyverts = scale*yverts + yo
-# #print 'xverts', xverts
-
-# linewidth = linewidths[i % Nlw]
-# rf,gf,bf,af = facecolors[i % Nface]
-# re,ge,be,ae = edgecolors[i % Nedge]
-# if af==0:
-# if ae==0 or linewidth == 0:
-# continue
-# rgbFace = None
-# alpha = ae
-# else:
-# rgbFace = rf,gf,bf
-# if ae==0:
-# alpha = af
-# gc.set_linewidth(0)
-# else:
-# # the draw_poly interface can't handle separate alphas for
-# # edge and face so we'll just use the maximum
-# alpha = max(af,ae)
-# gc.set_foreground( (re,ge,be), isRGB=True)
-# gc.set_linewidth( linewidths[i % Nlw] )
-# #print 'verts', zip(thisxverts, thisyverts)
-
-# gc.set_antialiased( antialiaseds[i % Naa] ) # Used for fill only?
-# gc.set_alpha( alpha )
-# #print 'verts', zip(thisxverts, thisyverts)
-# self.draw_polygon(gc, rgbFace, zip(thisxverts, thisyverts))
-
-
-# def draw_tex(self, gc, x, y, s, prop, angle, ismath='TeX!'):
-# raise NotImplementedError
-
-# def draw_text(self, gc, x, y, s, prop, angle, ismath=False):
-# """
-# Draw the text.Text instance s at x,y (display coords) with font
-# properties instance prop at angle in degrees, using GraphicsContext gc
-
-# **backend implementers note**
-
-# When you are trying to determine if you have gotten your bounding box
-# right (which is what enables the text layout/alignment to work
-# properly), it helps to change the line in text.py
-
-# if 0: bbox_artist(self, renderer)
-
-# to if 1, and then the actual bounding box will be blotted along with
-# your text.
-# """
-# raise NotImplementedError
-
 def flipy(self):
 """return true if y small numbers are top for renderer
 Is used for drawing text (text.py) and images (image.py) only
@@ -416,12 +149,6 @@
 self._texmanager = TexManager()
 return self._texmanager
 
- def get_text_extent(self, text): # is not used, can be removed?
- """
- Get the text extent in window coords
- """
- return transforms.lbwh_to_bbox(0,0,1,1) # your values here
-
 def get_text_width_height_descent(self, s, prop, ismath):
 """
 get the width and height, and the offset from the bottom to the
Modified: branches/transforms/lib/matplotlib/backends/backend_ps.py
===================================================================
--- branches/transforms/lib/matplotlib/backends/backend_ps.py	2007年10月16日 13:45:59 UTC (rev 3954)
+++ branches/transforms/lib/matplotlib/backends/backend_ps.py	2007年10月16日 14:17:53 UTC (rev 3955)
@@ -24,9 +24,9 @@
 from matplotlib.mathtext import MathTextParser
 from matplotlib._mathtext_data import uni2type1
 from matplotlib.text import Text
+from matplotlib.path import Path
+from matplotlib.transforms import IdentityTransform
 
-from matplotlib.transforms import get_vec6_scales
-
 import numpy as npy
 import binascii
 import re
@@ -141,7 +141,9 @@
 self.fontsize = None
 self.hatch = None
 self.image_magnification = dpi/72.0
-
+ self._clip_paths = {}
+ self._path_collection_id = 0
+ 
 self.fontd = {}
 self.afmfontd = {}
 self.used_characters = {}
@@ -247,7 +249,7 @@
 hatchl cvi hatchgap idiv hatchgap mul
 hatchgap
 hatchr cvi hatchgap idiv hatchgap mul
- {hatcht moveto 0 hatchb hatcht sub rlineto}
+ {hatcht m 0 hatchb hatcht sub r }
 for
 stroke
 grestore
@@ -330,18 +332,6 @@
 font.set_size(size, 72.0)
 return font
 
- def draw_arc(self, gc, rgbFace, x, y, width, height, angle1, angle2, rotation):
- """
- Draw an arc centered at x,y with width and height and angles
- from 0.0 to 360.0
-
- If gcFace is not None, fill the arc slice with it. gcEdge
- is a GraphicsContext instance
- """
- ps = '%f %f translate\n%f rotate\n%f %f translate\n%s ellipse' % \
- (x, y, rotation, -x, -y, _nums_to_str(angle1, angle2, 0.5*width, 0.5*height, x, y))
- self._draw_ps(ps, gc, rgbFace, "arc")
-
 def _rgba(self, im):
 return im.as_rgba_str()
 
@@ -428,14 +418,47 @@
 # unflip
 im.flipud_out()
 
- def draw_line(self, gc, x0, y0, x1, y1):
+ def _convert_path(self, path, transform):
+ path = transform.transform_path(path)
+ 
+ ps = []
+ for points, code in path.iter_segments():
+ if code == Path.MOVETO:
+ ps.append("%g %g m" % tuple(points))
+ elif code == Path.LINETO:
+ ps.append("%g %g l" % tuple(points))
+ elif code == Path.CURVE3:
+ ps.append("%g %g %g %g %g %g c" %
+ (points[0], points[1],
+ points[0], points[1],
+ points[2], points[3]))
+ elif code == Path.CURVE4:
+ ps.append("%g %g %g %g %g %g c" % tuple(points))
+ elif code == Path.CLOSEPOLY:
+ ps.append("cl")
+ ps = "\n".join(ps)
+ 
+ return ps
+
+ def _get_clip_path(self, clippath, clippath_transform):
+ id = self._clip_paths.get((clippath, clippath_transform))
+ if id is None:
+ id = 'c%x' % len(self._clip_paths)
+ ps_cmd = ['/%s {' % id]
+ ps_cmd.append(self._convert_path(clippath, clippath_transform))
+ ps_cmd.extend(['clip', 'newpath', '} bind def\n'])
+ self._pswriter.write('\n'.join(ps_cmd))
+ self._clip_paths[(clippath, clippath_transform)] = id
+ return id
+
+ def draw_path(self, gc, path, transform, rgbFace=None):
 """
- Draw a single line from x0,y0 to x1,y1
- """
- ps = '%1.4g %1.4g m %1.4g %1.4g l'%(x0, y0, x1, y1)
- self._draw_ps(ps, gc, None, "line")
+ Draws a Path instance using the given affine transform.
+	"""
+ ps = self._convert_path(path, transform)
+ self._draw_ps(ps, gc, rgbFace)
 
- def draw_markers(self, gc, path, rgbFace, x, y, transform):
+ def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None):
 """
 Draw the markers defined by path at each of the positions in x
 and y. path coordinates are points, x and y coords will be
@@ -452,216 +475,82 @@
 ps_color = '%1.3f %1.3f %1.3f setrgbcolor' % rgbFace
 
 # construct the generic marker command:
- ps_cmd = ['gsave'] # dont want the translate to be global
- ps_cmd.append('newpath')
- ps_cmd.append('translate')
- while 1:
- code, xp, yp = path.vertex()
- if code == agg.path_cmd_stop:
- ps_cmd.append('closepath') # Hack, path_cmd_end_poly not found
- break
- elif code == agg.path_cmd_move_to:
- ps_cmd.append('%g %g m' % (xp,yp))
- elif code == agg.path_cmd_line_to:
- ps_cmd.append('%g %g l' % (xp,yp))
- elif code == agg.path_cmd_curve3:
- pass
- elif code == agg.path_cmd_curve4:
- pass
- elif code == agg.path_cmd_end_poly:
- pass
- ps_cmd.append('closepath')
- elif code == agg.path_cmd_mask:
- pass
- else:
- pass
- #print code
+ ps_cmd = ['/o {', 'gsave', 'newpath', 'translate'] # dont want the translate to be global
+ ps_cmd.append(self._convert_path(marker_path, marker_trans))
 
 if rgbFace:
- ps_cmd.append('gsave')
- ps_cmd.append(ps_color)
- ps_cmd.append('fill')
- ps_cmd.append('grestore')
+ ps_cmd.extend(['gsave', ps_color, 'fill', 'grestore'])
 
- ps_cmd.append('stroke')
- ps_cmd.append('grestore') # undo translate()
- ps_cmd = '\n'.join(ps_cmd)
+ ps_cmd.extend(['stroke', 'grestore', '} bind def'])
+ 
+ tpath = trans.transform_path(path)
+ for x, y in tpath.vertices:
+ ps_cmd.append("%1.3g %1.3g o" % (x, y))
 
- self.push_gc(gc, store=1)
+ ps = '\n'.join(ps_cmd)
+ self._draw_ps(ps, gc, rgbFace, fill=False, stroke=False)
 
- def drawone(x, y):
- try:
- xt, yt = transform.xy_tup((x, y))
- ret = '%g %g o' % (xt, yt)
- except ValueError:
- pass
- else:
- return ret
-
- step = 500
- start = 0
- end = step
-
- mask = npy.where(npy.isnan(x) + npy.isnan(y), 0, 1)
-
- cliprect = gc.get_clip_rectangle()
- if cliprect:
- write('gsave\n')
- xc,yc,wc,hc=cliprect
- write('%g %g %g %g clipbox\n' % (wc,hc,xc,yc))
- write(' '.join(['/o {', ps_cmd, '} bind def\n']))
- # Now evaluate the marker command at each marker location:
- while start < len(x):
- todraw = izip(x[start:end+1], y[start:end+1], mask[start:end+1])
- ps = [i for i in [drawone(xi,yi) for xi,yi,mi in todraw if mi] if i]
- write('\n'.join(ps)+'\n')
- start = end
- end += step
- if cliprect: write('grestore\n')
-
- def draw_path(self,gc,rgbFace,path,trans):
- pass
-
- def draw_lines(self, gc, x, y, transform):
- """
- x and y are npy.equal length arrays, draw lines connecting each
- point in x, y
- """
- if debugPS: self._pswriter.write('% draw_lines \n')
-
+ def draw_path_collection(self, master_transform, cliprect, clippath,
+ clippath_trans, paths, all_transforms, offsets,
+ offsetTrans, facecolors, edgecolors, linewidths,
+ linestyles, antialiaseds):
 write = self._pswriter.write
+ 
+ Npaths = len(paths)
+ Noffsets = len(offsets)
+ N = max(Npaths, Noffsets)
+ Ntransforms = min(len(all_transforms), N)
+ Ntpaths = max(Npaths, Ntransforms)
+ Nfacecolors = len(facecolors)
+ Nedgecolors = len(edgecolors)
+ Nlinewidths = len(linewidths)
+ Nlinestyles = len(linestyles)
+ Naa = len(antialiaseds)
 
- def drawone(x, y, skip):
- try:
- if skip: raise(ValueError)
- xt, yt = transform.xy_tup((x, y))
- ret = '%g %g %c' % (xt, yt, drawone.state)
- except ValueError:
- drawone.state = 'm'
- else:
- drawone.state = 'l'
- return ret
+ if (Nfacecolors == 0 and Nedgecolors == 0) or N == 0:
+ return
+ 
+ for i in range(Ntpaths):
+ path = paths[i % Npaths]
+ transform = all_transforms[i % Ntransforms]
+ if transform is None:
+ transform = IdentityTransform()
+ transform += master_transform
 
- step = 100000
- start = 0
- end = step
+ ps_cmd = ['/p%x_%x {' % (self._path_collection_id, i),
+ 'newpath', 'translate']
+ ps_cmd.append(self._convert_path(path, transform))
+ ps_cmd.extend(['} bind def\n'])
+ write('\n'.join(ps_cmd))
+ 
+ toffsets = offsetTrans.transform(offsets)
+ 
+ gc = self.new_gc()
 
- skip = npy.where(npy.isnan(x) + npy.isnan(y), 1, 0)
- points = zip(x,y,skip)
+ gc.set_clip_rectangle(cliprect)
+ if clippath is not None:
+ clippath = transforms.TransformedPath(clippath, clippath_trans)
+ gc.set_clippath(clippath)
+ 
+ if Nfacecolors == 0:
+ rgbFace = None
 
- self.push_gc(gc, store=1)
- cliprect = gc.get_clip_rectangle()
- if cliprect:
- write('gsave\n')
- xc,yc,wc,hc=cliprect
- write('%g %g %g %g clipbox\n' % (wc,hc,xc,yc))
- while start < len(points):
- drawone.state = 'm'
- ps = [i for i in [drawone(x,y,s) for x,y,s in points[start:end+1]]\
- if i]
- ps.append('stroke')
- write('\n'.join(ps)+'\n')
- start = end
- end += step
- if cliprect: write('grestore\n')
+ for i in xrange(N):
+ path_id = i % Ntpaths
+ xo, yo = toffsets[i % Noffsets]
+ if Nfacecolors:
+ rgbFace = facecolors[i % Nfacecolors]
+ if Nedgecolors:
+ gc.set_foreground(edgecolors[i % Nedgecolors])
+ gc.set_linewidth(linewidths[i % Nlinewidths])
+ gc.set_dashes(*linestyles[i % Nlinestyles])
+ gc.set_antialiased(antialiaseds[i % Naa])
 
+ ps = "%g %g p%x_%x" % (xo, yo, self._path_collection_id, path_id)
+ self._draw_ps(ps, gc, rgbFace)
 
- def draw_lines_old(self, gc, x, y, transform=None):
- """
- x and y are npy.equal length arrays, draw lines connecting each
- point in x, y
- """
- if debugPS: self._pswriter.write('% draw_lines \n')
-
- write = self._pswriter.write
-
- mask = npy.where(npy.isnan(x) + npy.isnan(y), 0, 1)
- if transform: # this won't be called if draw_markers is hidden
- if transform.need_nonlinear():
- x,y,mask = transform.nonlinear_only_numerix(x, y, returnMask=1)
-
- # a,b,c,d,tx,ty affine which transforms x and y into ps coordinates
- a,b,c,d,tx,ty = transform.as_vec6_val()
-
- xo = a*x+c*y+tx
- yo = b*x+d*y+ty
- x,y = xo,yo
-
- self.push_gc(gc, store=1)
-
- cliprect = gc.get_clip_rectangle()
- if cliprect:
- write('gsave\n')
- xc,yc,wc,hc=cliprect
- write('%g %g %g %g clipbox\n' % (wc,hc,xc,yc))
-
- steps = 50
- start = 0
- end = steps
- points = zip(x,y)
-
- while start < len(x):
- # npy.put moveto on all the bad data and on the first good
- # point after the bad data
- codes = [('m','l')[int(i)] for i in mask]
- ind = npy.nonzero(mask[start:end+1]==0)+1
- if len(ind):
- if ind[-1]>=len(codes):
- ind = ind[:-1]
- for i in ind:
- codes[i] = 'm'
- # npy.put a moveto on the first point, regardless
- codes[0] = 'm'
-
- thisx = x[start:end+1]
- thisy = y[start:end+1]
- to_draw = izip(thisx, thisy, codes, mask)
- if not to_draw:
- break
-
- ps = ["%g %g %c" % (xp, yp, c) for xp, yp, c, m in to_draw if m]
- if transform:
- ps.append('stroke')
- write('\n'.join(ps)+'\n')
- else:
- self._draw_ps("\n".join(ps)+'\n', gc, None)
- start = end
- end += steps
- if transform:
- if cliprect: write("grestore\n")
-
- def draw_point(self, gc, x, y):
- """
- Draw a single point at x,y
- """
- # TODO: is there a better way to draw points in postscript?
- # (use a small circle?)
- self.draw_line(gc, x, y, x+1, y+1)
-
- def draw_polygon(self, gc, rgbFace, points):
- """
- Draw a polygon. points is a len vertices tuple, each element
- giving the x,y coords a vertex
-
- If rgbFace is not None, fill the poly with it. gc
- is a GraphicsContext instance
- """
- ps = ["%s m\n" % _nums_to_str(*points[0])]
- ps.extend([ "%s l\n" % _nums_to_str(x, y) for x,y in points[1:] ])
- ps.append("closepath")
- self._draw_ps(''.join(ps), gc, rgbFace, "polygon")
-
- def draw_rectangle(self, gc, rgbFace, x, y, width, height):
- """
- Draw a rectangle with lower left at x,y with width and height.
-
- If gcFace is not None, fill the rectangle with it. gcEdge
- is a GraphicsContext instance
- """
- # TODO: use rectstroke
- ps = '%s box' % _nums_to_str(width, height, x, y)
- self._draw_ps(ps, gc, rgbFace, "rectangle")
-
+ self._path_collection_id += 1
+ 
 def draw_tex(self, gc, x, y, s, prop, angle, ismath='TeX!'):
 """
 draw a Text instance
@@ -853,7 +742,6 @@
 """ % locals()
 self._pswriter.write(ps)
 
-
 def draw_mathtext(self, gc,
 x, y, s, prop, angle):
 """
@@ -875,68 +763,57 @@
 """ % locals()
 self._pswriter.write(ps)
 
- def _draw_ps(self, ps, gc, rgbFace, command=None):
+ def _draw_ps(self, ps, gc, rgbFace, fill=True, stroke=True, command=None):
 """
 Emit the PostScript sniplet 'ps' with all the attributes from 'gc'
 applied. 'ps' must consist of PostScript commands to construct a path.
 """
 # local variable eliminates all repeated attribute lookups
 write = self._pswriter.write
- write('gsave\n')
+ # write('gsave\n')
 if debugPS and command:
 write("% "+command+"\n")
 
- cliprect = gc.get_clip_rectangle()
- self.set_color(*gc.get_rgb())
 self.set_linewidth(gc.get_linewidth())
 jint = gc.get_joinstyle()
 self.set_linejoin(jint)
 cint = gc.get_capstyle()
 self.set_linecap(cint)
 self.set_linedash(*gc.get_dashes())
-
+ 
+ cliprect = gc.get_clip_rectangle()
 if cliprect:
- x,y,w,h=cliprect
+ x,y,w,h=cliprect.bounds
 write('gsave\n%1.4g %1.4g %1.4g %1.4g clipbox\n' % (w,h,x,y))
+ clippath, clippath_trans = gc.get_clip_path()
+ if clippath:
+ id = self._get_clip_path(clippath, clippath_trans)
+ write('gsave\n%s\n' % id)
+ 
 # Jochen, is the strip necessary? - this could be a honking big string
 write(ps.strip())
 write("\n")
- if rgbFace:
+
+ if rgbFace is not None and fill:
 #print 'rgbface', rgbFace
 write("gsave\n")
- self.set_color(store=0, *rgbFace)
+ self.set_color(store=0, *rgbFace[:3])
 write("fill\ngrestore\n")
 
 hatch = gc.get_hatch()
 if (hatch):
 self.set_hatch(hatch)
 
- if self.linewidth > 0:
+ if self.linewidth > 0 and stroke:
+ self.set_color(*gc.get_rgb()[:3])
 write("stroke\n")
+ if clippath:
+ write("grestore\n")
 if cliprect:
 write("grestore\n")
- write('grestore\n') 
- def push_gc(self, gc, store=1):
- """
- Push the current onto stack, with the exception of the clip box, which
- must be isolated in a gsave/grestore pair.
- """
- # local variable eliminates all repeated attribute lookups
- write = self._pswriter.write
+ #write('grestore\n')
 
- self.set_color(store=store, *gc.get_rgb())
- self.set_linewidth(gc.get_linewidth(), store=store)
- self.set_linejoin(gc.get_joinstyle(), store=store)
- self.set_linecap(gc.get_capstyle(), store=store)
- self.set_linedash(store=store, *gc.get_dashes())
-
-## cliprect = gc.get_clip_rectangle()
-## if cliprect:
-## x,y,w,h=cliprect
-## write('%1.3f %1.3f %1.3f %1.3f clipbox\n' % (w,h,x,y))
-
-## write("\n")
-
+ 
 class GraphicsContextPS(GraphicsContextBase):
 def get_capstyle(self):
 return {'butt':0,
@@ -1044,7 +921,7 @@
 xo = 72*0.5*(paperWidth - width)
 yo = 72*0.5*(paperHeight - height)
 
- l, b, w, h = self.figure.bbox.get_bounds()
+ l, b, w, h = self.figure.bbox.bounds
 llx = xo
 lly = yo
 urx = llx + w
@@ -1521,33 +1398,6 @@
 # http://www.mactech.com/articles/mactech/Vol.09/09.04/PostscriptTutorial/
 # http://www.math.ubc.ca/people/faculty/cass/graphics/text/www/
 #
-# Some comments about the implementation:
-#
-# Drawing ellipses:
-#
-# ellipse adds a counter-clockwise segment of an elliptical arc to the
-# current path. The ellipse procedure takes six operands: the x and y
-# coordinates of the center of the ellipse (the center is defined as
-# the point of intersection of the major and minor axes), the
-# ``radius'' of the ellipse in the x direction, the ``radius'' of the
-# ellipse in the y direction, the starting angle of the elliptical arc
-# and the ending angle of the elliptical arc.
-#
-# The basic strategy used in drawing the ellipse is to translate to
-# the center of the ellipse, scale the user coordinate system by the x
-# and y radius values, and then add a circular arc, centered at the
-# origin with a 1 unit radius to the current path. We will be
-# transforming the user coordinate system with the translate and
-# rotate operators to add the elliptical arc segment but we don't want
-# these transformations to affect other parts of the program. In other
-# words, we would like to localize the effect of the transformations.
-# Usually the gsave and grestore operators would be ideal candidates
-# for this task. Unfortunately gsave and grestore are inappropriate
-# for this situation because we cannot save the arc segment that we
-# have added to the path. Instead we will localize the effect of the
-# transformations by saving the current transformation matrix and
-# restoring it explicitly after we have added the elliptical arc to
-# the path.
 
 # The usage comments use the notation of the operator summary
 # in the PostScript Language reference manual.
@@ -1558,28 +1408,22 @@
 "/l { lineto } bind def",
 # x y *r* -
 "/r { rlineto } bind def",
+ # x1 y1 x2 y2 x y *c* -
+ "/c { curveto } bind def",
+ # *closepath* -
+ "/cl { closepath } bind def",
 # w h x y *box* -
 """/box {
 m
 1 index 0 r
 0 exch r
 neg 0 r
- closepath
+ cl
 } bind def""",
 # w h x y *clipbox* -
 """/clipbox {
 box
 clip
 newpath
- } bind def""",
- # angle1 angle2 rx ry x y *ellipse* -
- """/ellipse {
- newpath
- matrix currentmatrix 7 1 roll
- translate
- scale
- 0 0 1 5 3 roll arc
- setmatrix
- closepath
 } bind def"""
 ]
Modified: branches/transforms/lib/matplotlib/cbook.py
===================================================================
--- branches/transforms/lib/matplotlib/cbook.py	2007年10月16日 13:45:59 UTC (rev 3954)
+++ branches/transforms/lib/matplotlib/cbook.py	2007年10月16日 14:17:53 UTC (rev 3955)
@@ -174,6 +174,7 @@
 def __str__(self):
 return '<a list of %d %s objects>' % (len(self), self.type)
 
+# MGDTODO: This is very incomplete
 def strip_math(s):
 'remove latex formatting from mathtext'
 remove = (r'\rm', '\cal', '\tt', '\it', '\\', '{', '}')
Modified: branches/transforms/lib/matplotlib/collections.py
===================================================================
--- branches/transforms/lib/matplotlib/collections.py	2007年10月16日 13:45:59 UTC (rev 3954)
+++ branches/transforms/lib/matplotlib/collections.py	2007年10月16日 14:17:53 UTC (rev 3955)
@@ -167,7 +167,9 @@
 self.update_scalarmappable()
 
 clippath, clippath_trans = self.get_transformed_clip_path_and_affine()
-
+ if clippath_trans is not None:
+ clippath_trans = clippath_trans.frozen()
+ 
 # MGDTODO: This may benefit from using TransformedPath
 if not transform.is_affine:
 paths = [transform.transform_path_non_affine(path) for path in paths]
@@ -175,9 +177,9 @@
 if not transOffset.is_affine:
 offsets = transOffset.transform_non_affine(offsets)
 transOffset = transOffset.get_affine()
- 
+ 
 renderer.draw_path_collection(
- transform, self.clipbox, clippath, clippath_trans,
+ transform.frozen(), self.clipbox, clippath, clippath_trans,
 paths, self.get_transforms(),
 npy.asarray(offsets, npy.float_), transOffset, 
 self._facecolors, self._edgecolors, self._linewidths,
Modified: branches/transforms/lib/matplotlib/lines.py
===================================================================
--- branches/transforms/lib/matplotlib/lines.py	2007年10月16日 13:45:59 UTC (rev 3954)
+++ branches/transforms/lib/matplotlib/lines.py	2007年10月16日 14:17:53 UTC (rev 3955)
@@ -458,7 +458,7 @@
 if funcname != '_draw_nothing':
 tpath, affine = self._transformed_path.get_transformed_path_and_affine()
 lineFunc = getattr(self, funcname)
- lineFunc(renderer, gc, tpath, affine)
+ lineFunc(renderer, gc, tpath, affine.frozen())
 	 
 if self._marker is not None:
 gc = renderer.new_gc()
@@ -470,7 +470,7 @@
 if funcname != '_draw_nothing':
 tpath, affine = self._transformed_path.get_transformed_path_and_affine()
 markerFunc = getattr(self, funcname)
- markerFunc(renderer, gc, tpath, affine)
+ markerFunc(renderer, gc, tpath, affine.frozen())
 
 renderer.close_group('line2d')
 
Modified: branches/transforms/lib/matplotlib/path.py
===================================================================
--- branches/transforms/lib/matplotlib/path.py	2007年10月16日 13:45:59 UTC (rev 3954)
+++ branches/transforms/lib/matplotlib/path.py	2007年10月16日 14:17:53 UTC (rev 3955)
@@ -142,7 +142,7 @@
 	return self._vertices
 vertices = property(_get_vertices)
 
- def iter_endpoints(self):
+ def iter_segments(self):
 """
 Iterates over all of the endpoints in the path. Unlike
 iterating directly over the vertices array, curve control
@@ -151,15 +151,20 @@
 	i = 0
 	NUM_VERTICES = self.NUM_VERTICES
 	vertices = self.vertices
-	for code in self.codes:
+ codes = self.codes
+ 
+	while i < len(vertices):
+ code = codes[i]
 if code == self.CLOSEPOLY:
+ yield [], code
 i += 1
+ elif code == self.STOP:
+ return
 else:
 num_vertices = NUM_VERTICES[code]
- i += num_vertices - 1
- yield vertices[i]
- i += 1
-
+ yield vertices[i:i+num_vertices].flatten(), code
+ i += num_vertices
+ 
 def transformed(self, transform):
 """
 Return a transformed copy of the path.
Modified: branches/transforms/lib/matplotlib/transforms.py
===================================================================
--- branches/transforms/lib/matplotlib/transforms.py	2007年10月16日 13:45:59 UTC (rev 3954)
+++ branches/transforms/lib/matplotlib/transforms.py	2007年10月16日 14:17:53 UTC (rev 3955)
@@ -822,6 +822,12 @@
 raise TypeError(
 "Can not add Transform to object of type '%s'" % type(other))
 
+ def __array__(self):
+ """
+ Used by C/C++ -based backends to get at the array matrix data.
+ """
+ return self.frozen().__array__()
+ 
 def transform(self, values):
 """
 Performs the transformation on the given array of values.
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2007年10月23日 16:40:32
Revision: 3985
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3985&view=rev
Author: mdboom
Date: 2007年10月23日 09:40:25 -0700 (2007年10月23日)
Log Message:
-----------
More progress on SVG. Refactored PS collection drawing to make it
easier to reuse the (fairly complex) code.
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/backend_bases.py
 branches/transforms/lib/matplotlib/backends/backend_ps.py
 branches/transforms/lib/matplotlib/backends/backend_svg.py
Modified: branches/transforms/lib/matplotlib/backend_bases.py
===================================================================
--- branches/transforms/lib/matplotlib/backend_bases.py	2007年10月23日 14:30:57 UTC (rev 3984)
+++ branches/transforms/lib/matplotlib/backend_bases.py	2007年10月23日 16:40:25 UTC (rev 3985)
@@ -55,13 +55,90 @@
 offsetTrans, facecolors, edgecolors, linewidths,
 linestyles, antialiaseds):
 """
- MGDTODO: Document me. Explain that often the backend will not
- want to override this.
+ This provides a fallback implementation of
+ draw_path_collection that makes multiple calls to draw_path.
+ Often, the backend will want to override this in order to
+ render each set of path data only once, and then reference
+ that path multiple times with the different offsets, colors,
+ styles etc. The methods _iter_collection_raw_paths and
+ _iter_collection are provided to help with (and standardize)
+ the implementation that in each backend.
 """
+ path_ids = []
+ for path, transform in self._iter_collection_raw_paths(
+ master_transform, paths, all_transforms):
+ path_ids.append((path, transform))
+
+ for xo, yo, path_id, gc, rgbFace in self._iter_collection(
+ path_ids, cliprect, clippath, clippath_trans,
+ offsets, offsetTrans, facecolors, edgecolors,
+ linewidths, linestyles, antialiaseds):
+ path, transform = path_id
+ transform = transform.frozen().translate(xo, yo)
+ self.draw_path(gc, path, transform, rgbFace)
+ 
+ def _iter_collection_raw_paths(self, master_transform, paths, all_transforms):
+ """
+ This is a helper method (along with _iter_collection) to make
+ it easier to write a space-efficent draw_path_collection
+ implementation in a backend.
+
+ This method yields all of the base path/transform
+ combinations, given a master transform, a list of paths and
+ list of transforms.
+
+ The arguments should be exactly what is passed in to
+ draw_path_collection.
+
+ The backend should take each yielded path and transform and
+ create an object can be referenced (reused) later.
+ """
 Npaths = len(paths)
+ Ntransforms = len(all_transforms)
+ N = max(Npaths, Ntransforms)
+
+ if Npaths == 0:
+ return
+
+ for i in xrange(N):
+ path = paths[i % Npaths]
+ transform = all_transforms[i % Ntransforms]
+ if transform is None:
+ transform = transforms.IdentityTransform()
+ transform += master_transform
+ yield path, transform
+
+ def _iter_collection(self, path_ids, cliprect, clippath, clippath_trans,
+ offsets, offsetTrans, facecolors, edgecolors,
+ linewidths, linestyles, antialiaseds):
+ """
+ This is a helper method (along with
+ _iter_collection_raw_paths) to make it easier to write a
+ space-efficent draw_path_collection implementation in a
+ backend.
+
+ This method yields all of the path, offset and graphics
+ context combinations to draw the path collection. The caller
+ should already have looped over the results of
+ _iter_collection_raw_paths to draw this collection.
+
+ The arguments should be the same as that passed into
+ draw_path_collection, with the exception of path_ids, which
+ is a list of arbitrary objects that the backend will use to
+ reference one of the paths created in the
+ _iter_collection_raw_paths stage.
+
+ Each yielded result is of the form:
+
+ xo, yo, path_id, gc, rgbFace
+
+ where xo, yo is an offset; path_id is one of the elements of
+ path_ids; gc is a graphics context and rgbFace is a color to
+ use for filling the path.
+ """
+ Npaths = len(path_ids)
 Noffsets = len(offsets)
 N = max(Npaths, Noffsets)
- Ntransforms = min(len(all_transforms), N)
 Nfacecolors = len(facecolors)
 Nedgecolors = len(edgecolors)
 Nlinewidths = len(linewidths)
@@ -71,16 +148,10 @@
 if (Nfacecolors == 0 and Nedgecolors == 0) or Npaths == 0:
 return
 
- ttransforms = []
- for i in range(Ntransforms):
- transform = all_transforms[i]
- if transform is None:
- transform = transforms.IdentityTransform()
- ttransforms.append((transform + master_transform).frozen())
-
 toffsets = offsetTrans.transform(offsets)
 
 gc = self.new_gc()
+
 gc.set_clip_rectangle(cliprect)
 if clippath is not None:
 clippath = transforms.TransformedPath(clippath, clippath_trans)
@@ -89,12 +160,9 @@
 if Nfacecolors == 0:
 rgbFace = None
 
- print linewidths, edgecolors
- 
 for i in xrange(N):
- path = paths[i % Npaths]
+ path_id = path_ids[i % Npaths]
 xo, yo = toffsets[i % Noffsets]
- transform = ttransforms[i % Ntransforms].frozen().translate(xo, yo)
 if Nfacecolors:
 rgbFace = facecolors[i % Nfacecolors]
 if Nedgecolors:
@@ -103,8 +171,8 @@
 gc.set_dashes(*linestyles[i % Nlinestyles])
 gc.set_antialiased(antialiaseds[i % Naa])
 
- self.draw_path(gc, path, transform, rgbFace)
- 
+ yield xo, yo, path_id, gc, rgbFace
+ 
 def get_image_magnification(self):
 """
 Get the factor by which to magnify images passed to draw_image.
Modified: branches/transforms/lib/matplotlib/backends/backend_ps.py
===================================================================
--- branches/transforms/lib/matplotlib/backends/backend_ps.py	2007年10月23日 14:30:57 UTC (rev 3984)
+++ branches/transforms/lib/matplotlib/backends/backend_ps.py	2007年10月23日 16:40:25 UTC (rev 3985)
@@ -503,57 +503,22 @@
 linestyles, antialiaseds):
 write = self._pswriter.write
 
- Npaths = len(paths)
- Noffsets = len(offsets)
- N = max(Npaths, Noffsets)
- Ntransforms = min(len(all_transforms), N)
- Ntpaths = max(Npaths, Ntransforms)
- Nfacecolors = len(facecolors)
- Nedgecolors = len(edgecolors)
- Nlinewidths = len(linewidths)
- Nlinestyles = len(linestyles)
- Naa = len(antialiaseds)
-
- if (Nfacecolors == 0 and Nedgecolors == 0) or Npaths == 0:
- return
- 
- for i in range(Ntpaths):
- path = paths[i % Npaths]
- transform = all_transforms[i % Ntransforms]
- if transform is None:
- transform = IdentityTransform()
- transform += master_transform
-
+ path_codes = []
+ for i, (path, transform) in enumerate(self._iter_collection_raw_paths(
+ master_transform, paths, all_transforms)):
 ps_cmd = ['/p%x_%x {' % (self._path_collection_id, i),
 'newpath', 'translate']
 ps_cmd.append(self._convert_path(path, transform))
 ps_cmd.extend(['} bind def\n'])
 write('\n'.join(ps_cmd))
+ path_codes.append("p%x_%x" % (self._path_collection_id, i))
 
- toffsets = offsetTrans.transform(offsets)
- 
- gc = self.new_gc()
+ for xo, yo, path_id, gc, rgbFace in self._iter_collection(
+ path_codes, cliprect, clippath, clippath_trans,
+ offsets, offsetTrans, facecolors, edgecolors,
+ linewidths, linestyles, antialiaseds):
 
- gc.set_clip_rectangle(cliprect)
- if clippath is not None:
- clippath = transforms.TransformedPath(clippath, clippath_trans)
- gc.set_clippath(clippath)
- 
- if Nfacecolors == 0:
- rgbFace = None
-
- for i in xrange(N):
- path_id = i % Ntpaths
- xo, yo = toffsets[i % Noffsets]
- if Nfacecolors:
- rgbFace = facecolors[i % Nfacecolors]
- if Nedgecolors:
- gc.set_foreground(edgecolors[i % Nedgecolors])
- gc.set_linewidth(linewidths[i % Nlinewidths])
- gc.set_dashes(*linestyles[i % Nlinestyles])
- gc.set_antialiased(antialiaseds[i % Naa])
-
- ps = "%g %g p%x_%x" % (xo, yo, self._path_collection_id, path_id)
+ ps = "%g %g %s" % (xo, yo, path_id)
 self._draw_ps(ps, gc, rgbFace)
 
 self._path_collection_id += 1
@@ -786,7 +751,9 @@
 cint = gc.get_capstyle()
 self.set_linecap(cint)
 self.set_linedash(*gc.get_dashes())
- 
+ if self.linewidth > 0 and stroke:
+ self.set_color(*gc.get_rgb()[:3])
+
 cliprect = gc.get_clip_rectangle()
 if cliprect:
 x,y,w,h=cliprect.bounds
Modified: branches/transforms/lib/matplotlib/backends/backend_svg.py
===================================================================
--- branches/transforms/lib/matplotlib/backends/backend_svg.py	2007年10月23日 14:30:57 UTC (rev 3984)
+++ branches/transforms/lib/matplotlib/backends/backend_svg.py	2007年10月23日 16:40:25 UTC (rev 3985)
@@ -47,16 +47,16 @@
 svgwriter.write(svgProlog%(width,height,width,height))
 
 def _draw_svg_element(self, element, details, gc, rgbFace):
- cliprect, clipid = self._get_gc_clip_svg(gc)
+ clipid = self._get_gc_clip_svg(gc)
 if clipid is None:
 clippath = ''
 else:
 clippath = 'clip-path="url(#%s)"' % clipid
 
 style = self._get_style(gc, rgbFace)
- self._svgwriter.write ('%s<%s style="%s" %s %s/>\n' % (
- cliprect, element, style, clippath, details))
-
+ self._svgwriter.write ('<%s style="%s" %s %s/>\n' % (
+ element, style, clippath, details))
+ 
 def _get_font(self, prop):
 key = hash(prop)
 font = self.fontd.get(key)
@@ -108,36 +108,23 @@
 cliprect = gc.get_clip_rectangle()
 clippath, clippath_trans = gc.get_clip_path()
 if clippath is not None:
- pathkey = (hash(clippath), hash(clippath_trans))
- path = ''
- if self._clipd.get(pathkey) is None:
- self._clipd[pathkey] = clippath
- path_data = self._convert_path(clippath, clippath_trans)
- path = """\
-<defs>
- <clipPath id="%(pathkey)s">
- <path d="%(path_data)s"/>
- </clipPath>
-</defs>
-""" % locals()
- return path, pathkey
+ path_data = self._convert_path(clippath, clippath_trans)
+ path = '<path d="%s"/>' % path_data
 elif cliprect is not None:
- rectkey = hash(cliprect)
- box = ''
- if self._clipd.get(rectkey) is None:
- self._clipd[rectkey] = cliprect
- x, y, w, h = cliprect.bounds
- y = self.height-(y+h)
- box = """\
-<defs>
- <clipPath id="%(rectkey)s">
- <rect x="%(x)s" y="%(y)s" width="%(w)s" height="%(h)s"/>
- </clipPath>
-</defs>
-""" % locals()
- return box, rectkey
- 
- return '', None
+ x, y, w, h = cliprect.bounds
+ y = self.height-(y+h)
+ path = '<rect x="%(x)s" y="%(y)s" width="%(w)s" height="%(h)s"/>' % locals()
+ else:
+ return None
+ 
+ id = self._clipd.get(path)
+ if id is None:
+ id = 'p%x' % len(self._clipd)
+ self._svgwriter.write('<defs>\n <clipPath id="%s">\n' % id)
+ self._svgwriter.write(path)
+ self._svgwriter.write('\n </clipPath>\n</defs>')
+ self._clipd[path] = id
+ return id
 
 def open_group(self, s):
 self._groupd[s] = self._groupd.get(s,0) + 1
@@ -193,17 +180,17 @@
 def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None):
 write = self._svgwriter.write
 
- key = self._convert_path(marker_path, marker_trans + Affine2D().scale(0, -1.0))
+ key = self._convert_path(marker_path, marker_trans + Affine2D().scale(1.0, -1.0))
 name = self._markers.get(key)
 if name is None:
- name = 'm_%x' % len(self._markers)
+ name = 'm%x' % len(self._markers)
 write('<defs><path id="%s" d="%s"/></defs>\n' % (name, key))
 self._markers[key] = name
 
 trans_and_flip = self._make_flip_transform(trans)
 tpath = trans_and_flip.transform_path(path)
 for x, y in tpath.vertices:
- details = 'xlink:href="#%s" transform="translate(%f, %f)"' % (name, x, y)
+ details = 'xlink:href="#%s" x="%f" y="%f"' % (name, x, y)
 self._draw_svg_element('use', details, gc, rgbFace)
 
 def draw_image(self, x, y, im, bbox):
@@ -307,7 +294,7 @@
 
 svg.append('<use xlink:href="#%s"' % charid)
 if currx != 0:
- svg.append(' transform="translate(%s)"' %
+ svg.append(' x="%s"' %
 (currx * (self.FONT_SCALE / fontsize)))
 svg.append('/>\n')
 currx += (glyph.linearHoriAdvance / 65536.0)
@@ -364,7 +351,7 @@
 
 if step[0] != 4:
 currx, curry = step[-2], -step[-1]
- char_num = 'c_%x' % len(self._char_defs)
+ char_num = 'c%x' % len(self._char_defs)
 path_element = '<path id="%s" d="%s"/>\n' % (char_num, ''.join(path_data))
 self._char_defs[char_id] = (char_num, path_element)
 return char_num
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2007年10月24日 19:22:04
Revision: 3997
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3997&view=rev
Author: mdboom
Date: 2007年10月24日 12:22:00 -0700 (2007年10月24日)
Log Message:
-----------
Renamed [xmin, ymin, xmax, ymax] in Bbox to [x0, y0, x1, y1] and
provide functions that really do give xmax etc. as well.
Renamed lbrt to extents and lbwh to bounds (for consistency).
Removed some dead code.
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/axes.py
 branches/transforms/lib/matplotlib/axis.py
 branches/transforms/lib/matplotlib/backend_bases.py
 branches/transforms/lib/matplotlib/backends/backend_agg.py
 branches/transforms/lib/matplotlib/backends/backend_pdf.py
 branches/transforms/lib/matplotlib/collections.py
 branches/transforms/lib/matplotlib/figure.py
 branches/transforms/lib/matplotlib/image.py
 branches/transforms/lib/matplotlib/legend.py
 branches/transforms/lib/matplotlib/lines.py
 branches/transforms/lib/matplotlib/patches.py
 branches/transforms/lib/matplotlib/path.py
 branches/transforms/lib/matplotlib/projections/polar.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月24日 18:49:08 UTC (rev 3996)
+++ branches/transforms/lib/matplotlib/axes.py	2007年10月24日 19:22:00 UTC (rev 3997)
@@ -480,7 +480,7 @@
 if isinstance(rect, mtransforms.Bbox):
 self._position = rect
 else:
- self._position = mtransforms.Bbox.from_lbwh(*rect)
+ self._position = mtransforms.Bbox.from_bounds(*rect)
 self._originalPosition = self._position.frozen()
 self.set_axes(self)
 self.set_aspect('auto')
@@ -1696,7 +1696,7 @@
 	 # Call all of the other y-axes that are shared with this one
 	 for other in self._shared_y_axes.get_siblings(self):
 		if other is not self:
-		 other.set_ylim(self.viewLim.ymin, self.viewLim.ymax, emit=False)
+		 other.set_ylim(self.viewLim.intervaly, emit=False)
 
 if self.figure.canvas is not None:
 self.figure.canvas.draw_idle()
@@ -1902,7 +1902,6 @@
 if self.get_aspect() != 'auto':
 dx = 0.5 * (dx + dy)
 dy = dx
- xmin, ymin, xmax, ymax = p.lim.lbrt
 
 alpha = npy.power(10.0, (dx, dy))
 start = p.trans_inverse.transform_point((p.x, p.y))
@@ -5207,7 +5206,7 @@
 figBottom = top - (rowNum+1)*figH - rowNum*sepH
 figLeft = left + colNum*(figW + sepW)
 
- self.figbox = mtransforms.Bbox.from_lbwh(figLeft, figBottom, figW, figH)
+ self.figbox = mtransforms.Bbox.from_bounds(figLeft, figBottom, figW, figH)
 self.rowNum = rowNum
 self.colNum = colNum
 self.numRows = rows
Modified: branches/transforms/lib/matplotlib/axis.py
===================================================================
--- branches/transforms/lib/matplotlib/axis.py	2007年10月24日 18:49:08 UTC (rev 3996)
+++ branches/transforms/lib/matplotlib/axis.py	2007年10月24日 19:22:00 UTC (rev 3997)
@@ -1070,7 +1070,7 @@
 bottom = self.axes.bbox.ymin
 else:
 bbox = Bbox.union(bboxes)
- bottom = bbox.ymin
+ bottom = bbox.y0
 self.label.set_position( (x, bottom - self.LABELPAD*self.figure.dpi / 72.0))
 
 else:
@@ -1078,8 +1078,7 @@
 top = self.axes.bbox.ymax
 else:
 bbox = bbox_union(bboxes2)
- top = bbox.ymax
- 
+ top = bbox.y1
 self.label.set_position( (x, top+self.LABELPAD*self.figure.dpi / 72.0))
 
 def _update_offset_text_position(self, bboxes, bboxes2):
@@ -1092,7 +1091,7 @@
 bottom = self.axes.bbox.ymin
 else:
 bbox = Bbox.union(bboxes)
- bottom = bbox.ymin
+ bottom = bbox.y0
 self.offsetText.set_position((x, bottom-self.OFFSETTEXTPAD*self.figure.dpi/72.0))
 	
 def set_ticks_position(self, position):
@@ -1280,9 +1279,8 @@
 if not len(bboxes):
 left = self.axes.bbox.xmin
 else:
-
 bbox = Bbox.union(bboxes)
- left = bbox.xmin
+ left = bbox.x0
 
 self.label.set_position( (left-self.LABELPAD*self.figure.dpi/72.0, y))
 	 
@@ -1291,7 +1289,7 @@
 right = self.axes.bbox.xmax
 else:
 bbox = Bbox.union(bboxes2)
- right = bbox.xmax
+ right = bbox.x1
 
 self.label.set_position( (right+self.LABELPAD*self.figure.dpi/72.0, y))
 
Modified: branches/transforms/lib/matplotlib/backend_bases.py
===================================================================
--- branches/transforms/lib/matplotlib/backend_bases.py	2007年10月24日 18:49:08 UTC (rev 3996)
+++ branches/transforms/lib/matplotlib/backend_bases.py	2007年10月24日 19:22:00 UTC (rev 3997)
@@ -1422,7 +1422,7 @@
 self.draw()
 return
 
- xmin, ymin, xmax, ymax = lim.lbrt
+ x0, y0, x1, y1 = lim.extents
 
 # zoom to rect
 	 inverse = a.transData.inverted()
@@ -1432,49 +1432,49 @@
 Ymin,Ymax=a.get_ylim()
 
 if Xmin < Xmax:
- if x<lastx: xmin, xmax = x, lastx
- else: xmin, xmax = lastx, x
- if xmin < Xmin: xmin=Xmin
- if xmax > Xmax: xmax=Xmax
+ if x<lastx: x0, x1 = x, lastx
+ else: x0, x1 = lastx, x
+ if x0 < Xmin: x0=Xmin
+ if x1 > Xmax: x1=Xmax
 else:
- if x>lastx: xmin, xmax = x, lastx
- else: xmin, xmax = lastx, x
- if xmin > Xmin: xmin=Xmin
- if xmax < Xmax: xmax=Xmax
+ if x>lastx: x0, x1 = x, lastx
+ else: x0, x1 = lastx, x
+ if x0 > Xmin: x0=Xmin
+ if x1 < Xmax: x1=Xmax
 
 if Ymin < Ymax:
- if y<lasty: ymin, ymax = y, lasty
- else: ymin, ymax = lasty, y
- if ymin < Ymin: ymin=Ymin
- if ymax > Ymax: ymax=Ymax
+ if y<lasty: y0, y1 = y, lasty
+ else: y0, y1 = lasty, y
+ if y0 < Ymin: y0=Ymin
+ if y1 > Ymax: y1=Ymax
 else:
- if y>lasty: ymin, ymax = y, lasty
- else: ymin, ymax = lasty, y
- if ymin > Ymin: ymin=Ymin
- if ymax < Ymax: ymax=Ymax
+ if y>lasty: y0, y1 = y, lasty
+ else: y0, y1 = lasty, y
+ if y0 > Ymin: y0=Ymin
+ if y1 < Ymax: y1=Ymax
 
 if self._button_pressed == 1:
- a.set_xlim((xmin, xmax))
- a.set_ylim((ymin, ymax))
+ a.set_xlim((x0, x1))
+ a.set_ylim((y0, y1))
 elif self._button_pressed == 3:
 if a.get_xscale()=='log':
- alpha=npy.log(Xmax/Xmin)/npy.log(xmax/xmin)
- x1=pow(Xmin/xmin,alpha)*Xmin
- x2=pow(Xmax/xmin,alpha)*Xmin
+ alpha=npy.log(Xmax/Xmin)/npy.log(x1/x0)
+ rx1=pow(Xmin/x0,alpha)*Xmin
+ x2=pow(Xmax/x0,alpha)*Xmin
 else:
- alpha=(Xmax-Xmin)/(xmax-xmin)
- x1=alpha*(Xmin-xmin)+Xmin
- x2=alpha*(Xmax-xmin)+Xmin
+ alpha=(Xmax-Xmin)/(x1-x0)
+ rx1=alpha*(Xmin-x0)+Xmin
+ x2=alpha*(Xmax-x0)+Xmin
 if a.get_yscale()=='log':
- alpha=npy.log(Ymax/Ymin)/npy.log(ymax/ymin)
- y1=pow(Ymin/ymin,alpha)*Ymin
- y2=pow(Ymax/ymin,alpha)*Ymin
+ alpha=npy.log(Ymax/Ymin)/npy.log(y1/y0)
+ ry1=pow(Ymin/y0,alpha)*Ymin
+ ry2=pow(Ymax/y0,alpha)*Ymin
 else:
- alpha=(Ymax-Ymin)/(ymax-ymin)
- y1=alpha*(Ymin-ymin)+Ymin
- y2=alpha*(Ymax-ymin)+Ymin
- a.set_xlim((x1, x2))
- a.set_ylim((y1, y2))
+ alpha=(Ymax-Ymin)/(y1-y0)
+ ry1=alpha*(Ymin-y0)+Ymin
+ ry2=alpha*(Ymax-y0)+Ymin
+ a.set_xlim((rx1, rx2))
+ a.set_ylim((ry1, ry2))
 
 self.draw()
 self._xypress = None
Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py
===================================================================
--- branches/transforms/lib/matplotlib/backends/backend_agg.py	2007年10月24日 18:49:08 UTC (rev 3996)
+++ branches/transforms/lib/matplotlib/backends/backend_agg.py	2007年10月24日 19:22:00 UTC (rev 3997)
@@ -118,7 +118,7 @@
 self.mathtext_parser = MathTextParser('Agg')
 self._fontd = {}
 
- self.bbox = Bbox.from_lbwh(0,0, self.width, self.height)
+ self.bbox = Bbox.from_bounds(0, 0, self.width, self.height)
 if __debug__: verbose.report('RendererAgg.__init__ done',
 'debug-annoying')
 
@@ -227,7 +227,7 @@
 
 cliprect = gc.get_clip_rectangle()
 if cliprect is None: bbox = None
- else: bbox = Bbox.from_lbwh(*cliprect)
+ else: bbox = Bbox.from_bounds(*cliprect)
 self.draw_image(x, self.height-y, im, bbox)
 
 def get_canvas_width_height(self):
Modified: branches/transforms/lib/matplotlib/backends/backend_pdf.py
===================================================================
--- branches/transforms/lib/matplotlib/backends/backend_pdf.py	2007年10月24日 18:49:08 UTC (rev 3996)
+++ branches/transforms/lib/matplotlib/backends/backend_pdf.py	2007年10月24日 19:22:00 UTC (rev 3997)
@@ -1032,12 +1032,12 @@
 def writeMarkers(self):
 for tup in self.markers.values():
 name, object, path, trans, fillp, lw = tup
- bbox = Bbox.from_lbrt(*path.get_extents(trans))
+ bbox = Bbox.from_extents(*path.get_extents(trans))
 bbox = bbox.padded(lw * 0.5)
 self.beginStream(
 object.id, None,
 {'Type': Name('XObject'), 'Subtype': Name('Form'),
- 'BBox': list(bbox.lbrt) })
+ 'BBox': list(bbox.extents) })
 self.writePath(path, trans)
 if fillp:
 self.output(Op.fill_stroke)
Modified: branches/transforms/lib/matplotlib/collections.py
===================================================================
--- branches/transforms/lib/matplotlib/collections.py	2007年10月24日 18:49:08 UTC (rev 3996)
+++ branches/transforms/lib/matplotlib/collections.py	2007年10月24日 19:22:00 UTC (rev 3997)
@@ -126,12 +126,12 @@
 return self._transforms
 
 def get_datalim(self, transData):
- result = transforms.Bbox.from_lbrt(*path.get_path_collection_extents(
- self.get_transform().frozen(),
- self.get_paths(),
- self.get_transforms(),
- self._offsets,
- self._transOffset.frozen()))
+ result = path.get_path_collection_extents(
+ self.get_transform().frozen(),
+ self.get_paths(),
+ self.get_transforms(),
+ self._offsets,
+ self._transOffset.frozen())
 result = result.transformed(transData.inverted())
 return result
 
Modified: branches/transforms/lib/matplotlib/figure.py
===================================================================
--- branches/transforms/lib/matplotlib/figure.py	2007年10月24日 18:49:08 UTC (rev 3996)
+++ branches/transforms/lib/matplotlib/figure.py	2007年10月24日 19:22:00 UTC (rev 3997)
@@ -131,7 +131,7 @@
 
 	self._dpi_scale_trans = Affine2D()
 self.dpi = dpi
-	self.bbox_inches = Bbox.from_lbwh(0, 0, *figsize)
+	self.bbox_inches = Bbox.from_bounds(0, 0, *figsize)
 	self.bbox = TransformedBbox(self.bbox_inches, self._dpi_scale_trans)
 	
 self.frameon = frameon
@@ -351,11 +351,11 @@
 
 def get_figwidth(self):
 'Return the figwidth as a float'
-	return self.bbox_inches.xmax
+	return self.bbox_inches.width
 
 def get_figheight(self):
 'Return the figheight as a float'
- return self.bbox_inches.ymax
+ return self.bbox_inches.height
 
 def get_dpi(self):
 'Return the dpi as a float'
@@ -395,7 +395,7 @@
 
 ACCEPTS: float
 """
-	self.bbox_inches.xmax = val
+	self.bbox_inches.x1 = val
 	
 def set_figheight(self, val):
 """
@@ -403,7 +403,7 @@
 
 ACCEPTS: float
 """
-	self.bbox_inches.ymax = val
+	self.bbox_inches.y1 = val
 
 def set_frameon(self, b):
 """
Modified: branches/transforms/lib/matplotlib/image.py
===================================================================
--- branches/transforms/lib/matplotlib/image.py	2007年10月24日 18:49:08 UTC (rev 3996)
+++ branches/transforms/lib/matplotlib/image.py	2007年10月24日 19:22:00 UTC (rev 3997)
@@ -156,8 +156,8 @@
 im.apply_translation(-1, -1)
 
 # the viewport translation
- tx = (xmin-self.axes.viewLim.xmin)/dxintv * numcols
- ty = (ymin-self.axes.viewLim.ymin)/dyintv * numrows
+ tx = (xmin-self.axes.viewLim.x0)/dxintv * numcols
+ ty = (ymin-self.axes.viewLim.y0)/dyintv * numrows
 
 l, b, widthDisplay, heightDisplay = self.axes.bbox.bounds
 widthDisplay *= magnification
Modified: branches/transforms/lib/matplotlib/legend.py
===================================================================
--- branches/transforms/lib/matplotlib/legend.py	2007年10月24日 18:49:08 UTC (rev 3996)
+++ branches/transforms/lib/matplotlib/legend.py	2007年10月24日 19:22:00 UTC (rev 3997)
@@ -442,7 +442,7 @@
 
 candidates = []
 for l, b in consider:
- legendBox = Bbox.from_lbwh(l, b, width, height)
+ legendBox = Bbox.from_bounds(l, b, width, height)
 badness = 0
 badness = legendBox.count_contains(verts)
 badness += legendBox.count_overlaps(bboxes)
Modified: branches/transforms/lib/matplotlib/lines.py
===================================================================
--- branches/transforms/lib/matplotlib/lines.py	2007年10月24日 18:49:08 UTC (rev 3996)
+++ branches/transforms/lib/matplotlib/lines.py	2007年10月24日 19:22:00 UTC (rev 3997)
@@ -673,39 +673,6 @@
 gc.set_linestyle('solid')
 	renderer.draw_path(gc, path, trans)
 
-
- def _step(self, x, y, where):
- if not cbook.iterable(x):
- x = ma.array([x], dtype=npy.float_)
- if not cbook.iterable(y):
- y = ma.array([y], dtype=npy.float_)
-
- if where=='pre':
- x2 = ma.zeros((2*len(x)-1,), npy.float_)
- y2 = ma.zeros((2*len(y)-1,), npy.float_)
-
- x2[0::2], x2[1::2] = x, x[:-1]
- y2[0::2], y2[1:-1:2] = y, y[1:]
-
- elif where=='post':
- x2 = ma.zeros((2*len(x)-1,), npy.float_)
- y2 = ma.zeros((2*len(y)-1,), npy.float_)
-
- x2[::2], x2[1:-1:2] = x, x[1:]
- y2[0::2], y2[1::2] = y, y[:-1]
-
- elif where=='mid':
- x2 = ma.zeros((2*len(x),), npy.float_)
- y2 = ma.zeros((2*len(y),), npy.float_)
-
- x2[1:-1:2] = 0.5*(x[:-1]+x[1:])
- x2[2::2] = 0.5*(x[:-1]+x[1:])
- x2[0], x2[-1] = x[0], x[-1]
-
- y2[0::2], y2[1::2] = y, y
-
- return x2, y2
-
 
 def _draw_steps_pre(self, renderer, gc, path, trans):
 vertices = self._xy
Modified: branches/transforms/lib/matplotlib/patches.py
===================================================================
--- branches/transforms/lib/matplotlib/patches.py	2007年10月24日 18:49:08 UTC (rev 3996)
+++ branches/transforms/lib/matplotlib/patches.py	2007年10月24日 19:22:00 UTC (rev 3997)
@@ -346,7 +346,7 @@
 
 left, right = self.convert_xunits((xy[0], xy[0] + width))
 bottom, top = self.convert_yunits((xy[1], xy[1] + height))
-	self._bbox = transforms.Bbox.from_lbrt(left, bottom, right, top)
+	self._bbox = transforms.Bbox.from_extents(left, bottom, right, top)
 	self._rect_transform = transforms.BboxTransform(
 	 transforms.Bbox.unit(), self._bbox)
 __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd
@@ -367,11 +367,11 @@
 
 def get_x(self):
 "Return the left coord of the rectangle"
- return self._bbox.xmin
+ return self._bbox.x0
 
 def get_y(self):
 "Return the bottom coord of the rectangle"
- return self._bbox.ymin
+ return self._bbox.y0
 
 def get_width(self):
 "Return the width of the rectangle"
@@ -405,7 +405,7 @@
 
 ACCEPTS: float
 """
- self._bbox.xmax = self._bbox.xmin + w
+ self._bbox.x1 = self._bbox.x0 + w
 
 def set_height(self, h):
 """
@@ -413,7 +413,7 @@
 
 ACCEPTS: float
 """
- self._bbox.ymax = self._bbox.ymin + h
+ self._bbox.y1 = self._bbox.y0 + h
 
 def set_bounds(self, *args):
 """
Modified: branches/transforms/lib/matplotlib/path.py
===================================================================
--- branches/transforms/lib/matplotlib/path.py	2007年10月24日 18:49:08 UTC (rev 3996)
+++ branches/transforms/lib/matplotlib/path.py	2007年10月24日 19:22:00 UTC (rev 3997)
@@ -10,7 +10,8 @@
 from numpy import ma as ma
 
 from matplotlib._path import point_in_path, get_path_extents, \
- get_path_collection_extents, point_in_path_collection
+ point_in_path_collection
+import matplotlib._path as _path
 from matplotlib.cbook import simple_linear_interpolation
 
 KAPPA = 4.0 * (npy.sqrt(2) - 1) / 3.0
@@ -199,7 +200,7 @@
 from transforms import Affine2D, Bbox
 if transform is None:
 transform = Affine2D()
- return Bbox.from_lbrt(*get_path_extents(self, transform))
+ return Bbox.from_extents(*get_path_extents(self, transform))
 
 def interpolated(self, steps):
 """
@@ -402,3 +403,6 @@
 """
 return cls.arc(theta1, theta2, True)
 wedge = classmethod(wedge)
+
+def get_path_collection_extents(*args):
+ return Bbox.from_extents(*_path.get_path_collection_extents(*args))
Modified: branches/transforms/lib/matplotlib/projections/polar.py
===================================================================
--- branches/transforms/lib/matplotlib/projections/polar.py	2007年10月24日 18:49:08 UTC (rev 3996)
+++ branches/transforms/lib/matplotlib/projections/polar.py	2007年10月24日 19:22:00 UTC (rev 3997)
@@ -256,7 +256,7 @@
 return Circle((0.5, 0.5), 0.5)
 
 def set_rmax(self, rmax):
- self.viewLim.ymax = rmax
+ self.viewLim.y1 = rmax
 angle = self._r_label1_position.to_values()[4]
 self._r_label1_position.clear().translate(
 angle, rmax * self._rpad)
Modified: branches/transforms/lib/matplotlib/text.py
===================================================================
--- branches/transforms/lib/matplotlib/text.py	2007年10月24日 18:49:08 UTC (rev 3996)
+++ branches/transforms/lib/matplotlib/text.py	2007年10月24日 19:22:00 UTC (rev 3997)
@@ -253,7 +253,7 @@
 xmin -= offsetx
 ymin -= offsety
 
- bbox = Bbox.from_lbwh(xmin, ymin, width, height)
+ bbox = Bbox.from_bounds(xmin, ymin, width, height)
 
 # now rotate the positions around the first x,y position
 xys = M.transform(offsetLayout)
@@ -407,7 +407,7 @@
 if not self.get_visible(): return Bbox.unit()
 if self._text == '':
 tx, ty = self._get_xy_display()
- return Bbox.from_lbwh(tx,ty,0,0)
+ return Bbox.from_bounds(tx,ty,0,0)
 
 if renderer is not None:
 self._renderer = renderer
Modified: branches/transforms/lib/matplotlib/transforms.py
===================================================================
--- branches/transforms/lib/matplotlib/transforms.py	2007年10月24日 18:49:08 UTC (rev 3996)
+++ branches/transforms/lib/matplotlib/transforms.py	2007年10月24日 19:22:00 UTC (rev 3997)
@@ -196,28 +196,46 @@
 def __array__(self, *args, **kwargs):
 return self.get_points()
 
+ def _get_x0(self):
+ return self.get_points()[0, 0]
+ x0 = property(_get_x0)
+ 
+ def _get_y0(self):
+ return self.get_points()[0, 1]
+ y0 = property(_get_y0)
+
+ def _get_x1(self):
+ return self.get_points()[1, 0]
+ x1 = property(_get_x1)
+
+ def _get_y1(self):
+ return self.get_points()[1, 1]
+ y1 = property(_get_y1)
+
 def _get_xmin(self):
- return self.get_points()[0, 0]
+ return min(self.get_points()[:, 0])
 xmin = property(_get_xmin)
- 
+
 def _get_ymin(self):
- return self.get_points()[0, 1]
+ return min(self.get_points()[:, 1])
 ymin = property(_get_ymin)
 
 def _get_xmax(self):
- return self.get_points()[1, 0]
+ return max(self.get_points()[:, 0])
 xmax = property(_get_xmax)
 
 def _get_ymax(self):
- return self.get_points()[1, 1]
+ return max(self.get_points()[:, 1])
 ymax = property(_get_ymax)
-
+ 
 def _get_min(self):
- return self.get_points()[0]
+ return [min(self.get_points()[:, 0]),
+ min(self.get_points()[:, 1])]
 min = property(_get_min)
 
 def _get_max(self):
- return self.get_points()[1]
+ return [max(self.get_points()[:, 0]),
+ max(self.get_points()[:, 1])]
 max = property(_get_max)
 
 def _get_intervalx(self):
@@ -244,35 +262,35 @@
 size = property(_get_size)
 
 def _get_bounds(self):
- ((xmin, ymin), (xmax, ymax)) = self.get_points()
- return (xmin, ymin, xmax - xmin, ymax - ymin)
+ ((x0, y0), (x1, y1)) = self.get_points()
+ return (x0, y0, x1 - x0, y1 - y0)
 bounds = property(_get_bounds)
 
- def _get_lbrt(self):
+ def _get_extents(self):
 return self.get_points().flatten().copy()
- lbrt = property(_get_lbrt)
+ extents = property(_get_extents)
 
 def get_points(self):
 return NotImplementedError()
 
 def containsx(self, x):
- xmin, xmax = self.intervalx
- return ((xmin < xmax
- and (x >= xmin and x <= xmax))
- or (x >= xmax and x <= xmin))
+ x0, x1 = self.intervalx
+ return ((x0 < x1
+ and (x >= x0 and x <= x1))
+ or (x >= x1 and x <= x0))
 
 def containsy(self, y):
- ymin, ymax = self.intervaly
- return ((ymin < ymax
- and (y >= ymin and y <= ymax))
- or (y >= ymax and y <= ymin))
+ y0, y1 = self.intervaly
+ return ((y0 < y1
+ and (y >= y0 and y <= y1))
+ or (y >= y1 and y <= y0))
 
 def contains(self, x, y):
 return self.containsx(x) and self.containsy(y)
 
 def overlaps(self, other):
- ax1, ay1, ax2, ay2 = self._get_lbrt()
- bx1, by1, bx2, by2 = other._get_lbrt()
+ ax1, ay1, ax2, ay2 = self._get_extents()
+ bx1, by1, bx2, by2 = other._get_extents()
 
 if ax2 < ax1:
 ax2, ax1 = ax1, ax2
@@ -289,24 +307,24 @@
 (by1 > ay2))
 
 def fully_containsx(self, x):
- xmin, xmax = self.intervalx
- return ((xmin < xmax
- and (x > xmin and x < xmax))
- or (x > xmax and x < xmin))
+ x0, x1 = self.intervalx
+ return ((x0 < x1
+ and (x > x0 and x < x1))
+ or (x > x1 and x < x0))
 
 def fully_containsy(self, y):
- ymin, ymax = self.intervaly
- return ((ymin < ymax
- and (x > ymin and x < ymax))
- or (x > ymax and x < ymin))
+ y0, y1 = self.intervaly
+ return ((y0 < y1
+ and (x > y0 and x < y1))
+ or (x > y1 and x < y0))
 
 def fully_contains(self, x, y):
 return self.fully_containsx(x) \
 and self.fully_containsy(y)
 
 def fully_overlaps(self, other):
- ax1, ay1, ax2, ay2 = self._get_lbrt()
- bx1, by1, bx2, by2 = other._get_lbrt()
+ ax1, ay1, ax2, ay2 = self._get_extents()
+ bx1, by1, bx2, by2 = other._get_extents()
 
 if ax2 < ax1:
 ax2, ax1 = ax1, ax2
@@ -354,7 +372,7 @@
 or b) a string: C for centered, S for bottom-center, SE for
 bottom-left, E for left, etc.
 
- Optional arg container is the lbwh box within which the BBox
+ Optional arg container is the box within which the BBox
 is positioned; it defaults to the initial BBox.
 """
 if container is None:
@@ -413,10 +431,10 @@
 """
 boxes = []
 xf = [0] + list(args) + [1]
- l, b, r, t = self.lbrt
- w = r - l
+ x0, y0, x1, y1 = self._get_extents()
+ w = x1 - x0
 for xf0, xf1 in zip(xf[:-1], xf[1:]):
- boxes.append(Bbox([[l + xf0 * w, b], [l + xf1 * w, t]]))
+ boxes.append(Bbox([[x0 + xf0 * w, y0], [x0 + xf1 * w, y1]]))
 return boxes
 
 def splity(self, *args):
@@ -429,10 +447,10 @@
 """
 boxes = []
 yf = [0] + list(args) + [1]
- l, b, r, t = self.lbrt
- h = t - b
+ x0, y0, x1, y1 = self._get_extents()
+ h = y1 - y0
 for yf0, yf1 in zip(yf[:-1], yf[1:]):
- boxes.append(Bbox([[l, b + yf0 * h], [r, b + yf1 * h]]))
+ boxes.append(Bbox([[x0, y0 + yf0 * h], [x1, y0 + yf1 * h]]))
 return boxes
 
 def count_contains(self, vertices):
@@ -444,12 +462,12 @@
 if len(vertices) == 0:
 return 0
 vertices = npy.asarray(vertices)
- xmin, ymin, xmax, ymax = self._get_lbrt()
- dxmin = npy.sign(vertices[:, 0] - xmin)
- dymin = npy.sign(vertices[:, 1] - ymin)
- dxmax = npy.sign(vertices[:, 0] - xmax)
- dymax = npy.sign(vertices[:, 1] - ymax)
- inside = (abs(dxmin + dxmax) + abs(dymin + dymax)) <= 2
+ x0, y0, x1, y1 = self._get_extents()
+ dx0 = npy.sign(vertices[:, 0] - x0)
+ dy0 = npy.sign(vertices[:, 1] - y0)
+ dx1 = npy.sign(vertices[:, 0] - x1)
+ dy1 = npy.sign(vertices[:, 1] - y1)
+ inside = (abs(dx0 + dx1) + abs(dy0 + dy1)) <= 2
 return N.sum(inside)
 
 def count_overlaps(self, bboxes):
@@ -458,7 +476,7 @@
 
 bboxes is a sequence of Bbox objects
 """
- ax1, ay1, ax2, ay2 = self._get_lbrt()
+ ax1, ay1, ax2, ay2 = self._get_extents()
 if ax2 < ax1:
 ax2, ax1 = ax1, ax2
 if ay2 < ay1:
@@ -466,7 +484,7 @@
 
 count = 0
 for bbox in bboxes:
- # bx1, by1, bx2, by2 = bbox._get_lbrt() ... inlined...
+ # bx1, by1, bx2, by2 = bbox._get_extents() ... inlined...
 bx1, by1, bx2, by2 = bbox.get_points().flatten()
 if bx2 < bx1:
 bx2, bx1 = bx1, bx2
@@ -534,21 +552,21 @@
 if len(bboxes) == 1:
 return bboxes[0]
 
- xmin = npy.inf
- ymin = npy.inf
- xmax = -npy.inf
- ymax = -npy.inf
+ x0 = npy.inf
+ y0 = npy.inf
+ x1 = -npy.inf
+ y1 = -npy.inf
 
 for bbox in bboxes:
 points = bbox.get_points()
 xs = points[:, 0]
 ys = points[:, 1]
- xmin = min(xmin, npy.min(xs))
- ymin = min(ymin, npy.min(ys))
- xmax = max(xmax, npy.max(xs))
- ymax = max(ymax, npy.max(ys))
+ x0 = min(x0, npy.min(xs))
+ y0 = min(y0, npy.min(ys))
+ x1 = max(x1, npy.max(xs))
+ y1 = max(y1, npy.max(ys))
 
- return Bbox.from_lbrt(xmin, ymin, xmax, ymax)
+ return Bbox.from_extents(x0, y0, x1, y1)
 union = staticmethod(union)
 
 
@@ -557,10 +575,10 @@
 """
 Create a new bounding box.
 
- points: a 2x2 numpy array of the form [[xmin, ymin], [xmax, ymax]]
+ points: a 2x2 numpy array of the form [[x0, y0], [x1, y1]]
 
 If you need to create Bbox from another form of data, consider the
- class methods unit, from_lbwh and from_lbrt.
+ class methods unit, from_bounds and from_extents.
 """
 BboxBase.__init__(self)
 self._points = npy.asarray(points, npy.float_)
@@ -572,19 +590,19 @@
 """
 Create a new unit BBox from (0, 0) to (1, 1).
 """
- return Bbox.from_lbrt(0., 0., 1., 1.)
+ return Bbox.from_extents(0., 0., 1., 1.)
 unit = staticmethod(unit)
 
 #@staticmethod
- def from_lbwh(left, bottom, width, height):
+ def from_bounds(left, bottom, width, height):
 """
 Create a new Bbox from left, bottom, width and height.
 """
- return Bbox.from_lbrt(left, bottom, left + width, bottom + height)
- from_lbwh = staticmethod(from_lbwh)
+ return Bbox.from_extents(left, bottom, left + width, bottom + height)
+ from_bounds = staticmethod(from_bounds)
 
 #@staticmethod
- def from_lbrt(*args):
+ def from_extents(*args):
 """
 Create a new Bbox from left, bottom, right and top.
 
@@ -592,7 +610,7 @@
 """
 points = npy.array(args, dtype=npy.float_).reshape(2, 2)
 return Bbox(points)
- from_lbrt = staticmethod(from_lbrt)
+ from_extents = staticmethod(from_extents)
 
 def __repr__(self):
 return 'Bbox(%s)' % repr(self._points)
@@ -648,11 +666,12 @@
 npy.float_)
 self._minpos = minpos
 else:
+ x0, y0, x1, y1 = self._get_extents()
 	 points = npy.array(
-		[[min(x.min(), self.xmin),
- min(y.min(), self.ymin)],
-		 [max(x.max(), self.xmax),
- max(y.max(), self.ymax)]],
+		[[min(x.min(), x0, x1),
+ min(y.min(), y0, y1)],
+		 [max(x.max(), x0, x1),
+ max(y.max(), y0, y1)]],
 		 npy.float_)
 self._minpos = npy.minimum(minpos, self._minpos)
 
@@ -672,25 +691,25 @@
 """
 return self.update_from_data(xy[:, 0], xy[:, 1], ignore)
 
- def _set_xmin(self, val):
+ def _set_x0(self, val):
 self._points[0, 0] = val
 self.invalidate()
- xmin = property(BboxBase._get_xmin, _set_xmin)
+ x0 = property(BboxBase._get_x0, _set_x0)
 
- def _set_ymin(self, val):
+ def _set_y0(self, val):
 self._points[0, 1] = val
 self.invalidate()
- ymin = property(BboxBase._get_ymin, _set_ymin)
+ y0 = property(BboxBase._get_y0, _set_y0)
 
- def _set_xmax(self, val):
+ def _set_x1(self, val):
 self._points[1, 0] = val
 self.invalidate()
- xmax = property(BboxBase._get_xmax, _set_xmax)
+ x1 = property(BboxBase._get_x1, _set_x1)
 
- def _set_ymax(self, val):
+ def _set_y1(self, val):
 self._points[1, 1] = val
 self.invalidate()
- ymax = property(BboxBase._get_ymax, _set_ymax)
+ y1 = property(BboxBase._get_y1, _set_y1)
 
 def _set_min(self, val):
 self._points[0] = val
@@ -735,7 +754,7 @@
 def get_points(self):
 """
 Set the points of the bounding box directly as a numpy array
- of the form: [[xmin, ymin], [xmax, ymax]].
+ of the form: [[x0, y0], [x1, y1]].
 """
 self._invalid = 0
 return self._points
@@ -743,7 +762,7 @@
 def set_points(self, points):
 """
 Set the points of the bounding box directly from a numpy array
- of the form: [[xmin, ymin], [xmax, ymax]]. No error checking
+ of the form: [[x0, y0], [x1, y1]]. No error checking
 is performed, as this method is mainly for internal use.
 """
 if npy.any(self._points != points):
@@ -2137,11 +2156,11 @@
 from random import random
 import timeit
 
- bbox = Bbox.from_lbrt(10., 15., 20., 25.)
- assert bbox.xmin == 10
- assert bbox.ymin == 15
- assert bbox.xmax == 20
- assert bbox.ymax == 25
+ bbox = Bbox.from_extents(10., 15., 20., 25.)
+ assert bbox.x0 == 10
+ assert bbox.y0 == 15
+ assert bbox.x1 == 20
+ assert bbox.y1 == 25
 
 assert npy.all(bbox.min == [10, 15])
 assert npy.all(bbox.max == [20, 25])
@@ -2160,18 +2179,18 @@
 
 assert bbox.bounds == (11, 16, 10, 10)
 
- bbox.xmin = 12
- bbox.ymin = 17
- bbox.xmax = 22
- bbox.ymax = 27
+ bbox.x0 = 12
+ bbox.y0 = 17
+ bbox.x1 = 22
+ bbox.y1 = 27
 
 assert bbox.bounds == (12, 17, 10, 10)
 
- bbox = Bbox.from_lbwh(10, 11, 12, 13)
+ bbox = Bbox.from_bounds(10, 11, 12, 13)
 assert bbox.bounds == (10, 11, 12, 13)
 
 bbox_copy = copy.deepcopy(bbox)
- assert (bbox.lbrt == bbox_copy.lbrt).all()
+ assert (bbox.extents == bbox_copy.extents).all()
 bbox_copy.max = (14, 15)
 assert bbox.bounds == (10, 11, 12, 13)
 assert bbox_copy.bounds == (10, 11, 4, 4)
@@ -2180,7 +2199,7 @@
 bbox2 = Bbox([[30., 35.], [40., 45.]])
 trans = BboxTransform(bbox1, bbox2)
 bbox3 = bbox1.transformed(trans)
- assert (bbox3.lbrt == bbox2.lbrt).all()
+ assert (bbox3.extents == bbox2.extents).all()
 
 translation = Affine2D().translate(10, 20)
 assert translation.to_values() == (1, 0, 0, 1, 10, 20)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
1 2 > >> (Page 1 of 2)
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 によって変換されたページ (->オリジナル) /