You can subscribe to this list here.
2007 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
(115) |
Aug
(120) |
Sep
(137) |
Oct
(170) |
Nov
(461) |
Dec
(263) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2008 |
Jan
(120) |
Feb
(74) |
Mar
(35) |
Apr
(74) |
May
(245) |
Jun
(356) |
Jul
(240) |
Aug
(115) |
Sep
(78) |
Oct
(225) |
Nov
(98) |
Dec
(271) |
2009 |
Jan
(132) |
Feb
(84) |
Mar
(74) |
Apr
(56) |
May
(90) |
Jun
(79) |
Jul
(83) |
Aug
(296) |
Sep
(214) |
Oct
(76) |
Nov
(82) |
Dec
(66) |
2010 |
Jan
(46) |
Feb
(58) |
Mar
(51) |
Apr
(77) |
May
(58) |
Jun
(126) |
Jul
(128) |
Aug
(64) |
Sep
(50) |
Oct
(44) |
Nov
(48) |
Dec
(54) |
2011 |
Jan
(68) |
Feb
(52) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(1) |
2018 |
Jan
|
Feb
|
Mar
|
Apr
|
May
(1) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: <jr...@us...> - 2007-10-03 23:05:32
|
Revision: 3911 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3911&view=rev Author: jrevans Date: 2007-10-03 16:05:30 -0700 (Wed, 03 Oct 2007) Log Message: ----------- Removed an erroneous print statment in backend_qt.py. Added a feature to keep track of axes inversions. Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/axes.py trunk/matplotlib/lib/matplotlib/backends/backend_qt.py Modified: trunk/matplotlib/lib/matplotlib/axes.py =================================================================== --- trunk/matplotlib/lib/matplotlib/axes.py 2007-10-03 22:23:48 UTC (rev 3910) +++ trunk/matplotlib/lib/matplotlib/axes.py 2007-10-03 23:05:30 UTC (rev 3911) @@ -503,6 +503,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() @@ -1500,10 +1503,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_bounds() + """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().get_bounds() + if ( self._invertedx ): + return bound2, bound1 + else: + return bound1, bound2 def set_xlim(self, xmin=None, xmax=None, emit=True, **kwargs): """ @@ -1542,12 +1560,25 @@ if xmin is None: xmin = old_xmin if xmax is None: xmax = old_xmax + # 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 ) + 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) - self.viewLim.intervalx().set_bounds(xmin, xmax) + if ( self._invertedx ): + xmax, xmin = mtrans.nonsingular(xmax, xmin, increasing=False) + self.viewLim.intervalx().set_bounds(xmax, xmin) + else: + xmin, xmax = mtrans.nonsingular(xmin, xmax, increasing=False) + self.viewLim.intervalx().set_bounds(xmin, xmax) + if emit: self.callbacks.process('xlim_changed', self) return xmin, xmax @@ -1623,10 +1654,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_bounds() + """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().get_bounds() + 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): @@ -1649,7 +1696,6 @@ ACCEPTS: len(2) sequence of floats """ - if ymax is None and iterable(ymin): ymin,ymax = ymin @@ -1663,12 +1709,25 @@ if ymin is None: ymin = old_ymin if ymax is None: ymax = old_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.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) - self.viewLim.intervaly().set_bounds(ymin, ymax) + if ( self._invertedy ): + ymax, ymin = mtrans.nonsingular(ymax, ymin, increasing=False) + self.viewLim.intervaly().set_bounds(ymax, ymin) + else: + ymin, ymax = mtrans.nonsingular(ymin, ymax, increasing=False) + self.viewLim.intervaly().set_bounds(ymin, ymax) + if emit: self.callbacks.process('ylim_changed', self) return ymin, ymax Modified: trunk/matplotlib/lib/matplotlib/backends/backend_qt.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_qt.py 2007-10-03 22:23:48 UTC (rev 3910) +++ trunk/matplotlib/lib/matplotlib/backends/backend_qt.py 2007-10-03 23:05:30 UTC (rev 3911) @@ -135,7 +135,6 @@ def resizeEvent( self, event ): if DEBUG: print 'resize (%d x %d)' % (event.size().width(), event.size().height()) - print "JRE--DBG: qt : resizeEvent" qt.QWidget.resizeEvent( self, event ) w = event.size().width() h = event.size().height() @@ -147,7 +146,6 @@ self.draw() def resize( self, w, h ): - print "JRE--DBG: qt : resize" # Pass through to Qt to resize the widget. qt.QWidget.resize( self, w, h ) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jr...@us...> - 2007-10-03 22:23:50
|
Revision: 3910 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3910&view=rev Author: jrevans Date: 2007-10-03 15:23:48 -0700 (Wed, 03 Oct 2007) Log Message: ----------- Moved a couple of routines from the Agg version of the FigureCanvas to the base qt version where they belong. Added a couple of overloaded qt methods that should be there and reduce having to inherit when embedding in another QWidget. Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/backends/backend_qt.py trunk/matplotlib/lib/matplotlib/backends/backend_qt4.py trunk/matplotlib/lib/matplotlib/backends/backend_qt4agg.py trunk/matplotlib/lib/matplotlib/backends/backend_qtagg.py Modified: trunk/matplotlib/lib/matplotlib/backends/backend_qt.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_qt.py 2007-10-03 12:51:16 UTC (rev 3909) +++ trunk/matplotlib/lib/matplotlib/backends/backend_qt.py 2007-10-03 22:23:48 UTC (rev 3910) @@ -135,11 +135,38 @@ def resizeEvent( self, event ): if DEBUG: print 'resize (%d x %d)' % (event.size().width(), event.size().height()) + print "JRE--DBG: qt : resizeEvent" 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 ): + print "JRE--DBG: qt : resize" + # 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: trunk/matplotlib/lib/matplotlib/backends/backend_qt4.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_qt4.py 2007-10-03 12:51:16 UTC (rev 3909) +++ trunk/matplotlib/lib/matplotlib/backends/backend_qt4.py 2007-10-03 22:23:48 UTC (rev 3910) @@ -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: trunk/matplotlib/lib/matplotlib/backends/backend_qt4agg.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_qt4agg.py 2007-10-03 12:51:16 UTC (rev 3909) +++ trunk/matplotlib/lib/matplotlib/backends/backend_qt4agg.py 2007-10-03 22:23:48 UTC (rev 3910) @@ -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: trunk/matplotlib/lib/matplotlib/backends/backend_qtagg.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_qtagg.py 2007-10-03 12:51:16 UTC (rev 3909) +++ trunk/matplotlib/lib/matplotlib/backends/backend_qtagg.py 2007-10-03 22:23:48 UTC (rev 3910) @@ -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 This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-10-03 12:51:20
|
Revision: 3909 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3909&view=rev Author: mdboom Date: 2007-10-03 05:51:16 -0700 (Wed, 03 Oct 2007) Log Message: ----------- Merged revisions 3906-3908 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r3907 | efiring | 2007-10-02 04:30:29 -0400 (Tue, 02 Oct 2007) | 2 lines matplotlib.use() raises an exception if called too late ........ Modified Paths: -------------- branches/transforms/CHANGELOG branches/transforms/lib/matplotlib/__init__.py Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-3905 + /trunk/matplotlib:1-3908 Modified: branches/transforms/CHANGELOG =================================================================== --- branches/transforms/CHANGELOG 2007-10-03 12:50:04 UTC (rev 3908) +++ branches/transforms/CHANGELOG 2007-10-03 12:51:16 UTC (rev 3909) @@ -1,3 +1,6 @@ +2007-10-01 Made matplotlib.use() raise an exception if called after + backends has been imported. + 2007-09-30 Modified update* methods of Bbox and Interval so they work with reversed axes. Prior to this, trying to set the ticks on a reversed axis failed with an Modified: branches/transforms/lib/matplotlib/__init__.py =================================================================== --- branches/transforms/lib/matplotlib/__init__.py 2007-10-03 12:50:04 UTC (rev 3908) +++ branches/transforms/lib/matplotlib/__init__.py 2007-10-03 12:51:16 UTC (rev 3909) @@ -716,6 +716,9 @@ except: from config import rcParams, rcdefaults +_use_error_msg = """ matplotlib.use() must be called *before* pylab +or matplotlib.backends is imported for the first time.""" + def use(arg): """ Set the matplotlib backend to one of the known backends. @@ -732,6 +735,8 @@ for the first time; or, if you are not using pylab, it must be called before importing matplotlib.backends. """ + if 'matplotlib.backends' in sys.modules: + raise RuntimeError(_use_error_msg) be_parts = arg.split('.') name = validate_backend(be_parts[0]) rcParams['backend'] = name This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-10-03 12:50:11
|
Revision: 3908 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3908&view=rev Author: mdboom Date: 2007-10-03 05:50:04 -0700 (Wed, 03 Oct 2007) Log Message: ----------- Lots of progress on Polar transform refactoring. Added point_in_path algorithm. Modified Paths: -------------- 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/cbook.py branches/transforms/lib/matplotlib/figure.py branches/transforms/lib/matplotlib/patches.py branches/transforms/lib/matplotlib/path.py branches/transforms/lib/matplotlib/scale.py branches/transforms/lib/matplotlib/text.py branches/transforms/lib/matplotlib/ticker.py branches/transforms/lib/matplotlib/transforms.py branches/transforms/setup.py branches/transforms/src/_backend_agg.cpp branches/transforms/src/_backend_agg.h Added Paths: ----------- branches/transforms/lib/matplotlib/projections/ branches/transforms/lib/matplotlib/projections/polar.py Removed Paths: ------------- branches/transforms/lib/matplotlib/pbox.py Modified: branches/transforms/lib/matplotlib/artist.py =================================================================== --- branches/transforms/lib/matplotlib/artist.py 2007-10-02 08:30:29 UTC (rev 3907) +++ branches/transforms/lib/matplotlib/artist.py 2007-10-03 12:50:04 UTC (rev 3908) @@ -1,7 +1,8 @@ from __future__ import division import sys, re from cbook import iterable, flatten -from transforms import Affine2D +from transforms import Affine2D, Bbox, IdentityTransform, TransformedBbox, \ + TransformedPath import matplotlib.units as units ## Note, matplotlib artists use the doc strings for set and get @@ -145,7 +146,7 @@ def get_transform(self): 'return the Transformation instance used by this artist' if self._transform is None: - self._transform = Affine2D() + self._transform = IdentityTransform() return self._transform def hitlist(self,event): @@ -284,17 +285,29 @@ self._clipon = clipbox is not None or self._clippath is not None self.pchanged() - def set_clip_path(self, path): + def set_clip_path(self, path, transform=None): """ Set the artist's clip path - ACCEPTS: an agg.path_storage instance + ACCEPTS: a Path instance and a Transform instance, or a Patch instance """ - self._clippath = path + from patches import Patch, Rectangle + if transform is None: + if isinstance(path, Rectangle): + self.clipbox = TransformedBbox(Bbox.unit(), path.get_transform()) + elif isinstance(path, Patch): + self._clippath = TransformedPath( + path.get_path(), + path.get_transform()) + elif path is None: + self._clippath = None + else: + raise TypeError("Invalid arguments to set_clip_path") + else: + self._clippath = TransformedPath(path, transform) self._clipon = self.clipbox is not None or path is not None self.pchanged() - def get_alpha(self): """ Return the alpha value used for blending - not supported on all @@ -431,6 +444,7 @@ self._alpha = other._alpha self.clipbox = other.clipbox self._clipon = other._clipon + self._clippath = other._clippath self._lod = other._lod self._label = other._label self.pchanged() Modified: branches/transforms/lib/matplotlib/axes.py =================================================================== --- branches/transforms/lib/matplotlib/axes.py 2007-10-02 08:30:29 UTC (rev 3907) +++ branches/transforms/lib/matplotlib/axes.py 2007-10-03 12:50:04 UTC (rev 3908) @@ -1,5 +1,5 @@ from __future__ import division, generators -import math, sys, warnings, copy +import math, sys, warnings, copy, new import numpy as npy @@ -24,7 +24,6 @@ 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 from matplotlib import table as mtable @@ -428,15 +427,8 @@ """ - - # MGDTODO -# scaled = {mtrans.IDENTITY : 'linear', -# mtrans.LOG10 : 'log', -# } - scaled = {0 : 'linear', - 1 : 'log', - } - + name = "rectilinear" + _shared_x_axes = cbook.Grouper() _shared_y_axes = cbook.Grouper() @@ -474,16 +466,16 @@ visible: a boolean - whether the axes is visible xlabel: the xlabel xlim: (xmin, xmax) view limits - xscale: ['log' | 'linear' ] + xscale: [%(scale)s] xticklabels: sequence of strings xticks: sequence of floats ylabel: the ylabel strings ylim: (ymin, ymax) view limits - yscale: ['log' | 'linear'] + yscale: [%(scale)s] yticklabels: sequence of strings yticks: sequence of floats - """ + """ % {'scale': ' | '.join([repr(x) for x in mscale.get_scale_names()])} martist.Artist.__init__(self) self._position = mtransforms.Bbox.from_lbwh(*rect) self._originalPosition = copy.deepcopy(self._position) @@ -637,6 +629,10 @@ # It is assumed that this part will have non-linear components self.transScale = mtransforms.TransformWrapper(mtransforms.IdentityTransform()) + self._set_transData() + + # MGDTODO: Rename this method + def _set_transData(self): # A (possibly non-linear) projection on the (already scaled) data self.transProjection = mtransforms.IdentityTransform() @@ -647,7 +643,33 @@ self.transData = self.transScale + self.transProjection + self.transLimits + self.transAxes + self._xaxis_transform = mtransforms.blended_transform_factory( + self.axes.transData, self.axes.transAxes) + self._yaxis_transform = mtransforms.blended_transform_factory( + self.axes.transAxes, self.axes.transData) + def get_xaxis_transform(self): + return self._xaxis_transform + + def get_xaxis_text1_transform(self, pad_pixels): + return (self._xaxis_transform + + mtransforms.Affine2D().translate(0, -1 * pad_pixels)) + + def get_xaxis_text2_transform(self, pad_pixels): + return (self._xaxis_transform + + mtransforms.Affine2D().translate(0, pad_pixels)) + + def get_yaxis_transform(self): + return self._yaxis_transform + + def get_yaxis_text1_transform(self, pad_pixels): + return (self._yaxis_transform + + mtransforms.Affine2D().translate(-1 * pad_pixels, 0)) + + def get_yaxis_text2_transform(self, pad_pixels): + return (self._yaxis_transform + + mtransforms.Affine2D().translate(pad_pixels, 0)) + def _update_transScale(self): self.transScale.set( mtransforms.blended_transform_factory( @@ -691,6 +713,9 @@ a.set_transform(self.transData) a.axes = self + def get_axes_patch(self): + return mpatches.Rectangle((0.0, 0.0), 1.0, 1.0) + def cla(self): 'Clear the current axes' @@ -734,24 +759,26 @@ self.title.set_clip_box(None) self._set_artist_props(self.title) - - self.axesPatch = mpatches.Rectangle( - xy=(0,0), width=1, height=1, - facecolor=self._axisbg, - edgecolor=rcParams['axes.edgecolor'], - ) + + self.axesPatch = self.get_axes_patch() self.axesPatch.set_figure(self.figure) - self.axesPatch.set_transform(self.transAxes) + self.axesPatch.set_facecolor(self._axisbg) + self.axesPatch.set_edgecolor(rcParams['axes.edgecolor']) 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'], - figure=self.figure) + self.axesPatch.set_transform(self.transAxes) + + self.axesFrame = self.get_axes_patch() + self.axesFrame.set_figure(self.figure) + self.axesFrame.set_facecolor(None) + self.axesFrame.set_edgecolor(rcParams['axes.edgecolor']) + self.axesFrame.set_linewidth(rcParams['axes.linewidth']) self.axesFrame.set_transform(self.transAxes) self.axesFrame.set_zorder(2.5) self.axison = True + self.xaxis.set_clip_path(self.axesPatch) + self.yaxis.set_clip_path(self.axesPatch) + def clear(self): 'clear the axes' self.cla() @@ -838,19 +865,23 @@ """ ACCEPTS: ['C', 'SW', 'S', 'SE', 'E', 'NE', 'N', 'NW', 'W'] """ - if anchor in mpbox.PBox.coefs.keys() or len(anchor) == 2: + if anchor in mtransforms.Bbox.coefs.keys() or len(anchor) == 2: self._anchor = anchor else: raise ValueError('argument must be among %s' % - ', '.join(PBox.coefs.keys())) + ', '.join(mtransforms.BBox.coefs.keys())) - - def apply_aspect(self, data_ratio = None): + def get_data_ratio(self): + xmin,xmax = self.get_xlim() + xsize = max(math.fabs(xmax-xmin), 1e-30) + ymin,ymax = self.get_ylim() + ysize = max(math.fabs(ymax-ymin), 1e-30) + return ysize/xsize + + def apply_aspect(self): ''' Use self._aspect and self._adjustable to modify the axes box or the view limits. - The data_ratio kwarg is set to 1 for polar axes. It is - used only when _adjustable is 'box'. ''' if self._aspect == 'auto': @@ -869,18 +900,11 @@ figW,figH = self.get_figure().get_size_inches() fig_aspect = figH/figW - #print 'figW, figH, fig_aspect', figW, figH, fig_aspect - xmin,xmax = self.get_xlim() - xsize = max(math.fabs(xmax-xmin), 1e-30) - ymin,ymax = self.get_ylim() - ysize = max(math.fabs(ymax-ymin), 1e-30) if self._adjustable == 'box': - if data_ratio is None: - data_ratio = ysize/xsize - box_aspect = A * data_ratio - pb = mpbox.PBox(self._originalPosition) - pb1 = pb.shrink_to_aspect(box_aspect, fig_aspect) - self.set_position(pb1.anchor(self._anchor), 'active') + box_aspect = A * self.get_data_ratio() + pb = self._originalPosition.frozen() + pb1 = pb.shrunk_to_aspect(box_aspect, pb, fig_aspect) + self.set_position(pb1.anchored(self._anchor, pb), 'active') return @@ -1079,7 +1103,7 @@ collection.set_label('collection%d'%len(self.collections)) self.collections.append(collection) self._set_artist_props(collection) - collection.set_clip_box(self.bbox) + collection.set_clip_path(self.axesPatch) if autolim: self.update_datalim(collection.get_verts(self.transData)) collection._remove_method = lambda h: self.collections.remove(h) @@ -1087,7 +1111,7 @@ def add_line(self, line): 'Add a line to the list of plot lines' self._set_artist_props(line) - line.set_clip_box(self.bbox) + line.set_clip_path(self.axesPatch) self._update_line_limits(line) if not line.get_label(): @@ -1107,7 +1131,7 @@ """ self._set_artist_props(p) - p.set_clip_box(self.bbox) + p.set_clip_path(self.axesPatch) self._update_patch_limits(p) self.patches.append(p) p._remove_method = lambda h: self.patches.remove(h) @@ -1115,7 +1139,7 @@ def _update_patch_limits(self, p): 'update the datalimits for patch p' xys = self._get_verts_in_data_coords( - p.get_transform(), p.get_verts()) + p.get_transform(), p.get_path().vertices) self.update_datalim(xys) @@ -1160,8 +1184,8 @@ # display and then back to data to get it in data units #xys = trans.seq_xy_tups(xys) #return [ self.transData.inverse_xy_tup(xy) for xy in xys] - xys = trans(npy.asarray(xys)) - return self.transData.inverted()(xys) + xys = trans.transform(npy.asarray(xys)) + return self.transData.inverted().transform(xys) def _process_unit_info(self, xdata=None, ydata=None, kwargs=None): 'look for unit kwargs and update the axis instances as necessary' @@ -1189,9 +1213,9 @@ #print '\tkw setting yunits', yunits self.yaxis.set_units(yunits) - def in_axes(self, xwin, ywin): + def in_axes(self, mouseevent): 'return True is the point xwin, ywin (display coords) are in the Axes' - return self.bbox.contains(xwin, ywin) + return self.axesPatch.contains(mouseevent)[0] def get_autoscale_on(self): """ @@ -1207,7 +1231,6 @@ """ self._autoscaleon = b - def autoscale_view(self, tight=False, scalex=True, scaley=True): """ autoscale the view limits using the data limits. You can @@ -1239,8 +1262,8 @@ if yl[1] < yl[0]: YL = YL[::-1] self.set_ylim(YL) - #### Drawing + #### Drawing def draw(self, renderer=None, inframe=False): "Draw everything (plot lines, axes, labels)" if renderer is None: @@ -1252,7 +1275,9 @@ renderer.open_group('axes') self.apply_aspect() - if self.axison and self._frameon: self.axesPatch.draw(renderer) + if self.axison and self._frameon: + self.axesPatch.draw(renderer) + artists = [] if len(self.images)<=1 or renderer.option_image_nocomposite(): @@ -1262,7 +1287,6 @@ # make a composite image blending alpha # list of (mimage.Image, ox, oy) - mag = renderer.get_image_magnification() ims = [(im.make_image(mag),0,0) for im in self.images if im.get_visible()] @@ -1277,8 +1301,6 @@ # respect z-order for now renderer.draw_image(l, b, im, self.bbox) - - artists.extend(self.collections) artists.extend(self.patches) artists.extend(self.lines) @@ -1517,14 +1539,15 @@ return xmin, xmax def get_xscale(self): - 'return the xaxis scale string: log or linear' + 'return the xaxis scale string: %s' % ( + ", ".join(mscale.get_scale_names())) return self.xaxis.get_scale() def set_xscale(self, value, **kwargs): """ - SET_XSCALE(value, basex=10, subsx=None) + SET_XSCALE(value) - Set the xscaling: 'log' or 'linear' + Set the xscaling: %(scale)s If value is 'log', the additional kwargs have the following meaning @@ -1536,8 +1559,8 @@ put minor ticks on 1,2,5,11,12,15,21, ....To turn off minor ticking, set subsx=[] - ACCEPTS: ['log' | 'linear' ] - """ + ACCEPTS: [%(scale)s] + """ % {'scale': ' | '.join([repr(x) for x in mscale.get_scale_names()])} self.xaxis.set_scale(value, **kwargs) self._update_transScale() @@ -1610,11 +1633,6 @@ if ymin is None: ymin = old_ymin if ymax is None: ymax = old_ymax - # 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 = mtransforms.nonsingular(ymin, ymax, increasing=False) self.viewLim.intervaly = (ymin, ymax) if emit: @@ -1627,14 +1645,15 @@ return ymin, ymax def get_yscale(self): - 'return the yaxis scale string: log or linear' + 'return the xaxis scale string: %s' % ( + ", ".join(mscale.get_scale_names())) return self.yaxis.get_scale() def set_yscale(self, value, **kwargs): """ SET_YSCALE(value, basey=10, subsy=None) - Set the yscaling: 'log' or 'linear' + Set the yscaling: %(scale)s If value is 'log', the additional kwargs have the following meaning @@ -1646,8 +1665,8 @@ put minor ticks on 1,2,5,11,12,15, 21, ....To turn off minor ticking, set subsy=[] - ACCEPTS: ['log' | 'linear'] - """ + ACCEPTS: %(scale)s + """ % {'scale': ' | '.join([repr(x) for x in mscale.get_scale_names()])} self.yaxis.set_scale(value, **kwargs) self._update_transScale() @@ -1682,14 +1701,6 @@ return self.yaxis.set_ticklabels(labels, fontdict, **kwargs) set_yticklabels.__doc__ = cbook.dedent(set_yticklabels.__doc__) % martist.kwdocd - def toggle_log_lineary(self): - 'toggle between log and linear on the y axis' - # 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. @@ -1748,12 +1759,12 @@ def format_coord(self, x, y): 'return a format string formatting the x, y coord' - + if x is None or y is None: + return '' xs = self.format_xdata(x) ys = self.format_ydata(y) return 'x=%s, y=%s'%(xs,ys) - - + #### Interactive manipulation def get_navigate(self): @@ -1784,17 +1795,40 @@ """ self._navigate_mode = b - def drag_pan(self, button, x, y, startx, starty, start_lim, start_trans): + def drag_pan(self, button, key, startx, starty, dx, dy, + start_lim, start_trans): + def format_deltas(key, dx, dy): + if key=='control': + if(abs(dx)>abs(dy)): + dy = dx + else: + dx = dy + elif key=='x': + dy = 0 + elif key=='y': + dx = 0 + elif key=='shift': + if 2*abs(dx) < abs(dy): + dx=0 + elif 2*abs(dy) < abs(dx): + dy=0 + elif(abs(dx)>abs(dy)): + dy=dy/abs(dy)*abs(dx) + else: + dx=dx/abs(dx)*abs(dy) + return (dx,dy) + if button == 1: inverse = start_trans.inverted() - dx = startx - x - dy = starty - y - result = self.bbox.frozen().translated(dx, dy).transformed(inverse) + dx, dy = format_deltas(key, dx, dy) + result = self.bbox.frozen().translated(-dx, -dy).transformed(inverse) elif button == 3: try: + # MGDTODO: This is broken with log scales inverse = start_trans.inverted() - dx = (startx - x) / float(self.bbox.width) - dy = (starty - y) / float(self.bbox.height) + dx, dy = format_deltas(key, dx, dy) + dx = -dx / float(self.bbox.width) + dy = -dy / float(self.bbox.height) xmin, ymin, xmax, ymax = start_lim.lbrt alpha = npy.power(10.0, (dx, dy)) @@ -1806,7 +1840,6 @@ 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) @@ -1880,7 +1913,7 @@ """ if callable(self._contains): return self._contains(self,mouseevent) - inside = self.bbox.contains(mouseevent.x,mouseevent.y) + inside = self.axesPatch.contains(mouseevent.x, mouseevent.y) return inside,{} def pick(self,*args): @@ -2100,7 +2133,7 @@ #if t.get_clip_on(): t.set_clip_box(self.bbox) - if kwargs.has_key('clip_on'): t.set_clip_box(self.bbox) + if kwargs.has_key('clip_on'): t.set_clip_path(self.axesPatch) return t text.__doc__ = cbook.dedent(text.__doc__) % martist.kwdocd @@ -2118,7 +2151,7 @@ a = mtext.Annotation(*args, **kwargs) a.set_transform(mtransforms.Affine2D()) self._set_artist_props(a) - if kwargs.has_key('clip_on'): a.set_clip_box(self.bbox) + if kwargs.has_key('clip_on'): a.set_clip_path(self.axesPatch) self.texts.append(a) return a annotate.__doc__ = cbook.dedent(annotate.__doc__) % martist.kwdocd @@ -5056,7 +5089,7 @@ Subplot(211) # 2 rows, 1 column, first (upper) plot """ - def __init__(self, fig, *args): + def __init__(self, fig, *args, **kwargs): """ fig is a figure instance @@ -5087,6 +5120,10 @@ self.update_params() + # _axes_class is set in the subplot_class_factory + self._axes_class.__init__(self, fig, [self.figLeft, self.figBottom, + self.figW, self.figH], **kwargs) + def get_geometry(self): 'get the subplot geometry, eg 2,2,3' return self._rows, self._cols, self._num+1 @@ -5176,36 +5213,18 @@ for label in self.get_yticklabels(): label.set_visible(firstcol) -class Subplot(SubplotBase, Axes): - """ - Emulate matlab's(TM) subplot command, creating axes with +def subplot_class_factory(axes_class=None): + # MGDTODO: This is a little bit strange to make a new class on the + # fly like this, but it keeps things relatively similar to how they + # were before + new_class = new.classobj("%sSubplot" % (axes_class.__name__), + (SubplotBase, axes_class), + {'_axes_class': axes_class}) + return new_class - Subplot(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 "Subplot(%f,%f,%f,%f)" % (self.bbox.bounds) - - def __init__(self, fig, *args, **kwargs): - """ - See Axes base class documentation for args and kwargs - """ - SubplotBase.__init__(self, fig, *args) - Axes.__init__(self, fig, [self.figLeft, self.figBottom, - self.figW, self.figH], **kwargs) - - - class PolarAxes(Axes): """ - Make a PolarAxes. The rectangular bounding box of the axes is given by @@ -5644,11 +5663,6 @@ 'return the yaxis scale string' return 'polar' - def toggle_log_lineary(self): - 'toggle between log and linear axes ignored for polar' - pass - - def table(self, *args, **kwargs): """ TABLE(*args, **kwargs) @@ -5679,255 +5693,9 @@ PolarAxes.__init__( 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 # data point for some log scaling fixes. I realized there was a Modified: branches/transforms/lib/matplotlib/axis.py =================================================================== --- branches/transforms/lib/matplotlib/axis.py 2007-10-02 08:30:29 UTC (rev 3907) +++ branches/transforms/lib/matplotlib/axis.py 2007-10-03 12:50:04 UTC (rev 3908) @@ -18,12 +18,11 @@ 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, IntervalTransform + interval_contains_open, IntervalTransform, IdentityTransform from patches import bbox_artist from scale import scale_factory import matplotlib.units as units -#import pdb class Tick(Artist): @@ -112,6 +111,12 @@ children = [self.tick1line, self.tick2line, self.gridline, self.label1, self.label2] return children + def set_clip_path(self, clippath, transform=None): + Artist.set_clip_path(self, clippath, transform) + self.tick1line.set_clip_path(clippath, transform) + self.tick2line.set_clip_path(clippath, transform) + self.gridline.set_clip_path(clippath, transform) + def contains(self, mouseevent): """Test whether the mouse event occured in the Tick marks. @@ -164,9 +169,12 @@ midPoint = interval_contains_open(self.get_view_interval(), self.get_loc() ) if midPoint: - if self.gridOn: self.gridline.draw(renderer) - if self.tick1On: self.tick1line.draw(renderer) - if self.tick2On: self.tick2line.draw(renderer) + if self.gridOn: + self.gridline.draw(renderer) + if self.tick1On: + self.tick1line.draw(renderer) + if self.tick2On: + self.tick2line.draw(renderer) if self.label1On: self.label1.draw(renderer) if self.label2On: self.label2.draw(renderer) @@ -213,8 +221,10 @@ 'return the view Interval instance for the axis tjis tick is ticking' raise NotImplementedError('Derived must override') + def set_view_interval(self, vmin, vmax, ignore=False): + raise NotImplementedError('Derived must override') - + class XTick(Tick): """ Contains all the Artists needed to make an x tick - the tick line, @@ -237,12 +247,7 @@ xaxis=True, ) - trans = blended_transform_factory( - self.axes.transData, self.axes.transAxes) - #offset the text downward with a post transformation - trans = trans + Affine2D().translate(0, -1 * self._padPixels) - t.set_transform(trans) - + t.set_transform(self.axes.get_xaxis_text1_transform(self._padPixels)) self._set_artist_props(t) return t @@ -262,11 +267,7 @@ horizontalalignment='center', ) - trans = blended_transform_factory( - self.axes.transData, self.axes.transAxes) - # offset the text upward with a post transformation - trans = trans + Affine2D().translate(0, self._padPixels) - t.set_transform( trans ) + t.set_transform(self.axes.get_xaxis_text2_transform(self._padPixels)) self._set_artist_props(t) return t @@ -280,8 +281,7 @@ marker = self._xtickmarkers[0], markersize=self._size, ) - l.set_transform(blended_transform_factory( - self.axes.transData, self.axes.transAxes) ) + l.set_transform(self.axes.get_xaxis_transform()) self._set_artist_props(l) return l @@ -296,24 +296,20 @@ markersize=self._size, ) - l.set_transform(blended_transform_factory( - self.axes.transData, self.axes.transAxes) ) + l.set_transform(self.axes.get_xaxis_transform()) self._set_artist_props(l) return l def _get_gridline(self, loc): 'Get the default line2D instance' # x in data coords, y in axes coords - l = Line2D( xdata=(loc, loc), ydata=(0, 1), - color=rcParams['grid.color'], - linestyle=rcParams['grid.linestyle'], - linewidth=rcParams['grid.linewidth'], - antialiased=False, - ) - l.set_transform( - blended_transform_factory( - self.axes.transData, self.axes.transAxes)) - l.set_clip_box(self.axes.bbox) + l = Line2D(xdata=(loc, loc), ydata=(0, 1.0), + color=rcParams['grid.color'], + linestyle=rcParams['grid.linestyle'], + linewidth=rcParams['grid.linewidth'], + antialiased=False, + ) + l.set_transform(self.axes.get_xaxis_transform()) self._set_artist_props(l) return l @@ -322,7 +318,6 @@ 'Set the location of tick in data coords with scalar loc' x = loc - self.tick1line.set_xdata((x,)) self.tick2line.set_xdata((x,)) self.gridline.set_xdata((x, )) @@ -334,6 +329,13 @@ 'return the Interval instance for this axis view limits' return self.axes.viewLim.intervalx + def set_view_interval(self, vmin, vmax, ignore = False): + if ignore: + self.axes.viewLim.intervalx = vmin, vmax + else: + Vmin, Vmax = self.get_view_interval() + self.axes.viewLim.intervalx = min(vmin, Vmin), max(vmax, Vmax) + def get_minpos(self): return self.axes.dataLim.minposx @@ -363,12 +365,7 @@ dashdirection=0, xaxis=False, ) - trans = blended_transform_factory( - self.axes.transAxes, self.axes.transData) - # offset the text leftward with a post transformation - trans = trans + Affine2D().translate(-1 * self._padPixels, 0) - - t.set_transform( trans ) + t.set_transform(self.axes.get_yaxis_text1_transform(self._padPixels)) #t.set_transform( self.axes.transData ) self._set_artist_props(t) return t @@ -386,11 +383,7 @@ xaxis=False, horizontalalignment='left', ) - trans = blended_transform_factory( - self.axes.transAxes, self.axes.transData) - # offset the text rightward with a post transformation - trans = trans + Affine2D().translate(self._padPixels, 0) - t.set_transform( trans ) + t.set_transform(self.axes.get_yaxis_text2_transform(self._padPixels)) self._set_artist_props(t) return t @@ -404,9 +397,7 @@ linestyle = 'None', markersize=self._size, ) - l.set_transform( - blended_transform_factory( - self.axes.transAxes, self.axes.transData)) + l.set_transform(self.axes.get_yaxis_transform()) self._set_artist_props(l) return l @@ -420,9 +411,7 @@ markersize=self._size, ) - l.set_transform( - blended_transform_factory( - self.axes.transAxes, self.axes.transData)) + l.set_transform(self.axes.get_yaxis_transform()) self._set_artist_props(l) return l @@ -436,10 +425,7 @@ antialiased=False, ) - l.set_transform( blended_transform_factory( - self.axes.transAxes, self.axes.transData) ) - l.set_clip_box(self.axes.bbox) - + l.set_transform(self.axes.get_yaxis_transform()) self._set_artist_props(l) return l @@ -461,6 +447,13 @@ 'return the Interval instance for this axis view limits' return self.axes.viewLim.intervaly + def set_view_interval(self, vmin, vmax): + if ignore: + self.axes.viewLim.intervaly = vmin, vmax + else: + Vmin, Vmax = self.get_view_interval() + self.axes.viewLim.intervaly = min(vmin, Vmin), max(vmax, Vmax) + def get_minpos(self): return self.axes.dataLim.minposy @@ -530,8 +523,8 @@ def get_children(self): children = [self.label] - majorticks = self.get_major_ticks() - minorticks = self.get_minor_ticks() + majorticks = self.get_major_ticks(len(self.major.locator())) + minorticks = self.get_minor_ticks(len(self.minor.locator())) children.extend(majorticks) children.extend(minorticks) @@ -565,11 +558,20 @@ self.units = None self.set_units(None) - + def set_clip_path(self, clippath, transform=None): + Artist.set_clip_path(self, clippath, transform) + majorticks = self.get_major_ticks(len(self.major.locator())) + minorticks = self.get_minor_ticks(len(self.minor.locator())) + for child in self.majorTicks + self.minorTicks: + child.set_clip_path(clippath, transform) + def get_view_interval(self): 'return the Interval instance for this axis view limits' raise NotImplementedError('Derived must override') + def set_view_interval(self, vmin, vmax, ignore=False): + raise NotImplementedError('Derived must override') + def get_data_interval(self): 'return the Interval instance for this axis data limits' raise NotImplementedError('Derived must override') @@ -585,8 +587,8 @@ ticklabelBoxes = [] ticklabelBoxes2 = [] - majorTicks = self.get_major_ticks() majorLocs = self.major.locator() + majorTicks = self.get_major_ticks(len(majorLocs)) self.major.formatter.set_locs(majorLocs) majorLabels = [self.major.formatter(val, i) for i, val in enumerate(majorLocs)] @@ -609,8 +611,8 @@ extent = tick.label2.get_window_extent(renderer) ticklabelBoxes2.append(extent) - minorTicks = self.get_minor_ticks() minorLocs = self.minor.locator() + minorTicks = self.get_minor_ticks(len(minorLocs)) self.minor.formatter.set_locs(minorLocs) minorLabels = [self.minor.formatter(val, i) for i, val in enumerate(minorLocs)] @@ -727,11 +729,9 @@ 'Get the formatter of the minor ticker' return self.minor.formatter - def get_major_ticks(self): + def get_major_ticks(self, numticks): 'get the tick instances; grow as necessary' - numticks = len(self.major.locator()) - if len(self.majorTicks)<numticks: # update the new tick label properties from the old protoTick = self.majorTicks[0] @@ -746,9 +746,8 @@ return ticks - def get_minor_ticks(self): + def get_minor_ticks(self, numticks): 'get the minor tick instances; grow as necessary' - numticks = len(self.minor.locator()) if len(self.minorTicks)<numticks: protoTick = self.minorTicks[0] for i in range(numticks-len(self.minorTicks)): @@ -949,8 +948,9 @@ ### XXX if the user changes units, the information will be lost here ticks = self.convert_units(ticks) self.set_major_locator( FixedLocator(ticks) ) - self.get_view_interval().update(ticks,0) - return self.get_major_ticks() + if len(ticks): + self.set_view_interval(min(ticks), max(ticks)) + return self.get_major_ticks(len(ticks)) def _update_label_position(self, bboxes, bboxes2): """ @@ -1153,6 +1153,13 @@ 'return the Interval instance for this axis view limits' return self.axes.viewLim.intervalx + def set_view_interval(self, vmin, vmax, ignore=False): + if ignore: + self.axes.viewLim.intervalx = vmin, vmax + else: + Vmin, Vmax = self.get_view_interval() + self.axes.viewLim.intervalx = min(vmin, Vmin), max(vmax, Vmax) + def get_minpos(self): return self.axes.dataLim.minposx @@ -1357,6 +1364,13 @@ 'return the Interval instance for this axis view limits' return self.axes.viewLim.intervaly + def set_view_interval(self, vmin, vmax, ignore=False): + if ignore: + self.axes.viewLim.intervaly = vmin, vmax + else: + Vmin, Vmax = self.get_view_interval() + self.axes.viewLim.intervaly = min(vmin, Vmin), max(vmax, Vmax) + def get_minpos(self): return self.axes.dataLim.minposy Modified: branches/transforms/lib/matplotlib/backend_bases.py =================================================================== --- branches/transforms/lib/matplotlib/backend_bases.py 2007-10-02 08:30:29 UTC (rev 3907) +++ branches/transforms/lib/matplotlib/backend_bases.py 2007-10-03 12:50:04 UTC (rev 3908) @@ -537,7 +537,9 @@ """ Return the clip path """ - return self._clippath + if self._clippath is not None: + return self._clippath.get_transformed_path_and_affine() + return None, None def get_dashes(self): """ @@ -608,7 +610,7 @@ def set_clip_path(self, path): """ - Set the clip path + Set the clip path and transformation """ self._clippath = path @@ -758,7 +760,7 @@ return # Find all axes containing the mouse - axes_list = [a for a in self.canvas.figure.get_axes() if a.in_axes(x, y)] + axes_list = [a for a in self.canvas.figure.get_axes() if a.in_axes(self)] if len(axes_list) == 0: # None found self.inaxes = None @@ -1333,7 +1335,7 @@ if event.key!='a': n=int(event.key)-1 for i, a in enumerate(self.canvas.figure.get_axes()): - if event.x is not None and event.y is not None and a.in_axes(event.x, event.y): + if event.x is not None and event.y is not None and a.in_axes(event): if event.key=='a': a.set_navigate(True) else: @@ -1557,7 +1559,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(): + if x is not None and y is not None and a.in_axes(event) and a.get_navigate(): 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) @@ -1581,7 +1583,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(): + if x is not None and y is not None and a.in_axes(event) and a.get_navigate(): self._xypress.append(( x, y, a, i, a.viewLim.frozen(), a.transData.frozen())) self.press(event) @@ -1621,33 +1623,12 @@ def drag_pan(self, event): 'the drag callback in pan/zoom mode' - def format_deltas(event,dx,dy): - if event.key=='control': - if(abs(dx)>abs(dy)): - dy = dx - else: - dx = dy - elif event.key=='x': - dy = 0 - elif event.key=='y': - dx = 0 - elif event.key=='shift': - if 2*abs(dx) < abs(dy): - dx=0 - elif 2*abs(dy) < abs(dx): - dy=0 - elif(abs(dx)>abs(dy)): - dy=dy/abs(dy)*abs(dx) - else: - dx=dx/abs(dx)*abs(dy) - return (dx,dy) - 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... 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) + a.drag_pan(self._button_pressed, event.key, lastx, lasty, dx, dy, + old_lim, old_trans) self.dynamic_update() def release_zoom(self, event): @@ -1664,7 +1645,7 @@ self.draw() return - xmin, ymin, xmax, ymax = lim + xmin, ymin, xmax, ymax = lim.lbrt # zoom to rect inverse = a.transData.inverted() Modified: branches/transforms/lib/matplotlib/cbook.py =================================================================== --- branches/transforms/lib/matplotlib/cbook.py 2007-10-02 08:30:29 UTC (rev 3907) +++ branches/transforms/lib/matplotlib/cbook.py 2007-10-03 12:50:04 UTC (rev 3908) @@ -1033,7 +1033,27 @@ itself. """ return self._mapping.get(a, [a]) - + + +def simple_linear_interpolation(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) + + # MGDTODO: Could use linspace here? + for i in range(1, int(steps)): + result[i::steps] = delta * i + a0 + result[steps::steps] = a1 + + return result + if __name__=='__main__': assert( allequal([1,1,1]) ) assert(not allequal([1,1,0]) ) Modified: branches/transforms/lib/matplotlib/figure.py =================================================================== --- branches/transforms/lib/matplotlib/figure.py 2007-10-02 08:30:29 UTC (rev 3907) +++ branches/transforms/lib/matplotlib/figure.py 2007-10-03 12:50:04 UTC (rev 3908) @@ -7,7 +7,7 @@ import artist from artist import Artist -from axes import Axes, Subplot, PolarSubplot, PolarAxes +from axes import Axes, SubplotBase, subplot_class_factory from cbook import flatten, allequal, Stack, iterable, dedent import _image import colorbar as cbar @@ -22,6 +22,8 @@ from transforms import Affine2D, Bbox, BboxTransform, TransformedBbox from cm import ScalarMappable from contour import ContourSet +from projections import projection_factory, get_projection_names, \ + get_projection_class import warnings class SubplotParams: @@ -449,12 +451,17 @@ """ Add an a axes with axes rect [left, bottom, width, height] where all quantities are in fractions of figure width and height. kwargs are - legal Axes kwargs plus "polar" which sets whether to create a polar axes - + legal Axes kwargs plus "projection" which sets the projection type + of the axes. (For backward compatibility, polar=True may also be + provided, which is equivalent to projection='polar'). + Valid values for "projection" are: %s. Some of these projections + support additional kwargs, which may be provided to add_axes. + rect = l,b,w,h add_axes(rect) add_axes(rect, frameon=False, axisbg='g') add_axes(rect, polar=True) + add_axes(rect, projection='polar') add_axes(ax) # add an Axes instance @@ -470,10 +477,10 @@ add_axes(rect, label='axes2') The Axes instance will be returned - + The following kwargs are supported: - %(Axes)s - """ + %s + """ % (", ".join(get_projection_names()), '%(Axes)s') key = self._make_key(*args, **kwargs) @@ -489,13 +496,17 @@ else: rect = args[0] ispolar = kwargs.pop('polar', False) - + projection = kwargs.pop('projection', None) if ispolar: - a = PolarAxes(self, rect, **kwargs) - else: - a = Axes(self, rect, **kwargs) + if projection is not None and projection != 'polar': + raise ValueError( + "polar=True, yet projection='%s'. " + + "Only one of these arguments should be supplied." % + projection) + projection = 'polar' + + a = projection_factory(projection, self, rect, **kwargs) - self.axes.append(a) self._axstack.push(a) self.sca(a) @@ -513,15 +524,21 @@ add_subplot(111, polar=True) # add a polar subplot add_subplot(sub) # add Subplot instance sub - kwargs are legal Axes kwargs plus"polar" which sets whether to create a - polar axes. The Axes instance will be returned. + kwargs are legal Axes kwargs plus "projection", which chooses + a projection type for the axes. (For backward compatibility, + polar=True may also be provided, which is equivalent to + projection='polar'). Valid values for "projection" are: %s. + Some of these projections support additional kwargs, which may + be provided to add_axes. + The Axes instance will be returned. + If the figure already has a subplot with key *args, *kwargs then it will simply make that subplot current and return it The following kwargs are supported: - %(Axes)s - """ + %s + """ % (", ".join(get_projection_names()), "%(Axes)s") key = self._make_key(*args, **kwargs) if self._seen.has_key(key): @@ -532,16 +549,22 @@ if not len(args): return - if isinstance(args[0], Subplot) or isinstance(args[0], PolarSubplot): + if isinstance(args[0], SubplotBase): a = args[0] assert(a.get_figure() is self) else: ispolar = kwargs.pop('polar', False) + projection = kwargs.pop('projection', None) if ispolar: - a = PolarSubplot(self, *args, **kwargs) - else: - a = Subplot(self, *args, **kwargs) + if projection is not None and projection != 'polar': + raise ValueError( + "polar=True, yet projection='%s'. " + + "Only one of these arguments should be supplied." % + projection) + projection = 'polar' + projection_class = get_projection_class(projection) + a = subplot_class_factory(projection_class)(self, *args, **kwargs) self.axes.append(a) self._axstack.push(a) Modified: branches/transforms/lib/matplotlib/patches.py =================================================================== --- branches/transforms/lib/matplotlib/patches.py 2007-10-02 08:30:29 UTC (rev 3907) +++ branches/transforms/lib/matplotlib/patches.py 2007-10-03 12:50:04 UTC (rev 3908) @@ -12,6 +12,8 @@ import matplotlib.mlab as mlab import matplotlib.artist as artist from matplotlib.path import Path +# MGDTODO: Maybe this belongs elsewhere +from matplotlib.backends._backend_agg import point_in_path # these are not available for the object inspector until after the # class is build so we define an initial set here for the init @@ -72,6 +74,7 @@ self._linewidth = linewidth self._antialiased = antialiased self._hatch = hatch + self._combined_transform = transforms.IdentityTransform() self.fill = fill if len(kwargs): artist.setp(self, **kwargs) @@ -84,19 +87,15 @@ Returns T/F, {} """ - # MGDTODO: This will probably need to be implemented in C++ - + # This is a general version of contains should work on any + # patch with a path. However, patches that have a faster + # algebraic solution to hit-testing should override this + # method. if callable(self._contains): return self._contains(self,mouseevent) - try: - # TODO: make this consistent with patch collection algorithm - x, y = self.get_transform().inverse_xy_tup((mouseevent.x, mouseevent.y)) - xyverts = self.get_verts() - inside = nxutils.pnpoly(x, y, xyverts) - #print str(self),"%g,%g is in"%(x,y),xyverts,inside - return inside,{} - except ValueError: - return False,{} + inside = point_in_path(mouseevent.x, mouseevent.y, self.get_path(), + self.get_transform().frozen()) + return inside, {} def update_from(self, other): artist.Artist.update_from(self, other) @@ -109,6 +108,17 @@ self.set_figure(other.get_figure()) self.set_alpha(other.get_alpha()) + def get_transform(self): + return self._combined_transform + + def set_transform(self, t): + artist.Artist.set_transform(self, t) + self._combined_transform = self.get_patch_transform() + \ + artist.Artist.get_transform(self) + + def get_patch_transform(self): + return transforms.IdentityTransform() + def get_antialiased(self): return self._antialiased @@ -207,12 +217,12 @@ if not self.fill or self._facecolor is None: rgbFace = None else: rgbFace = colors.colorConverter.to_rgb(self._facecolor) - + if self._hatch: gc.set_hatch(self._hatch ) path = self.get_path() - transform = self.get_patch_transform() + self.get_transform() + transform = self.get_transform() renderer.draw_path(gc, path, transform, rgbFace) @@ -226,12 +236,10 @@ def get_window_extent(self, renderer=None): - verts = self.get_verts() - tverts = self.get_transform().seq_xy_tups(verts) - return transforms.bound_vertices(tverts) + trans_path = self.get_path().transformed(self.get_path_transform()) + return Bbox.unit().update_from_data(trans_path.vertices) - def set_lw(self, val): 'alias for set_linewidth' self.set_linewidth(val) @@ -350,6 +358,11 @@ def get_patch_transform(self): return self._rect_transform + + def contains(self, mouseevent): + x, y = self.get_transform().inverted().transform_point( + (mouseevent.x, mouseevent.y)) + return (x >= 0.0 and x <= 1.0 and y >= 0.0 and y <= 1.0), {} def get_x(self): "Return the left coord of the rectangle" @@ -445,8 +458,8 @@ def get_path(self): return self._path - def get_transform(self): - return self._poly_transform + self._transform + def get_patch_transform(self): + return self._poly_transform class Polygon(Patch): """ @@ -467,39 +480,35 @@ self._path = Path(xy, closed=True) __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd - def get_verts(self): + def get_path(self): return self._path - - # MGDTODO: Convert units - xs = self.convert_xunits(xs) - ys = self.convert_yunits(ys) - -class Wedge(Polygon): + +class Wedge(Patch): def __str__(self): return "Wedge(%g,%g)"%self.xy[0] - def __init__(self, center, r, theta1, theta2, - dtheta=0.1, **kwargs): + def __init__(self, center, r, theta1, theta2, **kwargs): """ Draw a wedge centered at x,y tuple center with radius r that sweeps theta1 to theta2 (angles) - dtheta is the resolution in degrees - Valid kwargs are: %(Patch)s """ - # MGDTODO: Implement me - xc, yc = center - rads = (math.pi/180.)*npy.arange(theta1, theta2+0.1*dtheta, dtheta) - xs = r*npy.cos(rads)+xc - ys = r*npy.sin(rads)+yc - ... [truncated message content] |
From: <ef...@us...> - 2007-10-02 08:30:38
|
Revision: 3907 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3907&view=rev Author: efiring Date: 2007-10-02 01:30:29 -0700 (Tue, 02 Oct 2007) Log Message: ----------- matplotlib.use() raises an exception if called too late Modified Paths: -------------- trunk/matplotlib/CHANGELOG trunk/matplotlib/lib/matplotlib/__init__.py Modified: trunk/matplotlib/CHANGELOG =================================================================== --- trunk/matplotlib/CHANGELOG 2007-10-01 11:53:52 UTC (rev 3906) +++ trunk/matplotlib/CHANGELOG 2007-10-02 08:30:29 UTC (rev 3907) @@ -1,3 +1,6 @@ +2007-10-01 Made matplotlib.use() raise an exception if called after + backends has been imported. + 2007-09-30 Modified update* methods of Bbox and Interval so they work with reversed axes. Prior to this, trying to set the ticks on a reversed axis failed with an Modified: trunk/matplotlib/lib/matplotlib/__init__.py =================================================================== --- trunk/matplotlib/lib/matplotlib/__init__.py 2007-10-01 11:53:52 UTC (rev 3906) +++ trunk/matplotlib/lib/matplotlib/__init__.py 2007-10-02 08:30:29 UTC (rev 3907) @@ -716,6 +716,9 @@ except: from config import rcParams, rcdefaults +_use_error_msg = """ matplotlib.use() must be called *before* pylab +or matplotlib.backends is imported for the first time.""" + def use(arg): """ Set the matplotlib backend to one of the known backends. @@ -732,6 +735,8 @@ for the first time; or, if you are not using pylab, it must be called before importing matplotlib.backends. """ + if 'matplotlib.backends' in sys.modules: + raise RuntimeError(_use_error_msg) be_parts = arg.split('.') name = validate_backend(be_parts[0]) rcParams['backend'] = name 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:54:17
|
Revision: 3906 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3906&view=rev Author: mdboom Date: 2007-10-01 04:53:52 -0700 (Mon, 01 Oct 2007) Log Message: ----------- Merged revisions 3896-3905 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r3898 | jdh2358 | 2007-09-28 08:41:08 -0400 (Fri, 28 Sep 2007) | 2 lines fixed some tick accessor bugs ........ r3899 | jouni | 2007-09-28 11:50:01 -0400 (Fri, 28 Sep 2007) | 3 lines Catch UnboundLocalError in checkdep_pdftops; it is raised if no output line of pdftops -v contains the word "version". ........ r3900 | jouni | 2007-09-28 11:57:49 -0400 (Fri, 28 Sep 2007) | 2 lines More debugging output when using TeX with the pdf backend ........ r3901 | jouni | 2007-09-30 16:08:50 -0400 (Sun, 30 Sep 2007) | 3 lines use_tex in pdf backend: don't use AFM files, which are not there in some TeX distros ........ r3902 | efiring | 2007-09-30 16:32:31 -0400 (Sun, 30 Sep 2007) | 4 lines bugfix by Zack, confirmed by Gary Ruben. http://sourceforge.net/mailarchive/forum.php?thread_name=d8cf9020703071339y43354eaerbfa1a47d272e5d26%40mail.gmail.com&forum_name=matplotlib-users ........ r3903 | efiring | 2007-09-30 16:47:55 -0400 (Sun, 30 Sep 2007) | 2 lines Apply patch by Leon Barrett, tracker #1798196 ........ r3904 | efiring | 2007-10-01 03:06:43 -0400 (Mon, 01 Oct 2007) | 2 lines Fixed bug in updating dataLim when an axis is reversed ........ Modified Paths: -------------- branches/transforms/CHANGELOG branches/transforms/lib/matplotlib/__init__.py branches/transforms/lib/matplotlib/axes3d.py branches/transforms/lib/matplotlib/axis.py branches/transforms/lib/matplotlib/backends/backend_pdf.py branches/transforms/lib/matplotlib/dviread.py branches/transforms/lib/matplotlib/widgets.py Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-3895 + /trunk/matplotlib:1-3905 Modified: branches/transforms/CHANGELOG =================================================================== --- branches/transforms/CHANGELOG 2007-10-01 11:44:54 UTC (rev 3905) +++ branches/transforms/CHANGELOG 2007-10-01 11:53:52 UTC (rev 3906) @@ -1,3 +1,10 @@ +2007-09-30 Modified update* methods of Bbox and Interval so they + work with reversed axes. Prior to this, trying to + set the ticks on a reversed axis failed with an + uninformative error message. - EF + +2007-09-30 Applied patches to axes3d to fix index error problem - EF + 2007-09-24 Applied Eike Welk's patch reported on mpl-dev on 2007-09-22 Fixes a bug with multiple plot windows in the qt backend, ported the changes to backend_qt4 as well - DSD @@ -2,3 +9,3 @@ -2007-09-21 Changed cbook.reversed to yield the same result as the +2007-09-21 Changed cbook.reversed to yield the same result as the python reversed builtin - DSD Modified: branches/transforms/lib/matplotlib/__init__.py =================================================================== --- branches/transforms/lib/matplotlib/__init__.py 2007-10-01 11:44:54 UTC (rev 3905) +++ branches/transforms/lib/matplotlib/__init__.py 2007-10-01 11:53:52 UTC (rev 3906) @@ -270,7 +270,7 @@ v = line.split()[-1] float(v) return v - except (IndexError, ValueError): + except (IndexError, ValueError, UnboundLocalError): return None def compare_versions(a, b): Modified: branches/transforms/lib/matplotlib/axes3d.py =================================================================== --- branches/transforms/lib/matplotlib/axes3d.py 2007-10-01 11:44:54 UTC (rev 3905) +++ branches/transforms/lib/matplotlib/axes3d.py 2007-10-01 11:53:52 UTC (rev 3906) @@ -510,16 +510,16 @@ # polys = [] boxes = [] - for rs in npy.arange(0,rows,rstride): - for cs in npy.arange(0,cols,cstride): + for rs in npy.arange(0,rows-1,rstride): + for cs in npy.arange(0,cols-1,cstride): ps = [] corners = [] for a,ta in [(X,tX),(Y,tY),(Z,tZ)]: - ztop = a[rs][cs:min(cols-1,cs+cstride)] + ztop = a[rs][cs:min(cols,cs+cstride+1)] zleft = ta[min(cols-1,cs+cstride)][rs:min(rows,rs+rstride+1)] zbase = a[min(rows-1,rs+rstride)][cs:min(cols,cs+cstride+1):] zbase = zbase[::-1] - zright = ta[cs][rs:min(rows-1,rs+rstride):] + zright = ta[cs][rs:min(rows,rs+rstride+1):] zright = zright[::-1] corners.append([ztop[0],ztop[-1],zbase[0],zbase[-1]]) z = npy.concatenate((ztop,zleft,zbase,zright)) Modified: branches/transforms/lib/matplotlib/axis.py =================================================================== --- branches/transforms/lib/matplotlib/axis.py 2007-10-01 11:44:54 UTC (rev 3905) +++ branches/transforms/lib/matplotlib/axis.py 2007-10-01 11:53:52 UTC (rev 3906) @@ -530,8 +530,11 @@ def get_children(self): children = [self.label] - children.extend(self.majorTicks) - children.extend(self.minorTicks) + majorticks = self.get_major_ticks() + minorticks = self.get_minor_ticks() + + children.extend(majorticks) + children.extend(minorticks) return children def cla(self): @@ -654,7 +657,8 @@ def get_gridlines(self): 'Return the grid lines as a list of Line2D instance' - return silent_list('Line2D gridline', [tick.gridline for tick in self.majorTicks]) + ticks = self.get_major_ticks() + return silent_list('Line2D gridline', [tick.gridline for tick in ticks]) def get_label(self): 'Return the axis label as a Text instance' @@ -670,14 +674,16 @@ def get_ticklabels(self): 'Return a list of Text instances for ticklabels' - labels1 = [tick.label1 for tick in self.majorTicks if tick.label1On] - labels2 = [tick.label2 for tick in self.majorTicks if tick.label2On] + ticks = self.get_major_ticks() + labels1 = [tick.label1 for tick in ticks if tick.label1On] + labels2 = [tick.label2 for tick in ticks if tick.label2On] return silent_list('Text ticklabel', labels1+labels2) def get_ticklines(self): 'Return the ticklines lines as a list of Line2D instance' lines = [] - for tick in self.majorTicks: + ticks = self.get_major_ticks() + for tick in ticks: lines.append(tick.tick1line) lines.append(tick.tick2line) return silent_list('Line2D ticklines', lines) @@ -1087,9 +1093,10 @@ """ assert position == 'top' or position == 'bottom' or position == 'both' or position == 'default' - ticks = list(self.majorTicks) # a copy - ticks.extend( self.minorTicks ) + ticks = list( self.get_major_ticks() ) # a copy + ticks.extend( self.get_minor_ticks() ) + if position == 'top': for t in ticks: t.tick1On = False @@ -1287,8 +1294,8 @@ """ assert position == 'left' or position == 'right' or position == 'both' or position == 'default' - ticks = list(self.majorTicks) # a copy - ticks.extend( self.minorTicks ) + ticks = list( self.get_major_ticks() ) # a copy + ticks.extend( self.get_minor_ticks() ) if position == 'right': self.set_offset_position('right') Modified: branches/transforms/lib/matplotlib/backends/backend_pdf.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_pdf.py 2007-10-01 11:44:54 UTC (rev 3905) +++ branches/transforms/lib/matplotlib/backends/backend_pdf.py 2007-10-01 11:53:52 UTC (rev 3906) @@ -500,70 +500,15 @@ finally: fh.close() - fh = open(fontinfo.afmfile, 'rb') - matplotlib.verbose.report( - 'Reading metrics from ' + fontinfo.afmfile, 'debug') - try: - afmdata = AFM(fh) - finally: - fh.close() - font = FT2Font(filename) - font.attach_file(fontinfo.afmfile) widthsObject, fontdescObject, fontdictObject, fontfileObject = \ [ self.reserveObject(n) for n in ('font widths', 'font descriptor', 'font dictionary', 'font file') ] - _, _, fullname, familyname, weight, italic_angle, fixed_pitch, \ - ul_position, ul_thickness = font.get_ps_font_info() - - if fontinfo.encodingfile is not None: - enc = dviread.Encoding(fontinfo.encodingfile) - widths = [] - for ch in enc: - try: - widths.append(afmdata.get_width_from_char_name(ch)) - except KeyError: - matplotlib.verbose.report( - 'No width for %s in %s' % (ch, fullname), 'debug-annoying') - widths.append(0) - - differencesArray = [ Name(ch) for ch in enc ] - differencesArray = [ 0 ] + differencesArray - firstchar = 0 - lastchar = len(differencesArray) - 2 - else: - widths = [ None for i in range(256) ] - for ch in range(256): - try: - widths[ch] = afmdata.get_width_char(ch, isord=True) - except KeyError: - pass - not_None = [ch for ch in range(256) - if widths[ch] is not None] - firstchar = not_None[0] - lastchar = not_None[-1] - widths = widths[firstchar:lastchar+1] - for i,w in enumerate(widths): - if w is None: widths[i] = 0 - - differencesArray = [ ] - need_idx = True - for ch in range(firstchar, lastchar+1): - try: - name = afmdata.get_name_char(ch, isord=True) - if need_idx: - differencesArray.append(ch) - need_idx = False - differencesArray.append(Name(name)) - except KeyError: - matplotlib.verbose.report( - 'No name for glyph %d in %s' % (ch, fullname), - 'debug-annoying') - need_idx = True - + firstchar = 0 + lastchar = len(fontinfo.widths) - 1 fontdict = { 'Type': Name('Font'), @@ -575,15 +520,22 @@ 'FontDescriptor': fontdescObject, } - fontdict.update({ - 'Encoding': { 'Type': Name('Encoding'), - 'Differences': differencesArray }, - }) + if fontinfo.encodingfile is not None: + enc = dviread.Encoding(fontinfo.encodingfile) + differencesArray = [ Name(ch) for ch in enc ] + differencesArray = [ 0 ] + differencesArray + fontdict.update({ + 'Encoding': { 'Type': Name('Encoding'), + 'Differences': differencesArray }, + }) + _, _, fullname, familyname, weight, italic_angle, fixed_pitch, \ + ul_position, ul_thickness = font.get_ps_font_info() + flags = 0 if fixed_pitch: flags |= 1 << 0 # fixed width if 0: flags |= 1 << 1 # TODO: serif - if 1: flags |= 1 << 2 # TODO: symbolic + if 1: flags |= 1 << 2 # TODO: symbolic (most TeX fonts are) else: flags |= 1 << 5 # non-symbolic if italic_angle: flags |= 1 << 6 # italic if 0: flags |= 1 << 16 # TODO: all caps @@ -598,33 +550,17 @@ 'ItalicAngle': italic_angle, 'Ascent': font.ascender, 'Descent': font.descender, - 'CapHeight': 1000, # default guess if missing from AFM file - 'XHeight': afmdata.get_xheight(), + 'CapHeight': 1000, # TODO: find this out + 'XHeight': 500, # TODO: this one too 'FontFile': fontfileObject, 'FontFamily': familyname, + 'StemV': 50, # TODO + # (see also revision 3874; but not all TeX distros have AFM files!) #'FontWeight': a number where 400 = Regular, 700 = Bold } - try: - descriptor['CapHeight'] = afmdata.get_capheight() - except KeyError: - pass - # StemV is obligatory in PDF font descriptors but optional in - # AFM files. The collection of AFM files in my TeX Live 2007 - # collection has values ranging from 22 to 219, with both - # median and mode 50, so if the AFM file is silent, I'm - # guessing 50. -JKS - StemV = afmdata.get_vertical_stem_width() - if StemV is None: StemV = 50 - descriptor['StemV'] = StemV - - # StemH is entirely optional: - StemH = afmdata.get_horizontal_stem_width() - if StemH is not None: - descriptor['StemH'] = StemH - self.writeObject(fontdictObject, fontdict) - self.writeObject(widthsObject, widths) + self.writeObject(widthsObject, fontinfo.widths) self.writeObject(fontdescObject, descriptor) t1font = type1font.Type1Font(filename) @@ -1470,11 +1406,13 @@ oldfont, seq = None, [] for x1, y1, dvifont, glyph, width in page.text: if dvifont != oldfont: - fontinfo = self.tex_font_mapping(dvifont.texname) - pdfname = self.file.fontName(fontinfo.filename) - self.file.fontInfo[pdfname] = Bunch( - encodingfile=fontinfo.encoding, - afmfile=fontinfo.afm) + psfont = self.tex_font_mapping(dvifont.texname) + pdfname = self.file.fontName(psfont.filename) + if self.file.fontInfo.get(pdfname, None) is None: + self.file.fontInfo[pdfname] = Bunch( + encodingfile=psfont.encoding, + widths=dvifont.widths, + dvifont=dvifont) seq += [['font', pdfname, dvifont.size]] oldfont = dvifont seq += [['text', x1, y1, [chr(glyph)], x1+width]] Modified: branches/transforms/lib/matplotlib/dviread.py =================================================================== --- branches/transforms/lib/matplotlib/dviread.py 2007-10-01 11:44:54 UTC (rev 3905) +++ branches/transforms/lib/matplotlib/dviread.py 2007-10-01 11:53:52 UTC (rev 3906) @@ -84,7 +84,7 @@ e = 0 # zero depth else: # glyph x,y,font,g,w = elt - h = _mul2012(font._scale, font._tfm.height[g]) + h = _mul2012(font._scale, font._tfm.height[g]) e = _mul2012(font._scale, font._tfm.depth[g]) minx = min(minx, x) miny = min(miny, y - h) @@ -380,19 +380,21 @@ class DviFont(object): """ - Object that holds a font's texname and size and supports comparison. + Object that holds a font's texname and size, supports comparison, + and knows the widths of glyphs in the same units as the AFM file. There are also internal attributes (for use by dviread.py) that are _not_ used for comparison. The size is in Adobe points (converted from TeX points). """ - __slots__ = ('texname', 'size', '_scale', '_vf', '_tfm') + __slots__ = ('texname', 'size', 'widths', '_scale', '_vf', '_tfm') def __init__(self, scale, tfm, texname, vf): self._scale, self._tfm, self.texname, self._vf = \ scale, tfm, texname, vf - # TODO: would it make more sense to have the size in dpi units? self.size = scale * (72.0 / (72.27 * 2**16)) + self.widths = [ (1000*tfm.width.get(char, 0)) >> 20 + for char in range(0, max(tfm.width)) ] def __eq__(self, other): return self.__class__ == other.__class__ and \ @@ -402,6 +404,10 @@ return not self.__eq__(other) def _width_of(self, char): + """ + Width of char in dvi units. For internal use by dviread.py. + """ + width = self._tfm.width.get(char, None) if width is not None: return _mul2012(width, self._scale) @@ -598,7 +604,6 @@ fn, enc = result.filename, result.encoding if fn is not None and not fn.startswith('/'): result.filename = find_tex_file(fn) - result.afm = find_tex_file(fn[:-4] + '.afm') if enc is not None and not enc.startswith('/'): result.encoding = find_tex_file(result.encoding) return result @@ -734,6 +739,9 @@ result = pipe.readline().rstrip() pipe.close() + matplotlib.verbose.report('find_tex_file: %s -> %s' \ + % (filename, result), + 'debug') return result # With multiple text objects per figure (e.g. tick labels) we may end Modified: branches/transforms/lib/matplotlib/widgets.py =================================================================== --- branches/transforms/lib/matplotlib/widgets.py 2007-10-01 11:44:54 UTC (rev 3905) +++ branches/transforms/lib/matplotlib/widgets.py 2007-10-01 11:53:52 UTC (rev 3906) @@ -971,14 +971,14 @@ print ' endposition : (%f, %f)' % (erelease.xdata, erelease.ydata) print ' used button : ', eclick.button - def toggle_Selector(event): + def toggle_selector(event): print ' Key pressed.' - if event.key in ['Q', 'q'] and toggle_Selector.RS.active: + if event.key in ['Q', 'q'] and toggle_selector.RS.active: print ' RectangleSelector deactivated.' - toggle_Selector.RS.set_active(False) - if event.key in ['A', 'a'] and not toggle_Selector.RS.active: + toggle_selector.RS.set_active(False) + if event.key in ['A', 'a'] and not toggle_selector.RS.active: print ' RectangleSelector activated.' - toggle_Selector.RS.set_active(True) + toggle_selector.RS.set_active(True) x = arange(100)/(99.0) y = sin(x) @@ -986,8 +986,8 @@ ax = subplot(111) ax.plot(x,y) - toggle_Selector.RS = RectangleSelector(ax, onselect, drawtype='line') - connect('key_press_event', toggle_Selector) + toggle_selector.RS = RectangleSelector(ax, onselect, drawtype='line') + connect('key_press_event', toggle_selector) show() """ def __init__(self, ax, onselect, drawtype='box', 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 (Mon, 01 Oct 2007) 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: <ef...@us...> - 2007-10-01 07:06:44
|
Revision: 3904 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3904&view=rev Author: efiring Date: 2007-10-01 00:06:43 -0700 (Mon, 01 Oct 2007) Log Message: ----------- Fixed bug in updating dataLim when an axis is reversed Modified Paths: -------------- trunk/matplotlib/CHANGELOG trunk/matplotlib/src/_transforms.cpp Modified: trunk/matplotlib/CHANGELOG =================================================================== --- trunk/matplotlib/CHANGELOG 2007-09-30 20:47:55 UTC (rev 3903) +++ trunk/matplotlib/CHANGELOG 2007-10-01 07:06:43 UTC (rev 3904) @@ -1,3 +1,10 @@ +2007-09-30 Modified update* methods of Bbox and Interval so they + work with reversed axes. Prior to this, trying to + set the ticks on a reversed axis failed with an + uninformative error message. - EF + +2007-09-30 Applied patches to axes3d to fix index error problem - EF + 2007-09-24 Applied Eike Welk's patch reported on mpl-dev on 2007-09-22 Fixes a bug with multiple plot windows in the qt backend, ported the changes to backend_qt4 as well - DSD @@ -2,3 +9,3 @@ -2007-09-21 Changed cbook.reversed to yield the same result as the +2007-09-21 Changed cbook.reversed to yield the same result as the python reversed builtin - DSD Modified: trunk/matplotlib/src/_transforms.cpp =================================================================== --- trunk/matplotlib/src/_transforms.cpp 2007-09-30 20:47:55 UTC (rev 3903) +++ trunk/matplotlib/src/_transforms.cpp 2007-10-01 07:06:43 UTC (rev 3904) @@ -159,12 +159,19 @@ double minx = _val1->val(); double maxx = _val2->val(); + int reversed = 0; + if (minx > maxx) { + reversed = 1; + double tmp = minx; + minx = maxx; + maxx = tmp; + } double thisval; thisval = Py::Float(vals[0]); - if (ignore) { + if (ignore) { minx = thisval; maxx = thisval; } @@ -176,9 +183,13 @@ _minpos->update(thisval); } - - _val1->set_api(minx); - _val2->set_api(maxx); + if (reversed) { + _val1->set_api(maxx); + _val2->set_api(minx); + } else { + _val1->set_api(minx); + _val2->set_api(maxx); + } return Py::Object(); } @@ -459,8 +470,24 @@ double minx = _ll->xval(); double maxx = _ur->xval(); + int xreversed = 0; + if (minx > maxx) { + xreversed = 1; + double tmp = minx; + minx = maxx; + maxx = tmp; + } + + double miny = _ll->yval(); double maxy = _ur->yval(); + int yreversed = 0; + if (miny > maxy) { + yreversed = 1; + double tmp = miny; + miny = maxy; + maxy = tmp; + } Py::Tuple tup; if (ignore) { @@ -482,11 +509,22 @@ if (y>maxy) maxy=y; } + if (xreversed) { + _ll->x_api()->set_api(maxx); + _ur->x_api()->set_api(minx); + } else { + _ll->x_api()->set_api(minx); + _ur->x_api()->set_api(maxx); + } - _ll->x_api()->set_api(minx); - _ll->y_api()->set_api(miny); - _ur->x_api()->set_api(maxx); - _ur->y_api()->set_api(maxy); + if (yreversed) { + _ll->y_api()->set_api(maxy); + _ur->y_api()->set_api(miny); + } else { + _ll->y_api()->set_api(miny); + _ur->y_api()->set_api(maxy); + } + return Py::Object(); } @@ -519,8 +557,24 @@ double minx = _ll->xval(); double maxx = _ur->xval(); + int xreversed = 0; + if (minx > maxx) { + xreversed = 1; + double tmp = minx; + minx = maxx; + maxx = tmp; + } + + double miny = _ll->yval(); double maxy = _ur->yval(); + int yreversed = 0; + if (miny > maxy) { + yreversed = 1; + double tmp = miny; + miny = maxy; + maxy = tmp; + } double thisx, thisy; //don't use current bounds on first update @@ -550,10 +604,21 @@ Py_XDECREF(xyin); if (ngood) { - _ll->x_api()->set_api(minx); - _ll->y_api()->set_api(miny); - _ur->x_api()->set_api(maxx); - _ur->y_api()->set_api(maxy); + if (xreversed) { + _ll->x_api()->set_api(maxx); + _ur->x_api()->set_api(minx); + } else { + _ll->x_api()->set_api(minx); + _ur->x_api()->set_api(maxx); + } + + if (yreversed) { + _ll->y_api()->set_api(maxy); + _ur->y_api()->set_api(miny); + } else { + _ll->y_api()->set_api(miny); + _ur->y_api()->set_api(maxy); + } } return Py::Object(); } @@ -594,8 +659,24 @@ double minx = _ll->xval(); double maxx = _ur->xval(); + int xreversed = 0; + if (minx > maxx) { + xreversed = 1; + double tmp = minx; + minx = maxx; + maxx = tmp; + } + + double miny = _ll->yval(); double maxy = _ur->yval(); + int yreversed = 0; + if (miny > maxy) { + yreversed = 1; + double tmp = miny; + miny = maxy; + maxy = tmp; + } double thisx, thisy; //don't use current bounds on first update @@ -627,10 +708,21 @@ Py_XDECREF(y); - _ll->x_api()->set_api(minx); - _ll->y_api()->set_api(miny); - _ur->x_api()->set_api(maxx); - _ur->y_api()->set_api(maxy); + if (xreversed) { + _ll->x_api()->set_api(maxx); + _ur->x_api()->set_api(minx); + } else { + _ll->x_api()->set_api(minx); + _ur->x_api()->set_api(maxx); + } + + if (yreversed) { + _ll->y_api()->set_api(maxy); + _ur->y_api()->set_api(miny); + } else { + _ll->y_api()->set_api(miny); + _ur->y_api()->set_api(maxy); + } return Py::Object(); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ef...@us...> - 2007-09-30 20:47:58
|
Revision: 3903 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3903&view=rev Author: efiring Date: 2007-09-30 13:47:55 -0700 (Sun, 30 Sep 2007) Log Message: ----------- Apply patch by Leon Barrett, tracker #1798196 Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/axes3d.py Modified: trunk/matplotlib/lib/matplotlib/axes3d.py =================================================================== --- trunk/matplotlib/lib/matplotlib/axes3d.py 2007-09-30 20:32:31 UTC (rev 3902) +++ trunk/matplotlib/lib/matplotlib/axes3d.py 2007-09-30 20:47:55 UTC (rev 3903) @@ -515,11 +515,11 @@ ps = [] corners = [] for a,ta in [(X,tX),(Y,tY),(Z,tZ)]: - ztop = a[rs][cs:min(cols-1,cs+cstride)] + ztop = a[rs][cs:min(cols,cs+cstride+1)] zleft = ta[min(cols-1,cs+cstride)][rs:min(rows,rs+rstride+1)] zbase = a[min(rows-1,rs+rstride)][cs:min(cols,cs+cstride+1):] zbase = zbase[::-1] - zright = ta[cs][rs:min(rows-1,rs+rstride):] + zright = ta[cs][rs:min(rows,rs+rstride+1):] zright = zright[::-1] corners.append([ztop[0],ztop[-1],zbase[0],zbase[-1]]) z = npy.concatenate((ztop,zleft,zbase,zright)) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ef...@us...> - 2007-09-30 20:32:33
|
Revision: 3902 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3902&view=rev Author: efiring Date: 2007-09-30 13:32:31 -0700 (Sun, 30 Sep 2007) Log Message: ----------- bugfix by Zack, confirmed by Gary Ruben. http://sourceforge.net/mailarchive/forum.php?thread_name=d8cf9020703071339y43354eaerbfa1a47d272e5d26%40mail.gmail.com&forum_name=matplotlib-users Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/axes3d.py Modified: trunk/matplotlib/lib/matplotlib/axes3d.py =================================================================== --- trunk/matplotlib/lib/matplotlib/axes3d.py 2007-09-30 20:08:50 UTC (rev 3901) +++ trunk/matplotlib/lib/matplotlib/axes3d.py 2007-09-30 20:32:31 UTC (rev 3902) @@ -510,8 +510,8 @@ # polys = [] boxes = [] - for rs in npy.arange(0,rows,rstride): - for cs in npy.arange(0,cols,cstride): + for rs in npy.arange(0,rows-1,rstride): + for cs in npy.arange(0,cols-1,cstride): ps = [] corners = [] for a,ta in [(X,tX),(Y,tY),(Z,tZ)]: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jo...@us...> - 2007-09-30 20:08:57
|
Revision: 3901 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3901&view=rev Author: jouni Date: 2007-09-30 13:08:50 -0700 (Sun, 30 Sep 2007) Log Message: ----------- use_tex in pdf backend: don't use AFM files, which are not there in some TeX distros Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py trunk/matplotlib/lib/matplotlib/dviread.py Modified: trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2007-09-28 15:57:49 UTC (rev 3900) +++ trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2007-09-30 20:08:50 UTC (rev 3901) @@ -500,70 +500,15 @@ finally: fh.close() - fh = open(fontinfo.afmfile, 'rb') - matplotlib.verbose.report( - 'Reading metrics from ' + fontinfo.afmfile, 'debug') - try: - afmdata = AFM(fh) - finally: - fh.close() - font = FT2Font(filename) - font.attach_file(fontinfo.afmfile) widthsObject, fontdescObject, fontdictObject, fontfileObject = \ [ self.reserveObject(n) for n in ('font widths', 'font descriptor', 'font dictionary', 'font file') ] - _, _, fullname, familyname, weight, italic_angle, fixed_pitch, \ - ul_position, ul_thickness = font.get_ps_font_info() - - if fontinfo.encodingfile is not None: - enc = dviread.Encoding(fontinfo.encodingfile) - widths = [] - for ch in enc: - try: - widths.append(afmdata.get_width_from_char_name(ch)) - except KeyError: - matplotlib.verbose.report( - 'No width for %s in %s' % (ch, fullname), 'debug-annoying') - widths.append(0) - - differencesArray = [ Name(ch) for ch in enc ] - differencesArray = [ 0 ] + differencesArray - firstchar = 0 - lastchar = len(differencesArray) - 2 - else: - widths = [ None for i in range(256) ] - for ch in range(256): - try: - widths[ch] = afmdata.get_width_char(ch, isord=True) - except KeyError: - pass - not_None = [ch for ch in range(256) - if widths[ch] is not None] - firstchar = not_None[0] - lastchar = not_None[-1] - widths = widths[firstchar:lastchar+1] - for i,w in enumerate(widths): - if w is None: widths[i] = 0 - - differencesArray = [ ] - need_idx = True - for ch in range(firstchar, lastchar+1): - try: - name = afmdata.get_name_char(ch, isord=True) - if need_idx: - differencesArray.append(ch) - need_idx = False - differencesArray.append(Name(name)) - except KeyError: - matplotlib.verbose.report( - 'No name for glyph %d in %s' % (ch, fullname), - 'debug-annoying') - need_idx = True - + firstchar = 0 + lastchar = len(fontinfo.widths) - 1 fontdict = { 'Type': Name('Font'), @@ -575,15 +520,22 @@ 'FontDescriptor': fontdescObject, } - fontdict.update({ - 'Encoding': { 'Type': Name('Encoding'), - 'Differences': differencesArray }, - }) + if fontinfo.encodingfile is not None: + enc = dviread.Encoding(fontinfo.encodingfile) + differencesArray = [ Name(ch) for ch in enc ] + differencesArray = [ 0 ] + differencesArray + fontdict.update({ + 'Encoding': { 'Type': Name('Encoding'), + 'Differences': differencesArray }, + }) + _, _, fullname, familyname, weight, italic_angle, fixed_pitch, \ + ul_position, ul_thickness = font.get_ps_font_info() + flags = 0 if fixed_pitch: flags |= 1 << 0 # fixed width if 0: flags |= 1 << 1 # TODO: serif - if 1: flags |= 1 << 2 # TODO: symbolic + if 1: flags |= 1 << 2 # TODO: symbolic (most TeX fonts are) else: flags |= 1 << 5 # non-symbolic if italic_angle: flags |= 1 << 6 # italic if 0: flags |= 1 << 16 # TODO: all caps @@ -598,33 +550,17 @@ 'ItalicAngle': italic_angle, 'Ascent': font.ascender, 'Descent': font.descender, - 'CapHeight': 1000, # default guess if missing from AFM file - 'XHeight': afmdata.get_xheight(), + 'CapHeight': 1000, # TODO: find this out + 'XHeight': 500, # TODO: this one too 'FontFile': fontfileObject, 'FontFamily': familyname, + 'StemV': 50, # TODO + # (see also revision 3874; but not all TeX distros have AFM files!) #'FontWeight': a number where 400 = Regular, 700 = Bold } - try: - descriptor['CapHeight'] = afmdata.get_capheight() - except KeyError: - pass - # StemV is obligatory in PDF font descriptors but optional in - # AFM files. The collection of AFM files in my TeX Live 2007 - # collection has values ranging from 22 to 219, with both - # median and mode 50, so if the AFM file is silent, I'm - # guessing 50. -JKS - StemV = afmdata.get_vertical_stem_width() - if StemV is None: StemV = 50 - descriptor['StemV'] = StemV - - # StemH is entirely optional: - StemH = afmdata.get_horizontal_stem_width() - if StemH is not None: - descriptor['StemH'] = StemH - self.writeObject(fontdictObject, fontdict) - self.writeObject(widthsObject, widths) + self.writeObject(widthsObject, fontinfo.widths) self.writeObject(fontdescObject, descriptor) t1font = type1font.Type1Font(filename) @@ -1470,16 +1406,13 @@ oldfont, seq = None, [] for x1, y1, dvifont, glyph, width in page.text: if dvifont != oldfont: - fontinfo = self.tex_font_mapping(dvifont.texname) - pdfname = self.file.fontName(fontinfo.filename) - if not fontinfo.afm: - matplotlib.verbose.report( - 'RendererPdf.draw_tex: No AFM file found for %s (%s)' \ - % (dvifont.texname, fontinfo.filename), - 'helpful') - self.file.fontInfo[pdfname] = Bunch( - encodingfile=fontinfo.encoding, - afmfile=fontinfo.afm) + psfont = self.tex_font_mapping(dvifont.texname) + pdfname = self.file.fontName(psfont.filename) + if self.file.fontInfo.get(pdfname, None) is None: + self.file.fontInfo[pdfname] = Bunch( + encodingfile=psfont.encoding, + widths=dvifont.widths, + dvifont=dvifont) seq += [['font', pdfname, dvifont.size]] oldfont = dvifont seq += [['text', x1, y1, [chr(glyph)], x1+width]] Modified: trunk/matplotlib/lib/matplotlib/dviread.py =================================================================== --- trunk/matplotlib/lib/matplotlib/dviread.py 2007-09-28 15:57:49 UTC (rev 3900) +++ trunk/matplotlib/lib/matplotlib/dviread.py 2007-09-30 20:08:50 UTC (rev 3901) @@ -84,7 +84,7 @@ e = 0 # zero depth else: # glyph x,y,font,g,w = elt - h = _mul2012(font._scale, font._tfm.height[g]) + h = _mul2012(font._scale, font._tfm.height[g]) e = _mul2012(font._scale, font._tfm.depth[g]) minx = min(minx, x) miny = min(miny, y - h) @@ -380,19 +380,21 @@ class DviFont(object): """ - Object that holds a font's texname and size and supports comparison. + Object that holds a font's texname and size, supports comparison, + and knows the widths of glyphs in the same units as the AFM file. There are also internal attributes (for use by dviread.py) that are _not_ used for comparison. The size is in Adobe points (converted from TeX points). """ - __slots__ = ('texname', 'size', '_scale', '_vf', '_tfm') + __slots__ = ('texname', 'size', 'widths', '_scale', '_vf', '_tfm') def __init__(self, scale, tfm, texname, vf): self._scale, self._tfm, self.texname, self._vf = \ scale, tfm, texname, vf - # TODO: would it make more sense to have the size in dpi units? self.size = scale * (72.0 / (72.27 * 2**16)) + self.widths = [ (1000*tfm.width.get(char, 0)) >> 20 + for char in range(0, max(tfm.width)) ] def __eq__(self, other): return self.__class__ == other.__class__ and \ @@ -402,6 +404,10 @@ return not self.__eq__(other) def _width_of(self, char): + """ + Width of char in dvi units. For internal use by dviread.py. + """ + width = self._tfm.width.get(char, None) if width is not None: return _mul2012(width, self._scale) @@ -598,7 +604,6 @@ fn, enc = result.filename, result.encoding if fn is not None and not fn.startswith('/'): result.filename = find_tex_file(fn) - result.afm = find_tex_file(fn[:-4] + '.afm') if enc is not None and not enc.startswith('/'): result.encoding = find_tex_file(result.encoding) return result This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jo...@us...> - 2007-09-28 15:57:52
|
Revision: 3900 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3900&view=rev Author: jouni Date: 2007-09-28 08:57:49 -0700 (Fri, 28 Sep 2007) Log Message: ----------- More debugging output when using TeX with the pdf backend Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py trunk/matplotlib/lib/matplotlib/dviread.py Modified: trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2007-09-28 15:50:01 UTC (rev 3899) +++ trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2007-09-28 15:57:49 UTC (rev 3900) @@ -1472,6 +1472,11 @@ if dvifont != oldfont: fontinfo = self.tex_font_mapping(dvifont.texname) pdfname = self.file.fontName(fontinfo.filename) + if not fontinfo.afm: + matplotlib.verbose.report( + 'RendererPdf.draw_tex: No AFM file found for %s (%s)' \ + % (dvifont.texname, fontinfo.filename), + 'helpful') self.file.fontInfo[pdfname] = Bunch( encodingfile=fontinfo.encoding, afmfile=fontinfo.afm) Modified: trunk/matplotlib/lib/matplotlib/dviread.py =================================================================== --- trunk/matplotlib/lib/matplotlib/dviread.py 2007-09-28 15:50:01 UTC (rev 3899) +++ trunk/matplotlib/lib/matplotlib/dviread.py 2007-09-28 15:57:49 UTC (rev 3900) @@ -734,6 +734,9 @@ result = pipe.readline().rstrip() pipe.close() + matplotlib.verbose.report('find_tex_file: %s -> %s' \ + % (filename, result), + 'debug') return result # With multiple text objects per figure (e.g. tick labels) we may end This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jo...@us...> - 2007-09-28 15:50:29
|
Revision: 3899 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3899&view=rev Author: jouni Date: 2007-09-28 08:50:01 -0700 (Fri, 28 Sep 2007) Log Message: ----------- Catch UnboundLocalError in checkdep_pdftops; it is raised if no output line of pdftops -v contains the word "version". Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/__init__.py Modified: trunk/matplotlib/lib/matplotlib/__init__.py =================================================================== --- trunk/matplotlib/lib/matplotlib/__init__.py 2007-09-28 12:41:08 UTC (rev 3898) +++ trunk/matplotlib/lib/matplotlib/__init__.py 2007-09-28 15:50:01 UTC (rev 3899) @@ -270,7 +270,7 @@ v = line.split()[-1] float(v) return v - except (IndexError, ValueError): + except (IndexError, ValueError, UnboundLocalError): return None def compare_versions(a, b): This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jd...@us...> - 2007-09-28 12:41:15
|
Revision: 3898 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3898&view=rev Author: jdh2358 Date: 2007-09-28 05:41:08 -0700 (Fri, 28 Sep 2007) Log Message: ----------- fixed some tick accessor bugs Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/axis.py trunk/matplotlib/lib/matplotlib/widgets.py Modified: trunk/matplotlib/lib/matplotlib/axis.py =================================================================== --- trunk/matplotlib/lib/matplotlib/axis.py 2007-09-26 14:08:12 UTC (rev 3897) +++ trunk/matplotlib/lib/matplotlib/axis.py 2007-09-28 12:41:08 UTC (rev 3898) @@ -519,8 +519,11 @@ def get_children(self): children = [self.label] - children.extend(self.majorTicks) - children.extend(self.minorTicks) + majorticks = self.get_major_ticks() + minorticks = self.get_minor_ticks() + + children.extend(majorticks) + children.extend(minorticks) return children def cla(self): @@ -643,7 +646,8 @@ def get_gridlines(self): 'Return the grid lines as a list of Line2D instance' - return silent_list('Line2D gridline', [tick.gridline for tick in self.majorTicks]) + ticks = self.get_major_ticks() + return silent_list('Line2D gridline', [tick.gridline for tick in ticks]) def get_label(self): 'Return the axis label as a Text instance' @@ -659,14 +663,16 @@ def get_ticklabels(self): 'Return a list of Text instances for ticklabels' - labels1 = [tick.label1 for tick in self.majorTicks if tick.label1On] - labels2 = [tick.label2 for tick in self.majorTicks if tick.label2On] + ticks = self.get_major_ticks() + labels1 = [tick.label1 for tick in ticks if tick.label1On] + labels2 = [tick.label2 for tick in ticks if tick.label2On] return silent_list('Text ticklabel', labels1+labels2) def get_ticklines(self): 'Return the ticklines lines as a list of Line2D instance' lines = [] - for tick in self.majorTicks: + ticks = self.get_major_ticks() + for tick in ticks: lines.append(tick.tick1line) lines.append(tick.tick2line) return silent_list('Line2D ticklines', lines) @@ -1081,9 +1087,10 @@ """ assert position == 'top' or position == 'bottom' or position == 'both' or position == 'default' - ticks = list(self.majorTicks) # a copy - ticks.extend( self.minorTicks ) + ticks = list( self.get_major_ticks() ) # a copy + ticks.extend( self.get_minor_ticks() ) + if position == 'top': for t in ticks: t.tick1On = False @@ -1277,8 +1284,8 @@ """ assert position == 'left' or position == 'right' or position == 'both' or position == 'default' - ticks = list(self.majorTicks) # a copy - ticks.extend( self.minorTicks ) + ticks = list( self.get_major_ticks() ) # a copy + ticks.extend( self.get_minor_ticks() ) if position == 'right': self.set_offset_position('right') Modified: trunk/matplotlib/lib/matplotlib/widgets.py =================================================================== --- trunk/matplotlib/lib/matplotlib/widgets.py 2007-09-26 14:08:12 UTC (rev 3897) +++ trunk/matplotlib/lib/matplotlib/widgets.py 2007-09-28 12:41:08 UTC (rev 3898) @@ -971,14 +971,14 @@ print ' endposition : (%f, %f)' % (erelease.xdata, erelease.ydata) print ' used button : ', eclick.button - def toggle_Selector(event): + def toggle_selector(event): print ' Key pressed.' - if event.key in ['Q', 'q'] and toggle_Selector.RS.active: + if event.key in ['Q', 'q'] and toggle_selector.RS.active: print ' RectangleSelector deactivated.' - toggle_Selector.RS.set_active(False) - if event.key in ['A', 'a'] and not toggle_Selector.RS.active: + toggle_selector.RS.set_active(False) + if event.key in ['A', 'a'] and not toggle_selector.RS.active: print ' RectangleSelector activated.' - toggle_Selector.RS.set_active(True) + toggle_selector.RS.set_active(True) x = arange(100)/(99.0) y = sin(x) @@ -986,8 +986,8 @@ ax = subplot(111) ax.plot(x,y) - toggle_Selector.RS = RectangleSelector(ax, onselect, drawtype='line') - connect('key_press_event', toggle_Selector) + toggle_selector.RS = RectangleSelector(ax, onselect, drawtype='line') + connect('key_press_event', toggle_selector) show() """ def __init__(self, ax, onselect, drawtype='box', 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 (Wed, 26 Sep 2007) 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-09-26 13:55:53
|
Revision: 3896 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3896&view=rev Author: mdboom Date: 2007-09-26 06:55:41 -0700 (Wed, 26 Sep 2007) Log Message: ----------- Merged revisions 3885-3895 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r3894 | mdboom | 2007-09-26 09:41:15 -0400 (Wed, 26 Sep 2007) | 3 lines Bugfix: Display exponents in tick values in the default font (not the default math font) ........ Modified Paths: -------------- branches/transforms/lib/matplotlib/mathtext.py branches/transforms/lib/matplotlib/ticker.py Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-3884 + /trunk/matplotlib:1-3895 Modified: branches/transforms/lib/matplotlib/mathtext.py =================================================================== --- branches/transforms/lib/matplotlib/mathtext.py 2007-09-26 13:53:53 UTC (rev 3895) +++ branches/transforms/lib/matplotlib/mathtext.py 2007-09-26 13:55:41 UTC (rev 3896) @@ -1855,7 +1855,7 @@ "tanh") fontname = oneOf("rm cal it tt sf bf") - latex2efont = oneOf("mathrm mathcal mathit mathtt mathsf mathbf") + latex2efont = oneOf("mathrm mathcal mathit mathtt mathsf mathbf mathdefault") space =(FollowedBy(bslash) + (Literal(r'\ ') Modified: branches/transforms/lib/matplotlib/ticker.py =================================================================== --- branches/transforms/lib/matplotlib/ticker.py 2007-09-26 13:53:53 UTC (rev 3895) +++ branches/transforms/lib/matplotlib/ticker.py 2007-09-26 13:55:41 UTC (rev 3896) @@ -300,9 +300,12 @@ sciNotStr = r'{\times}'+self.format_data(10**self.orderOfMagnitude) else: sciNotStr = u'\xd7'+'1e%d'% self.orderOfMagnitude - if self._useMathText or self._usetex: + if self._useMathText: + return ''.join(('$\mathdefault{',sciNotStr,offsetStr,'}$')) + elif self._usetex: return ''.join(('$',sciNotStr,offsetStr,'$')) - else: return ''.join((sciNotStr,offsetStr)) + else: + return ''.join((sciNotStr,offsetStr)) else: return '' def set_locs(self, locs): @@ -363,8 +366,11 @@ for loc in locs] sigfigs.sort() self.format = '%1.' + str(sigfigs[-1]) + 'f' - if self._usetex or self._useMathText: self.format = '$%s$'%self.format - + if self._usetex: + self.format = '$%s$' % self.format + elif self._useMathText: + self.format = '$\mathdefault{%s}$' % self.format + def pprint_val(self, x): xp = (x-self.offset)/10**self.orderOfMagnitude if npy.absolute(xp) < 1e-8: xp = 0 @@ -511,11 +517,13 @@ elif not isDecade: if usetex: s = r'$%d^{%.2f}$'% (b, fx) - else: s = '$%d^{%.2f}$'% (b, fx) + else: + s = '$\mathdefault{%d^{%.2f}}$'% (b, fx) else: if usetex: s = r'$%d^{%d}$'% (b, self.nearest_long(fx)) - else: s = r'$%d^{%d}$'% (b, self.nearest_long(fx)) + else: + s = r'$\mathdefault{%d^{%d}}$'% (b, self.nearest_long(fx)) return s 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 (Wed, 26 Sep 2007) 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 13:41:29
|
Revision: 3894 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3894&view=rev Author: mdboom Date: 2007-09-26 06:41:15 -0700 (Wed, 26 Sep 2007) Log Message: ----------- Bugfix: Display exponents in tick values in the default font (not the default math font) Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/mathtext.py trunk/matplotlib/lib/matplotlib/ticker.py Modified: trunk/matplotlib/lib/matplotlib/mathtext.py =================================================================== --- trunk/matplotlib/lib/matplotlib/mathtext.py 2007-09-26 12:29:05 UTC (rev 3893) +++ trunk/matplotlib/lib/matplotlib/mathtext.py 2007-09-26 13:41:15 UTC (rev 3894) @@ -1855,7 +1855,7 @@ "tanh") fontname = oneOf("rm cal it tt sf bf") - latex2efont = oneOf("mathrm mathcal mathit mathtt mathsf mathbf") + latex2efont = oneOf("mathrm mathcal mathit mathtt mathsf mathbf mathdefault") space =(FollowedBy(bslash) + (Literal(r'\ ') Modified: trunk/matplotlib/lib/matplotlib/ticker.py =================================================================== --- trunk/matplotlib/lib/matplotlib/ticker.py 2007-09-26 12:29:05 UTC (rev 3893) +++ trunk/matplotlib/lib/matplotlib/ticker.py 2007-09-26 13:41:15 UTC (rev 3894) @@ -332,9 +332,12 @@ sciNotStr = r'{\times}'+self.format_data(10**self.orderOfMagnitude) else: sciNotStr = u'\xd7'+'1e%d'% self.orderOfMagnitude - if self._useMathText or self._usetex: + if self._useMathText: + return ''.join(('$\mathdefault{',sciNotStr,offsetStr,'}$')) + elif self._usetex: return ''.join(('$',sciNotStr,offsetStr,'$')) - else: return ''.join((sciNotStr,offsetStr)) + else: + return ''.join((sciNotStr,offsetStr)) else: return '' def set_locs(self, locs): @@ -395,8 +398,11 @@ for loc in locs] sigfigs.sort() self.format = '%1.' + str(sigfigs[-1]) + 'f' - if self._usetex or self._useMathText: self.format = '$%s$'%self.format - + if self._usetex: + self.format = '$%s$' % self.format + elif self._useMathText: + self.format = '$\mathdefault{%s}$' % self.format + def pprint_val(self, x): xp = (x-self.offset)/10**self.orderOfMagnitude if npy.absolute(xp) < 1e-8: xp = 0 @@ -545,11 +551,13 @@ elif not isDecade: if usetex: s = r'$%d^{%.2f}$'% (b, fx) - else: s = '$%d^{%.2f}$'% (b, fx) + else: + s = '$\mathdefault{%d^{%.2f}}$'% (b, fx) else: if usetex: s = r'$%d^{%d}$'% (b, self.nearest_long(fx)) - else: s = r'$%d^{%d}$'% (b, self.nearest_long(fx)) + else: + s = r'$\mathdefault{%d^{%d}}$'% (b, self.nearest_long(fx)) return s This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-09-26 12:29:17
|
Revision: 3893 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3893&view=rev Author: mdboom Date: 2007-09-26 05:29:05 -0700 (Wed, 26 Sep 2007) Log Message: ----------- Committing simple_ploy_fps.py Added Paths: ----------- branches/transforms/examples/simple_plot_fps.py Added: branches/transforms/examples/simple_plot_fps.py =================================================================== --- branches/transforms/examples/simple_plot_fps.py (rev 0) +++ branches/transforms/examples/simple_plot_fps.py 2007-09-26 12:29:05 UTC (rev 3893) @@ -0,0 +1,32 @@ +#!/usr/bin/env python +""" +Example: simple line plot. +Show how to make and save a simple line plot with labels, title and grid +""" +from pylab import * + +plot([1,2]) +show() + +t = arange(0.0, 1.0+0.001, 0.001) +s = cos(2*2*pi*t) +plot(t, s, '-', lw=2) + +xlabel('time (s)') +ylabel('voltage (mV)') +title('About as simple as it gets, folks') +grid(True) + +#savefig('simple_plot.png') +#savefig('simple_plot') + +import time + +frames = 100.0 +t = time.clock() +ion() +for i in xrange(int(frames)): + part = i / frames + axis([0.0, 1.0 - part, -1.0 + part, 1.0 - part]) + show() +print "fps:", frames / (time.clock() - t) Property changes on: branches/transforms/examples/simple_plot_fps.py ___________________________________________________________________ Name: svn:executable + * 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 (Tue, 25 Sep 2007) 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: <js...@us...> - 2007-09-25 19:08:56
|
Revision: 3891 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3891&view=rev Author: jswhit Date: 2007-09-25 12:08:51 -0700 (Tue, 25 Sep 2007) Log Message: ----------- clarify satellite height units Modified Paths: -------------- trunk/toolkits/basemap/examples/geos_demo.py Modified: trunk/toolkits/basemap/examples/geos_demo.py =================================================================== --- trunk/toolkits/basemap/examples/geos_demo.py 2007-09-25 18:29:44 UTC (rev 3890) +++ trunk/toolkits/basemap/examples/geos_demo.py 2007-09-25 19:08:51 UTC (rev 3891) @@ -2,7 +2,7 @@ from pylab import title, show, arange # create Basemap instance for Geostationary (satellite view) projection. lon_0 = float(raw_input('enter reference longitude (lon_0):')) -h = float(raw_input('enter satellite height above equator (satellite_height):')) +h = float(raw_input('enter satellite height above equator in meters (satellite_height):')) m = Basemap(projection='geos',lon_0=lon_0,satellite_height=h,rsphere=(6378137.00,6356752.3142),) # plot land-sea mask. rgba_land = (0,255,0,255) # land green. 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 (Tue, 25 Sep 2007) 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 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 (Tue, 25 Sep 2007) 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: <js...@us...> - 2007-09-25 12:15:28
|
Revision: 3888 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3888&view=rev Author: jswhit Date: 2007-09-25 05:15:22 -0700 (Tue, 25 Sep 2007) Log Message: ----------- fix addcyclic Modified Paths: -------------- trunk/toolkits/basemap/Changelog Modified: trunk/toolkits/basemap/Changelog =================================================================== --- trunk/toolkits/basemap/Changelog 2007-09-25 12:14:28 UTC (rev 3887) +++ trunk/toolkits/basemap/Changelog 2007-09-25 12:15:22 UTC (rev 3888) @@ -1,4 +1,5 @@ -version 0.9.6 (svn revision 3878) +version 0.9.6 (svn revision 3888) + * fix addcyclic function so it handles masked arrays. * labelling of meridians and parallels now works with very small map regions (less than 0.2 degrees square). * Subregions of the globe may be specified with llcrnrlat, This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <js...@us...> - 2007-09-25 12:14:32
|
Revision: 3887 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3887&view=rev Author: jswhit Date: 2007-09-25 05:14:28 -0700 (Tue, 25 Sep 2007) Log Message: ----------- fix addcyclic so it can handle masked arrays Modified Paths: -------------- trunk/toolkits/basemap/lib/matplotlib/toolkits/basemap/basemap.py Modified: trunk/toolkits/basemap/lib/matplotlib/toolkits/basemap/basemap.py =================================================================== --- trunk/toolkits/basemap/lib/matplotlib/toolkits/basemap/basemap.py 2007-09-24 17:33:03 UTC (rev 3886) +++ trunk/toolkits/basemap/lib/matplotlib/toolkits/basemap/basemap.py 2007-09-25 12:14:28 UTC (rev 3887) @@ -2917,10 +2917,16 @@ """ nlats = arrin.shape[0] nlons = arrin.shape[1] - arrout = NX.zeros((nlats,nlons+1),arrin.dtype) + if hasattr(arrin,'mask'): + arrout = ma.zeros((nlats,nlons+1),arrin.dtype) + else: + arrout = NX.zeros((nlats,nlons+1),arrin.dtype) arrout[:,0:nlons] = arrin[:,:] arrout[:,nlons] = arrin[:,0] - lonsout = NX.zeros(nlons+1,lonsin.dtype) + if hasattr(lonsin,'mask'): + lonsout = ma.zeros(nlons+1,lonsin.dtype) + else: + lonsout = NX.zeros(nlons+1,lonsin.dtype) lonsout[0:nlons] = lonsin[:] lonsout[nlons] = lonsin[-1] + lonsin[1]-lonsin[0] return arrout,lonsout This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |