From: <as...@us...> - 2009-06-01 21:41:48
|
Revision: 7170 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=7170&view=rev Author: astraw Date: 2009-06-01 21:41:46 +0000 (Mon, 01 Jun 2009) Log Message: ----------- Spine is now derived from Patch Modified Paths: -------------- trunk/matplotlib/CHANGELOG trunk/matplotlib/examples/api/custom_projection_example.py trunk/matplotlib/examples/pylab_examples/spine_placement_demo.py trunk/matplotlib/lib/matplotlib/axes.py trunk/matplotlib/lib/matplotlib/projections/geo.py trunk/matplotlib/lib/matplotlib/projections/polar.py trunk/matplotlib/lib/matplotlib/spines.py Modified: trunk/matplotlib/CHANGELOG =================================================================== --- trunk/matplotlib/CHANGELOG 2009-06-01 21:41:31 UTC (rev 7169) +++ trunk/matplotlib/CHANGELOG 2009-06-01 21:41:46 UTC (rev 7170) @@ -1,3 +1,5 @@ +2009-06-01 Spine is now derived from Patch - ADS + 2009-06-01 use cbook.is_string_like() instead of isinstance() for spines - ADS 2009-06-01 cla() support for spines - ADS Modified: trunk/matplotlib/examples/api/custom_projection_example.py =================================================================== --- trunk/matplotlib/examples/api/custom_projection_example.py 2009-06-01 21:41:31 UTC (rev 7169) +++ trunk/matplotlib/examples/api/custom_projection_example.py 2009-06-01 21:41:46 UTC (rev 7170) @@ -237,7 +237,8 @@ return Circle((0.5, 0.5), 0.5) def _gen_axes_spines(self): - return {'hammer':mspines.Spine(self,'hammer',Circle((0.5, 0.5), 0.5))} + return {'hammer':mspines.Spine.circular_spine(self, + (0.5, 0.5), 0.5)} # Prevent the user from applying scales to one or both of the # axes. In this particular case, scaling the axes wouldn't make Modified: trunk/matplotlib/examples/pylab_examples/spine_placement_demo.py =================================================================== --- trunk/matplotlib/examples/pylab_examples/spine_placement_demo.py 2009-06-01 21:41:31 UTC (rev 7169) +++ trunk/matplotlib/examples/pylab_examples/spine_placement_demo.py 2009-06-01 21:41:46 UTC (rev 7170) @@ -12,7 +12,7 @@ if loc in ['left','bottom']: spine.set_position(('outward',10)) # outward by 10 points elif loc in ['right','top']: - spine.set_color('none') # don't draw spine + spine.set_edgecolor('none') # don't draw spine else: raise ValueError('unknown spine location: %s'%loc) @@ -34,9 +34,9 @@ ax.set_title('centered spines') ax.plot(x,y) ax.spines['left'].set_position('center') -ax.spines['right'].set_color('none') +ax.spines['right'].set_edgecolor('none') ax.spines['bottom'].set_position('center') -ax.spines['top'].set_color('none') +ax.spines['top'].set_edgecolor('none') ax.xaxis.set_ticks_position('bottom') ax.yaxis.set_ticks_position('left') @@ -44,9 +44,9 @@ ax.set_title('zeroed spines') ax.plot(x,y) ax.spines['left'].set_position('zero') -ax.spines['right'].set_color('none') +ax.spines['right'].set_edgecolor('none') ax.spines['bottom'].set_position('zero') -ax.spines['top'].set_color('none') +ax.spines['top'].set_edgecolor('none') ax.xaxis.set_ticks_position('bottom') ax.yaxis.set_ticks_position('left') @@ -54,9 +54,9 @@ ax.set_title('spines at axes (0.6, 0.1)') ax.plot(x,y) ax.spines['left'].set_position(('axes',0.6)) -ax.spines['right'].set_color('none') +ax.spines['right'].set_edgecolor('none') ax.spines['bottom'].set_position(('axes',0.1)) -ax.spines['top'].set_color('none') +ax.spines['top'].set_edgecolor('none') ax.xaxis.set_ticks_position('bottom') ax.yaxis.set_ticks_position('left') @@ -64,9 +64,9 @@ ax.set_title('spines at data (1,2)') ax.plot(x,y) ax.spines['left'].set_position(('data',1)) -ax.spines['right'].set_color('none') +ax.spines['right'].set_edgecolor('none') ax.spines['bottom'].set_position(('data',2)) -ax.spines['top'].set_color('none') +ax.spines['top'].set_edgecolor('none') ax.xaxis.set_ticks_position('bottom') ax.yaxis.set_ticks_position('left') @@ -77,7 +77,7 @@ if loc in spines: spine.set_position(('outward',10)) # outward by 10 points else: - spine.set_color('none') # don't draw spine + spine.set_edgecolor('none') # don't draw spine # turn off ticks where there is no spine if 'left' in spines: Modified: trunk/matplotlib/lib/matplotlib/axes.py =================================================================== --- trunk/matplotlib/lib/matplotlib/axes.py 2009-06-01 21:41:31 UTC (rev 7169) +++ trunk/matplotlib/lib/matplotlib/axes.py 2009-06-01 21:41:46 UTC (rev 7170) @@ -891,14 +891,10 @@ Intended to be overridden by new projection types. """ return { - 'left':mspines.Spine(self,'left', - mlines.Line2D((0.0, 0.0), (0.0, 1.0))), - 'right':mspines.Spine(self,'right', - mlines.Line2D((1.0, 1.0), (0.0, 1.0))), - 'bottom':mspines.Spine(self,'bottom', - mlines.Line2D((0.0, 1.0), (0.0, 0.0))), - 'top':mspines.Spine(self,'top', - mlines.Line2D((0.0, 1.0), (1.0, 1.0))), + 'left':mspines.Spine.linear_spine(self,'left'), + 'right':mspines.Spine.linear_spine(self,'right'), + 'bottom':mspines.Spine.linear_spine(self,'bottom'), + 'top':mspines.Spine.linear_spine(self,'top'), } def cla(self): Modified: trunk/matplotlib/lib/matplotlib/projections/geo.py =================================================================== --- trunk/matplotlib/lib/matplotlib/projections/geo.py 2009-06-01 21:41:31 UTC (rev 7169) +++ trunk/matplotlib/lib/matplotlib/projections/geo.py 2009-06-01 21:41:46 UTC (rev 7170) @@ -145,7 +145,8 @@ return Circle((0.5, 0.5), 0.5) def _gen_axes_spines(self): - return {'geo':mspines.Spine(self,'geo',Circle((0.5, 0.5), 0.5))} + return {'geo':mspines.Spine.circular_spine(self, + (0.5, 0.5), 0.5)} def set_yscale(self, *args, **kwargs): if args[0] != 'linear': Modified: trunk/matplotlib/lib/matplotlib/projections/polar.py =================================================================== --- trunk/matplotlib/lib/matplotlib/projections/polar.py 2009-06-01 21:41:31 UTC (rev 7169) +++ trunk/matplotlib/lib/matplotlib/projections/polar.py 2009-06-01 21:41:46 UTC (rev 7170) @@ -294,7 +294,8 @@ return Circle((0.5, 0.5), 0.5) def _gen_axes_spines(self): - return {'polar':mspines.Spine(self,'polar',Circle((0.5, 0.5), 0.5))} + return {'polar':mspines.Spine.circular_spine(self, + (0.5, 0.5), 0.5)} def set_rmax(self, rmax): self.viewLim.y0 = 0 Modified: trunk/matplotlib/lib/matplotlib/spines.py =================================================================== --- trunk/matplotlib/lib/matplotlib/spines.py 2009-06-01 21:41:31 UTC (rev 7169) +++ trunk/matplotlib/lib/matplotlib/spines.py 2009-06-01 21:41:46 UTC (rev 7170) @@ -8,10 +8,11 @@ import matplotlib.transforms as mtransforms import matplotlib.lines as mlines import matplotlib.patches as mpatches +import matplotlib.path as mpath import matplotlib.cbook as cbook import warnings -class Spine(martist.Artist): +class Spine(mpatches.Patch): """an axis spine -- the line noting the data area boundaries Spines are the lines connecting the axis tick marks and noting the @@ -20,39 +21,98 @@ for more information. The default position is ``('outward',0)``. + + Spines are subclasses of class:`~matplotlib.patches.Patch`, and + inherit much of their behavior. + + Spines draw a line or a circle, depending if + function:`~matplotlib.spines.Spine.set_patch_line` or + function:`~matplotlib.spines.Spine.set_patch_circle` has been + called. Line-like is the default. + """ def __str__(self): return "Spine" - def __init__(self,axes,spine_type,artist): + def __init__(self,axes,spine_type,path,**kwargs): """ - *axes* : the Axes instance containing the spine - *spine_type* : a string specifying the spine type - - *artist* : the artist instance used to draw the spine + - *path* : the path instance used to draw the spine + + Valid kwargs are: + %(Patch)s """ - martist.Artist.__init__(self) + super(Spine,self).__init__(**kwargs) self.axes = axes self.set_figure(self.axes.figure) self.spine_type = spine_type - self.artist = artist - self.color = rcParams['axes.edgecolor'] + self.set_facecolor('none') + self.set_edgecolor( rcParams['axes.edgecolor'] ) + self.set_linewidth(rcParams['axes.linewidth']) self.axis = None - if isinstance(self.artist,mlines.Line2D): - self.artist.set_color(self.color) - self.artist.set_linewidth(rcParams['axes.linewidth']) - elif isinstance(self.artist,mpatches.Patch): - self.artist.set_facecolor('none') - self.artist.set_edgecolor(self.color) - self.artist.set_linewidth(rcParams['axes.linewidth']) - self.artist.set_zorder(2.5) - self.artist.set_transform(self.axes.transAxes) # default transform + self.set_zorder(2.5) + self.set_transform(self.axes.transAxes) # default transform # Defer initial position determination. (Not much support for # non-rectangular axes is currently implemented, and this lets # them pass through the spines machinery without errors.) self._position = None + assert isinstance(path,matplotlib.path.Path) + self._path = path + # To support drawing both linear and circular spines, this + # class implements Patch behavior two ways. If + # self._patch_type == 'line', behave like a mpatches.PathPatch + # instance. If self._patch_type == 'circle', behave like a + # mpatches.Ellipse instance. + self._patch_type = 'line' + + # Behavior copied from mpatches.Ellipse: + # Note: This cannot be calculated until this is added to an Axes + self._patch_transform = mtransforms.IdentityTransform() + __init__.__doc__ = cbook.dedent(__init__.__doc__) % martist.kwdocd + + def set_patch_circle(self,center,radius): + """set the spine to be circular""" + self._patch_type = 'circle' + self._center = center + self._width = radius*2 + self._height = radius*2 + self._angle = 0 + + def set_patch_line(self): + """set the spine to be linear""" + self._patch_type = 'line' + + # Behavior copied from mpatches.Ellipse: + def _recompute_transform(self): + """NOTE: This cannot be called until after this has been added + to an Axes, otherwise unit conversion will fail. This + maxes it very important to call the accessor method and + not directly access the transformation member variable. + """ + assert self._patch_type == 'circle' + center = (self.convert_xunits(self._center[0]), + self.convert_yunits(self._center[1])) + width = self.convert_xunits(self._width) + height = self.convert_yunits(self._height) + self._patch_transform = mtransforms.Affine2D() \ + .scale(width * 0.5, height * 0.5) \ + .rotate_deg(self._angle) \ + .translate(*center) + + def get_patch_transform(self): + if self._patch_type == 'circle': + self._recompute_transform() + return self._patch_transform + else: + return super(Spine,self).get_patch_transform() + + def get_path(self): + return self._path + def _ensure_position_is_set(self): if self._position is None: # default position @@ -76,14 +136,6 @@ if self.axis is not None: self.axis.cla() - @allow_rasterization - def draw(self,renderer): - "draw everything that belongs to the spine" - if self.color=='none': - # don't draw invisible spines - return - self.artist.draw(renderer) - def _calc_offset_transform(self): """calculate the offset transform performed by the spine""" self._ensure_position_is_set() @@ -176,7 +228,7 @@ elif self.spine_type in ['bottom','top']: t2 = mtransforms.blended_transform_factory(self.axes.transAxes, t) - self.artist.set_transform(t2) + self.set_transform(t2) if self.axis is not None: self.axis.cla() @@ -223,17 +275,31 @@ else: raise ValueError("unknown spine_transform type: %s"%what) - def set_color(self,value): - """set the color of the spine artist + @classmethod + def linear_spine(cls, axes, spine_type, **kwargs): + """ + (staticmethod) Returns a linear :class:`Spine`. + """ + if spine_type=='left': + path = mpath.Path([(0.0, 0.0), (0.0, 1.0)]) + elif spine_type=='right': + path = mpath.Path([(1.0, 0.0), (1.0, 1.0)]) + elif spine_type=='bottom': + path = mpath.Path([(0.0, 0.0), (1.0, 0.0)]) + elif spine_type=='top': + path = mpath.Path([(0.0, 1.0), (1.0, 1.0)]) + else: + raise ValueError('unable to make path for spine "%s"'%spine_type) + result = cls(axes,spine_type,path,**kwargs) + return result - Note: a value of 'none' will cause the artist not to be drawn. + @classmethod + def circular_spine(cls,axes,center,radius,**kwargs): """ - self.color = value - if isinstance(self.artist,mlines.Line2D): - self.artist.set_color(self.color) - elif isinstance(self.artist,mpatches.Patch): - self.artist.set_edgecolor(self.color) - - def get_color(self): - """get the color of the spine artist""" - return self.color + (staticmethod) Returns a circular :class:`Spine`. + """ + path = mpath.Path.unit_circle() + spine_type = 'circle' + result = cls(axes,spine_type,path,**kwargs) + result.set_patch_circle(center,radius) + return result This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |