|
18 | 18 | from collections import RegularPolyCollection, PolyCollection, LineCollection, QuadMesh
|
19 | 19 | from colors import colorConverter, normalize, Colormap, LinearSegmentedColormap, looks_like_color
|
20 | 20 | import cm
|
21 |
| -#from cm import ColormapJet, Grayscale, ScalarMappable |
22 | 21 | from cm import ScalarMappable
|
23 | 22 | from contour import ContourSet
|
24 | 23 | import _image
|
@@ -370,8 +369,9 @@ def __init__(self, fig, rect,
|
370 | 369 | self._cachedRenderer = None
|
371 | 370 | self.set_navigate(True)
|
372 | 371 |
|
373 |
| - # aspect ration atribute, and original position |
374 |
| - self._aspect = 'normal' |
| 372 | + # aspect ratio atribute, and original position |
| 373 | + self.set_aspect('auto') |
| 374 | + self.set_aspect_adjusts('position') |
375 | 375 | self._originalPosition = self.get_position()
|
376 | 376 |
|
377 | 377 | if len(kwargs): setp(self, **kwargs)
|
@@ -816,8 +816,6 @@ def autoscale_view(self):
|
816 | 816 | locator = self.yaxis.get_major_locator()
|
817 | 817 | self.set_ylim(locator.autoscale())
|
818 | 818 |
|
819 |
| - if self._aspect == 'equal': self.set_aspect('equal') |
820 |
| - |
821 | 819 | def quiver(self, U, V, *args, **kwargs ):
|
822 | 820 | """
|
823 | 821 | QUIVER( X, Y, U, V )
|
@@ -1406,6 +1404,7 @@ def draw(self, renderer=None, inframe=False):
|
1406 | 1404 | if not self.get_visible(): return
|
1407 | 1405 | renderer.open_group('axes')
|
1408 | 1406 |
|
| 1407 | + self.apply_aspect() |
1409 | 1408 | try: self.transData.freeze() # eval the lazy objects
|
1410 | 1409 | except ValueError:
|
1411 | 1410 | print >> sys.stderr, 'data freeze value error', self.get_position(), self.dataLim.get_bounds(), self.viewLim.get_bounds()
|
@@ -2442,7 +2441,7 @@ def pcolormesh(self, *args, **kwargs):
|
2442 | 2441 | showedges = 1
|
2443 | 2442 | else:
|
2444 | 2443 | showedges = 0
|
2445 |
| - |
| 2444 | + |
2446 | 2445 | collection = QuadMesh(Ny - 1, Nx - 1, coords, showedges)
|
2447 | 2446 | collection.set_alpha(alpha)
|
2448 | 2447 | collection.set_array(C)
|
@@ -2969,7 +2968,7 @@ def scatter(self, x, y, s=20, c='b', marker='o', cmap=None, norm=None,
|
2969 | 2968 | faceted=True,
|
2970 | 2969 | **kwargs):
|
2971 | 2970 | """
|
2972 |
| - SCATTER(x, y, s=20, c='b', marker='o', cmap=None, norm=None, |
| 2971 | + SCATTER(x, y, s=20, c='b', marker='o', cmap=None, norm=None, |
2973 | 2972 | vmin=None, vmax=None, alpha=1.0, linewidths=None,
|
2974 | 2973 | faceted=True, **kwargs)
|
2975 | 2974 | Supported function signatures:
|
@@ -3344,7 +3343,7 @@ def set_xscale(self, value, basex = 10, subsx=None):
|
3344 | 3343 | * subsx: the location of the minor ticks; None defaults to autosubs,
|
3345 | 3344 | which depend on the number of decades in the plot
|
3346 | 3345 |
|
3347 |
| - ACCEPTS: str |
| 3346 | + ACCEPTS: ['log' | 'linear' ] |
3348 | 3347 | """
|
3349 | 3348 |
|
3350 | 3349 | #if subsx is None: subsx = range(2, basex)
|
@@ -3466,7 +3465,7 @@ def set_yscale(self, value, basey=10, subsy=None):
|
3466 | 3465 | * subsy: the location of the minor ticks; None are the default
|
3467 | 3466 | is to autosub
|
3468 | 3467 |
|
3469 |
| - ACCEPTS: str |
| 3468 | + ACCEPTS: ['log' | 'linear'] |
3470 | 3469 | """
|
3471 | 3470 |
|
3472 | 3471 | #if subsy is None: subsy = range(2, basey)
|
@@ -3942,71 +3941,124 @@ def dist(a):
|
3942 | 3941 | elif among is None:
|
3943 | 3942 | pass
|
3944 | 3943 | else:
|
3945 |
| - raise ValueError('among mut be callable or iterable') |
| 3944 | + raise ValueError('among must be callable or iterable') |
3946 | 3945 | if not len(artists): return None
|
3947 | 3946 | ds = [ (dist(a),a) for a in artists]
|
3948 | 3947 | ds.sort()
|
3949 | 3948 | return ds[0][1]
|
3950 | 3949 |
|
3951 |
| - def set_aspect(self,aspect='normal',fixLimits=False): |
| 3950 | + def set_aspect(self, aspect='auto', fixLimits=None, |
| 3951 | + aspect_adjusts='position'): |
| 3952 | + """ |
| 3953 | + aspect: |
| 3954 | + 'auto' - automatic; fill position rectangle with data |
| 3955 | + 'normal' - same as 'auto'; deprecated |
| 3956 | + 'equal' - same scaling from data to plot units for x and y |
| 3957 | + A - a circle will be stretched such that the height |
| 3958 | + is A times the width. aspect=1 is the same as |
| 3959 | + aspect='equal'. |
| 3960 | +
|
| 3961 | + aspect_adjusts: |
| 3962 | + 'position' - change width or height of bounding rectangle; |
| 3963 | + keep it centered. |
| 3964 | + 'box_size' - as above, but anchored to lower left |
| 3965 | + 'datalim' - change xlim or ylim |
| 3966 | +
|
| 3967 | + fixLimits: deprecated; False is aspect_adjusts='datalim'; |
| 3968 | + True is aspect_adjusts='position' |
| 3969 | +
|
| 3970 | + ACCEPTS: ['auto' | 'equal' | aspect_ratio] |
3952 | 3971 | """
|
3953 |
| - Set aspect to 'normal' or 'equal' |
3954 |
| - 'normal' means matplotlib determines aspect ratio |
3955 |
| - 'equal' means scale on x and y axes will be set equal such that circle looks like circle |
3956 |
| - In future we may want to add a number as input to have a certain aspect ratio, |
3957 |
| - such as vertical scale exagerrated by 2. |
| 3972 | + if aspect in ('normal', 'auto'): |
| 3973 | + self._aspect = 'auto' |
| 3974 | + elif aspect == 'equal': |
| 3975 | + self._aspect = 'equal' |
| 3976 | + else: |
| 3977 | + self._aspect = float(aspect) # raise ValueError if necessary |
3958 | 3978 |
|
3959 |
| - fixLimits: False means data limits will be changed, but height and widths of axes preserved. |
3960 |
| - True means height or width will be changed, but data limits preserved |
| 3979 | + if fixLimits is not None: |
| 3980 | + if not fixLimits: aspect_adjusts = 'datalim' |
| 3981 | + if aspect_adjusts in ('position', 'box_size', 'datalim'): |
| 3982 | + self._aspect_adjusts = aspect_adjusts |
| 3983 | + else: |
| 3984 | + raise ValueError( |
| 3985 | + 'aspect_adjusts must be "position", "box_size", or "datalim"') |
3961 | 3986 |
|
3962 |
| - ACCEPTS: str, boolean |
| 3987 | + def set_aspect_adjusts(self, aspect_adjusts = 'position'): |
3963 | 3988 | """
|
| 3989 | + Must be called after set_aspect. |
| 3990 | +
|
| 3991 | + ACCEPTS: ['position' | 'box_size' | 'datalim'] |
| 3992 | + """ |
| 3993 | + if aspect_adjusts in ('position', 'box_size', 'datalim'): |
| 3994 | + self._aspect_adjusts = aspect_adjusts |
| 3995 | + else: |
| 3996 | + raise ValueError( |
| 3997 | + 'argument must be "position", "box_size", or "datalim"') |
| 3998 | + |
3964 | 3999 |
|
3965 |
| - self._aspect = aspect |
3966 |
| - if self._aspect == 'normal': |
| 4000 | + def apply_aspect(self): |
| 4001 | + ''' |
| 4002 | + Use self._aspect and self._aspect_adjusts to modify the |
| 4003 | + axes box or the view limits. |
| 4004 | + ''' |
| 4005 | + |
| 4006 | + if self._aspect == 'auto': |
3967 | 4007 | self.set_position( self._originalPosition )
|
3968 |
| - elif self._aspect == 'equal' or self._aspect == 'scaled': |
3969 |
| - figW,figH = self.get_figure().get_size_inches() |
3970 |
| - xmin,xmax = self.get_xlim() |
3971 |
| - xsize = math.fabs(xmax-xmin) |
3972 |
| - ymin,ymax = self.get_ylim() |
3973 |
| - ysize = math.fabs(ymax-ymin) |
3974 |
| - if fixLimits: # Change size of axes |
3975 |
| - l,b,w,h = self._originalPosition # Always start from original position |
3976 |
| - axW = w * figW; axH = h * figH |
3977 |
| - if xsize / axW > ysize / axH: # y axis too long |
3978 |
| - axH = axW * ysize / xsize |
3979 |
| - if self._aspect == 'equal': |
3980 |
| - axc = b + 0.5 * h |
3981 |
| - h = axH / figH; b = axc - 0.5 * h |
3982 |
| - elif self._aspect == 'scaled': |
3983 |
| - h = axH / figH |
3984 |
| - else: # x axis too long |
3985 |
| - axW = axH * xsize / ysize |
3986 |
| - if self._aspect == 'equal': |
3987 |
| - axc = l + 0.5 * w |
3988 |
| - w = axW / figW; l = axc - 0.5 * w |
3989 |
| - elif self._aspect == 'scaled': |
3990 |
| - w = axW / figW |
3991 |
| - self.set_position( (l,b,w,h) ) |
3992 |
| - else: # Change limits on axes |
3993 |
| - l,b,w,h = self.get_position() # Keep size of subplot |
3994 |
| - axW = w * figW; axH = h * figH |
3995 |
| - if xsize / axW > ysize / axH: # y limits too narrow |
3996 |
| - dely = axH * xsize / axW |
3997 |
| - yc = 0.5 * ( ymin + ymax ) |
3998 |
| - ymin = yc - 0.5*dely; ymax = yc + 0.5*dely |
3999 |
| - self.set_ylim( ymin, ymax ) |
4000 |
| - else: |
4001 |
| - delx = axW * ysize / axH |
4002 |
| - xc = 0.5 * ( xmin + xmax ) |
4003 |
| - xmin = xc - 0.5*delx; xmax = xc + 0.5*delx |
4004 |
| - self.set_xlim( xmin, xmax ) |
| 4008 | + return |
| 4009 | + |
| 4010 | + if self._aspect == 'equal': |
| 4011 | + A = 1 |
| 4012 | + else: |
| 4013 | + A = self._aspect |
| 4014 | + |
| 4015 | + figW,figH = self.get_figure().get_size_inches() |
| 4016 | + fig_aspect = figH/figW |
| 4017 | + xmin,xmax = self.get_xlim() |
| 4018 | + xsize = math.fabs(xmax-xmin) |
| 4019 | + ymin,ymax = self.get_ylim() |
| 4020 | + ysize = math.fabs(ymax-ymin) |
| 4021 | + l,b,w,h = self._originalPosition |
| 4022 | + if self._aspect_adjusts in ('position', 'box_size'): |
| 4023 | + data_ratio = ysize/xsize |
| 4024 | + box_aspect = A * data_ratio |
| 4025 | + H = w * box_aspect/fig_aspect |
| 4026 | + if H <= h: |
| 4027 | + W = w |
| 4028 | + else: |
| 4029 | + W = h * fig_aspect/box_aspect |
| 4030 | + H = h |
| 4031 | + if self._aspect_adjusts == 'position': |
| 4032 | + L = l + 0.5 * (w-W) |
| 4033 | + B = b + 0.5 * (h-H) |
| 4034 | + else: |
| 4035 | + L,B = l,b |
| 4036 | + self.set_position((L,B,W,H)) |
| 4037 | + return |
| 4038 | + |
| 4039 | + self.autoscale_view() |
| 4040 | + xmin,xmax = self.get_xlim() |
| 4041 | + xsize = math.fabs(xmax-xmin) |
| 4042 | + ymin,ymax = self.get_ylim() |
| 4043 | + ysize = math.fabs(ymax-ymin) |
| 4044 | + box_aspect = fig_aspect * (h/w) |
| 4045 | + data_ratio = box_aspect / A |
| 4046 | + Ysize = data_ratio * xsize |
| 4047 | + if Ysize > ysize: |
| 4048 | + dy = 0.5 * (Ysize - ysize) |
| 4049 | + self.set_ylim((ymin-dy, ymax+dy)) |
| 4050 | + return |
| 4051 | + |
| 4052 | + Xsize = ysize / data_ratio |
| 4053 | + if Xsize > xsize: |
| 4054 | + dx = 0.5 * (Xsize - xsize) |
| 4055 | + self.set_xlim((xmin-dx, xmax+dx)) |
4005 | 4056 |
|
4006 | 4057 | def get_aspect(self):
|
4007 |
| - """Get the aspect 'normal' or 'equal' """ |
4008 | 4058 | return self._aspect
|
4009 | 4059 |
|
| 4060 | + def get_aspect_adjusts(self): |
| 4061 | + return self._aspect_adjusts |
4010 | 4062 |
|
4011 | 4063 | class SubplotBase:
|
4012 | 4064 | """
|
|
0 commit comments