Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Autoscaling and limits in mplot3d. #1289

Merged
merged 4 commits into from

3 participants

@WeatherGod
Collaborator

Due to time constraints in releasing v1.2.0, I would understand if this doesn't make it in for the release.

  • Fixes improper setting of x,y,z limits not turning off autoscaling
    • Adds units support to z-axis
    • Adds shared axis support for z-axis
    • Closes #783
@WeatherGod WeatherGod Autoscaling and limits in mplot3d.
    * Fixes improper setting of x,y,z limits not turning off autoscaling
    * Adds units support to z-axis
    * Adds shared axis support for z-axis
    * Closes #783
e76fd7f
lib/mpl_toolkits/mplot3d/axes3d.py
@@ -831,7 +1021,7 @@ def cla(self):
self.zaxis.cla()
# TODO: Support sharez
- self._sharez = None
+ #self._sharez = None
@dmcdougall Collaborator

If z-axis sharing is supported, why not just remove these three lines?

@WeatherGod Collaborator

Whoops, I thought I got all the cruft. I will take care of that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@dmcdougall
Collaborator

Does this suffer from the problems reported in #1110? If so, #1145 fixed it for the 2D case. Maybe it's worth taking a look at the diff there?

@WeatherGod
Collaborator

Axes3D can't do twinx/y yet because of the way the axis and axis ticks and labels are drawn. Support for that will have to come much further down the road.

@dmcdougall
Collaborator

Sweet. Cheers for clarification.

@pelson
Collaborator

My biggest concern with mplot3d in general is that I don't think there are any tests? At the very least, would you be willing to add a simple test case for this change?

@WeatherGod
Collaborator

Oh, I whole-heartedly agree that one of mplot3d's main problems is the lack of tests. I have been putting off making such tests because I have never been satisfied with the appearance of the figures. What I do whenever I make an invasive change like this is that I run all of the mplot3d examples (plus others I have) and make sure that they still produce expected results.

My one remaining hurdle I have before I am really willing to sit down and create baseline images is getting the 3d axes to take up a significantly larger portion of the subaxes. Right now, everything looks crammed. That should be the last major visual change for mplot3d toolkit. Unfortunately, it is not quite possible to do this, although some changes that have happened over the summer should get us most of the way there.

@WeatherGod
Collaborator

Now that v1.2.0 is out, I want to merge this bugfix into the maintenance branch and master. Objections?

@dmcdougall
Collaborator

My feeling is that this should be merged, but just into master. It's not entirely a bugfix, it adds support for things that weren't previously supported.

@WeatherGod
Collaborator
@dmcdougall
Collaborator

@WeatherGod Alright. I'd like to play with it first though. I haven't done that yet.

@dmcdougall
Collaborator

@WeatherGod Tried this out -- it seems to behave like the 2D case for the example in #783. I haven't tried the units support.

How does everyone else feel about this going into the v1.2.x branch?

lib/mpl_toolkits/mplot3d/axes3d.py
@@ -112,6 +124,44 @@ def set_axis_off(self):
def set_axis_on(self):
self._axis3don = True
+ def have_units(self):
+ 'Return *True* if units are set on the *x*, *y*, or *z* axes'
@dmcdougall Collaborator

Is there any reason you didn't make this a """ docstring?

@WeatherGod Collaborator

Most of the PEP8 violations here are a result of my copying and pasting from axes.py. Thanks for catching these and I will fix them all (as well as do PEP8 work for mplot3d in a separate PR).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/mpl_toolkits/mplot3d/axes3d.py
@@ -112,6 +124,44 @@ def set_axis_off(self):
def set_axis_on(self):
self._axis3don = True
+ def have_units(self):
+ 'Return *True* if units are set on the *x*, *y*, or *z* axes'
+ return (self.xaxis.have_units() or self.yaxis.have_units() or
+ self.zaxis.have_units())
+
+ def convert_zunits(self, z):
+ """For artists in an axes, if the zaxis has units support,
@dmcdougall Collaborator

Should the For artists... part start on a new line?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/mpl_toolkits/mplot3d/axes3d.py
((19 lines not shown))
+ """
+ Look for unit *kwargs* and update the axis instances as necessary
+ """
+ Axes._process_unit_info(self, xdata=xdata, ydata=ydata, kwargs=kwargs)
+
+ if self.xaxis is None or self.yaxis is None or self.zaxis is None:
+ return
+
+ if zdata is not None:
+ # we only need to update if there is nothing set yet.
+ if not self.zaxis.have_units():
+ self.zaxis.update_units(xdata)
+
+ # process kwargs 2nd since these will override default units
+ if kwargs is not None:
+ zunits = kwargs.pop( 'zunits', self.zaxis.units)
@dmcdougall Collaborator

There's a stray space between ( and '.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/mpl_toolkits/mplot3d/axes3d.py
((20 lines not shown))
+ Look for unit *kwargs* and update the axis instances as necessary
+ """
+ Axes._process_unit_info(self, xdata=xdata, ydata=ydata, kwargs=kwargs)
+
+ if self.xaxis is None or self.yaxis is None or self.zaxis is None:
+ return
+
+ if zdata is not None:
+ # we only need to update if there is nothing set yet.
+ if not self.zaxis.have_units():
+ self.zaxis.update_units(xdata)
+
+ # process kwargs 2nd since these will override default units
+ if kwargs is not None:
+ zunits = kwargs.pop( 'zunits', self.zaxis.units)
+ if zunits!=self.zaxis.units:
@dmcdougall Collaborator

Could you put spaces around !=?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@dmcdougall dmcdougall commented on the diff
lib/mpl_toolkits/mplot3d/axes3d.py
@@ -407,22 +459,17 @@ def autoscale_view(self, tight=None, scalex=True, scaley=True,
.. versionchanged :: 1.1.0
Function signature was changed to better match the 2D version.
- *tight* is now explicitly a kwarg and placed first. However,
- it currently does not do anything.
- """
+ *tight* is now explicitly a kwarg and placed first.
@dmcdougall Collaborator

I thought it didn't matter where kwargs were placed. Am I not understanding something?

@WeatherGod Collaborator

IIRC, the issue was that originally this function had **kwargs instead of explicit kwarg variables. The call signature did not match that from the 2d axes equivalent function. In v1.1.x, I fixed this issue.

@dmcdougall Collaborator

@WeatherGod To clarify, you're going to address the PEP8 issues here (along with the rest of the mplot3d module) in a different pull request?

@WeatherGod Collaborator

Completely missed this comment. I will update this PR to be PEP8 compliant, but then address the remaining PEP8 issues in mplot3d separately. In other words, I don't want to introduce new code with bad style. Fixes forthcoming.

@dmcdougall Collaborator

Thanks :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/mpl_toolkits/mplot3d/axes3d.py
((11 lines not shown))
'''
- # TODO: Add compatibility for 'left' and 'right'
- # TODO: support 'emit' and 'auto'
- lims = self._determine_lims(*args, **kwargs)
- self.xy_viewLim.intervalx = lims
- return lims
+ if 'xmin' in kw:
+ left = kw.pop('xmin')
+ if 'xmax' in kw:
+ right = kw.pop('xmax')
+ if kw:
+ raise ValueError("unrecognized kwargs: %s" % kw.keys())
+
+ if right is None and iterable(left):
+ left,right = left
@dmcdougall Collaborator

Could you put a space after the comma?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/mpl_toolkits/mplot3d/axes3d.py
((19 lines not shown))
+ if 'xmax' in kw:
+ right = kw.pop('xmax')
+ if kw:
+ raise ValueError("unrecognized kwargs: %s" % kw.keys())
+
+ if right is None and iterable(left):
+ left,right = left
+
+ self._process_unit_info(xdata=(left, right))
+ if left is not None:
+ left = self.convert_xunits(left)
+ if right is not None:
+ right = self.convert_xunits(right)
+
+ old_left, old_right = self.get_xlim()
+ if left is None: left = old_left
@dmcdougall Collaborator

Could you make these blocks?

if left is None:
    left = old_left
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/mpl_toolkits/mplot3d/axes3d.py
((20 lines not shown))
+ right = kw.pop('xmax')
+ if kw:
+ raise ValueError("unrecognized kwargs: %s" % kw.keys())
+
+ if right is None and iterable(left):
+ left,right = left
+
+ self._process_unit_info(xdata=(left, right))
+ if left is not None:
+ left = self.convert_xunits(left)
+ if right is not None:
+ right = self.convert_xunits(right)
+
+ old_left, old_right = self.get_xlim()
+ if left is None: left = old_left
+ if right is None: right = old_right
@dmcdougall Collaborator

Ditto.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/mpl_toolkits/mplot3d/axes3d.py
((22 lines not shown))
+ raise ValueError("unrecognized kwargs: %s" % kw.keys())
+
+ if right is None and iterable(left):
+ left,right = left
+
+ self._process_unit_info(xdata=(left, right))
+ if left is not None:
+ left = self.convert_xunits(left)
+ if right is not None:
+ right = self.convert_xunits(right)
+
+ old_left, old_right = self.get_xlim()
+ if left is None: left = old_left
+ if right is None: right = old_right
+
+ if left==right:
@dmcdougall Collaborator

Could you put spaces around ==?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/mpl_toolkits/mplot3d/axes3d.py
((23 lines not shown))
+
+ if right is None and iterable(left):
+ left,right = left
+
+ self._process_unit_info(xdata=(left, right))
+ if left is not None:
+ left = self.convert_xunits(left)
+ if right is not None:
+ right = self.convert_xunits(right)
+
+ old_left, old_right = self.get_xlim()
+ if left is None: left = old_left
+ if right is None: right = old_right
+
+ if left==right:
+ warnings.warn(('Attempting to set identical left==right results\n'
@dmcdougall Collaborator

Spaces around ==.

@dmcdougall Collaborator

Just realised this is in a string. You can ignore my previous comment if you wish.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/mpl_toolkits/mplot3d/axes3d.py
((24 lines not shown))
+ if right is None and iterable(left):
+ left,right = left
+
+ self._process_unit_info(xdata=(left, right))
+ if left is not None:
+ left = self.convert_xunits(left)
+ if right is not None:
+ right = self.convert_xunits(right)
+
+ old_left, old_right = self.get_xlim()
+ if left is None: left = old_left
+ if right is None: right = old_right
+
+ if left==right:
+ warnings.warn(('Attempting to set identical left==right results\n'
+ + 'in singular transformations; automatically expanding.\n'
@dmcdougall Collaborator

I don't think you need to + strings if they're on different lines.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/mpl_toolkits/mplot3d/axes3d.py
((70 lines not shown))
'''
- # TODO: Add compatibility for 'top' and 'bottom'
- # TODO: support 'emit' and 'auto'
- lims = self._determine_lims(*args, **kwargs)
- self.xy_viewLim.intervaly = lims
- return lims
+ if 'ymin' in kw:
+ bottom = kw.pop('ymin')
+ if 'ymax' in kw:
+ top = kw.pop('ymax')
+ if kw:
+ raise ValueError("unrecognized kwargs: %s" % kw.keys())
+
+ if top is None and iterable(bottom):
+ bottom,top = bottom
@dmcdougall Collaborator

Put a space after the ,.

@dmcdougall Collaborator

Space after ,.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/mpl_toolkits/mplot3d/axes3d.py
((79 lines not shown))
+ top = kw.pop('ymax')
+ if kw:
+ raise ValueError("unrecognized kwargs: %s" % kw.keys())
+
+ if top is None and iterable(bottom):
+ bottom,top = bottom
+
+ self._process_unit_info(ydata=(bottom, top))
+ if bottom is not None:
+ bottom = self.convert_yunits(bottom)
+ if top is not None:
+ top = self.convert_yunits(top)
+
+ old_bottom, old_top = self.get_ylim()
+ if bottom is None: bottom = old_bottom
+ if top is None: top = old_top
@dmcdougall Collaborator

Could you make these two ifs blocks, please?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/mpl_toolkits/mplot3d/axes3d.py
((81 lines not shown))
+ raise ValueError("unrecognized kwargs: %s" % kw.keys())
+
+ if top is None and iterable(bottom):
+ bottom,top = bottom
+
+ self._process_unit_info(ydata=(bottom, top))
+ if bottom is not None:
+ bottom = self.convert_yunits(bottom)
+ if top is not None:
+ top = self.convert_yunits(top)
+
+ old_bottom, old_top = self.get_ylim()
+ if bottom is None: bottom = old_bottom
+ if top is None: top = old_top
+
+ if top==bottom:
@dmcdougall Collaborator

Spaces around ==.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/mpl_toolkits/mplot3d/axes3d.py
((84 lines not shown))
+ bottom,top = bottom
+
+ self._process_unit_info(ydata=(bottom, top))
+ if bottom is not None:
+ bottom = self.convert_yunits(bottom)
+ if top is not None:
+ top = self.convert_yunits(top)
+
+ old_bottom, old_top = self.get_ylim()
+ if bottom is None: bottom = old_bottom
+ if top is None: top = old_top
+
+ if top==bottom:
+ warnings.warn(('Attempting to set identical bottom==top results\n'
+ + 'in singular transformations; automatically expanding.\n'
+ + 'bottom=%s, top=%s') % (bottom, top))
@dmcdougall Collaborator

Don't need to add strings.

@dmcdougall Collaborator

Adding strings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/mpl_toolkits/mplot3d/axes3d.py
((138 lines not shown))
+ top = kw.pop('zmax')
+ if kw:
+ raise ValueError("unrecognized kwargs: %s" % kw.keys())
+
+ if top is None and iterable(bottom):
+ bottom,top = bottom
+
+ self._process_unit_info(zdata=(bottom, top))
+ if bottom is not None:
+ bottom = self.convert_zunits(bottom)
+ if top is not None:
+ top = self.convert_zunits(top)
+
+ old_bottom, old_top = self.get_zlim()
+ if bottom is None: bottom = old_bottom
+ if top is None: top = old_top
@dmcdougall Collaborator

Blocks here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/mpl_toolkits/mplot3d/axes3d.py
((140 lines not shown))
+ raise ValueError("unrecognized kwargs: %s" % kw.keys())
+
+ if top is None and iterable(bottom):
+ bottom,top = bottom
+
+ self._process_unit_info(zdata=(bottom, top))
+ if bottom is not None:
+ bottom = self.convert_zunits(bottom)
+ if top is not None:
+ top = self.convert_zunits(top)
+
+ old_bottom, old_top = self.get_zlim()
+ if bottom is None: bottom = old_bottom
+ if top is None: top = old_top
+
+ if top==bottom:
@dmcdougall Collaborator

Spaces.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/mpl_toolkits/mplot3d/axes3d.py
@@ -1958,6 +2145,9 @@ def scatter(self, xs, ys, zs=0, zdir='z', s=20, c='b', *args, **kwargs):
is_2d = False
art3d.patch_collection_2d_to_3d(patches, zs=zs, zdir=zdir)
+ if self._zmargin < 0.05 and xs.size > 0 :
@dmcdougall Collaborator

Get rid of the space before :.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@WeatherGod
Collaborator

Ok, done.

@dmcdougall
Collaborator

Woohoooooo. Cheers mate. Another one bites the dust.

@dmcdougall dmcdougall merged commit b2a7195 into from
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Sep 20, 2012
  1. @WeatherGod

    Autoscaling and limits in mplot3d.

    WeatherGod authored
        * Fixes improper setting of x,y,z limits not turning off autoscaling
        * Adds units support to z-axis
        * Adds shared axis support for z-axis
        * Closes #783
  2. @WeatherGod

    A bit of cleanup

    WeatherGod authored
Commits on Dec 3, 2012
  1. @WeatherGod
  2. @WeatherGod
This page is out of date. Refresh to see the latest.
Showing with 256 additions and 56 deletions.
  1. +256 −56 lib/mpl_toolkits/mplot3d/axes3d.py
View
312 lib/mpl_toolkits/mplot3d/axes3d.py
@@ -36,6 +36,7 @@ class Axes3D(Axes):
3D axes object.
"""
name = '3d'
+ _shared_z_axes = cbook.Grouper()
def __init__(self, fig, rect=None, *args, **kwargs):
'''
@@ -52,18 +53,22 @@ def __init__(self, fig, rect=None, *args, **kwargs):
*azim* Azimuthal viewing angle (default -60)
*elev* Elevation viewing angle (default 30)
*zscale* [%(scale)s]
+ *sharez* Other axes to share z-limits with
================ =========================================
+
+ .. versionadded :: 1.2.1
+ *sharez*
+
''' % {'scale': ' | '.join([repr(x) for x in mscale.get_scale_names()])}
if rect is None:
rect = [0.0, 0.0, 1.0, 1.0]
self._cids = []
- # TODO: Support z-axis sharing
-
self.initial_azim = kwargs.pop('azim', -60)
self.initial_elev = kwargs.pop('elev', 30)
zscale = kwargs.pop('zscale', None)
+ sharez = kwargs.pop('sharez', None)
self.xy_viewLim = unit_bbox()
self.zz_viewLim = unit_bbox()
@@ -74,6 +79,11 @@ def __init__(self, fig, rect=None, *args, **kwargs):
self.view_init(self.initial_elev, self.initial_azim)
self._ready = 0
+ self._sharez = sharez
+ if sharez is not None:
+ self._shared_z_axes.join(self, sharez)
+ self._adjustable = 'datalim'
+
Axes.__init__(self, fig, rect,
frameon=True,
*args, **kwargs)
@@ -112,6 +122,50 @@ def set_axis_off(self):
def set_axis_on(self):
self._axis3don = True
+ def have_units(self):
+ """
+ Return *True* if units are set on the *x*, *y*, or *z* axes
+
+ """
+ return (self.xaxis.have_units() or self.yaxis.have_units() or
+ self.zaxis.have_units())
+
+ def convert_zunits(self, z):
+ """
+ For artists in an axes, if the zaxis has units support,
+ convert *z* using zaxis unit type
+
+ .. versionadded :: 1.2.1
+
+ """
+ return self.zaxis.convert_units(z)
+
+ def _process_unit_info(self, xdata=None, ydata=None, zdata=None,
+ kwargs=None):
+ """
+ Look for unit *kwargs* and update the axis instances as necessary
+
+ """
+ Axes._process_unit_info(self, xdata=xdata, ydata=ydata, kwargs=kwargs)
+
+ if self.xaxis is None or self.yaxis is None or self.zaxis is None:
+ return
+
+ if zdata is not None:
+ # we only need to update if there is nothing set yet.
+ if not self.zaxis.have_units():
+ self.zaxis.update_units(xdata)
+
+ # process kwargs 2nd since these will override default units
+ if kwargs is not None:
+ zunits = kwargs.pop('zunits', self.zaxis.units)
+ if zunits != self.zaxis.units:
+ self.zaxis.set_units(zunits)
+ # If the units being set imply a different converter,
+ # we need to update.
+ if zdata is not None:
+ self.zaxis.update_units(zdata)
+
def set_top_view(self):
# this happens to be the right view for the viewing coordinates
# moved up and to the left slightly to fit labels and axes
@@ -120,6 +174,8 @@ def set_top_view(self):
ydwl = (0.95/self.dist)
ydw = (0.9/self.dist)
+ # This is purposely using the 2D Axes's set_xlim and set_ylim,
+ # because we are trying to place our viewing pane.
Axes.set_xlim(self, -xdwl, xdw, auto=None)
Axes.set_ylim(self, -ydwl, ydw, auto=None)
@@ -407,22 +463,17 @@ def autoscale_view(self, tight=None, scalex=True, scaley=True,
.. versionchanged :: 1.1.0
Function signature was changed to better match the 2D version.
- *tight* is now explicitly a kwarg and placed first. However,
- it currently does not do anything.
- """
+ *tight* is now explicitly a kwarg and placed first.
@dmcdougall Collaborator

I thought it didn't matter where kwargs were placed. Am I not understanding something?

@WeatherGod Collaborator

IIRC, the issue was that originally this function had **kwargs instead of explicit kwarg variables. The call signature did not match that from the 2d axes equivalent function. In v1.1.x, I fixed this issue.

@dmcdougall Collaborator

@WeatherGod To clarify, you're going to address the PEP8 issues here (along with the rest of the mplot3d module) in a different pull request?

@WeatherGod Collaborator

Completely missed this comment. I will update this PR to be PEP8 compliant, but then address the remaining PEP8 issues in mplot3d separately. In other words, I don't want to introduce new code with bad style. Fixes forthcoming.

@dmcdougall Collaborator

Thanks :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+
+ .. versionchanged :: 1.2.1
+ This is now fully functional.
- self.set_top_view()
+ """
if not self._ready:
return
- # TODO: This is nearly the equivalent code from the 2D
- # version, but it doesn't seem to work correctly.
- # Therefore, we are currently staying with the
- # same old behavior.
- """
# This method looks at the rectangular volume (see above)
# of data and decides how to scale the view portal to fit it.
-
if tight is None:
# if image data only just use the datalim
_tight = self._tight or (len(self.images)>0 and
@@ -431,13 +482,48 @@ def autoscale_view(self, tight=None, scalex=True, scaley=True,
else:
_tight = self._tight = bool(tight)
- Axes.autoscale_view(self, tight=_tight, scalex=scalex, scaley=scaley)
+ if scalex and self._autoscaleXon:
+ xshared = self._shared_x_axes.get_siblings(self)
+ dl = [ax.dataLim for ax in xshared]
+ bb = mtransforms.BboxBase.union(dl)
+ x0, x1 = self.xy_dataLim.intervalx
+ xlocator = self.xaxis.get_major_locator()
+ try:
+ x0, x1 = xlocator.nonsingular(x0, x1)
+ except AttributeError:
+ x0, x1 = mtransforms.nonsingular(x0, x1, increasing=False,
+ expander=0.05)
+ if self._xmargin > 0:
+ delta = (x1 - x0) * self._xmargin
+ x0 -= delta
+ x1 += delta
+ if not _tight:
+ x0, x1 = xlocator.view_limits(x0, x1)
+ self.set_xbound(x0, x1)
+
+ if scaley and self._autoscaleYon:
+ yshared = self._shared_y_axes.get_siblings(self)
+ dl = [ax.dataLim for ax in yshared]
+ bb = mtransforms.BboxBase.union(dl)
+ y0, y1 = self.xy_dataLim.intervaly
+ ylocator = self.yaxis.get_major_locator()
+ try:
+ y0, y1 = ylocator.nonsingular(y0, y1)
+ except AttributeError:
+ y0, y1 = mtransforms.nonsingular(y0, y1, increasing=False,
+ expander=0.05)
+ if self._ymargin > 0:
+ delta = (y1 - y0) * self._ymargin
+ y0 -= delta
+ y1 += delta
+ if not _tight:
+ y0, y1 = ylocator.view_limits(y0, y1)
+ self.set_ybound(y0, y1)
if scalez and self._autoscaleZon:
- # TODO: mplot3d does not support the sharing of Z axis.
- #zshared = self._shared_z_axes.get_siblings(self)
- #dl = [ax.dataLim for ax in zshared]
- #bb = mtransforms.BboxBase.union(dl)
+ zshared = self._shared_z_axes.get_siblings(self)
+ dl = [ax.dataLim for ax in zshared]
+ bb = mtransforms.BboxBase.union(dl)
z0, z1 = self.zz_dataLim.intervalx
zlocator = self.zaxis.get_major_locator()
try:
@@ -452,16 +538,6 @@ def autoscale_view(self, tight=None, scalex=True, scaley=True,
if not _tight:
z0, z1 = zlocator.view_limits(z0, z1)
self.set_zbound(z0, z1)
- """
- # Previous version's code
- if not self.get_autoscale_on():
- return
- if scalex:
- self.set_xlim3d(self.xy_dataLim.intervalx)
- if scaley:
- self.set_ylim3d(self.xy_dataLim.intervaly)
- if scalez:
- self.set_zlim3d(self.zz_dataLim.intervalx)
def get_w_lims(self):
'''Get 3D world limits.'''
@@ -478,44 +554,167 @@ def _determine_lims(self, xmin=None, xmax=None, *args, **kwargs):
xmax += 0.05
return (xmin, xmax)
- def set_xlim3d(self, *args, **kwargs):
- '''
+ def set_xlim3d(self, left=None, right=None, emit=True, auto=False, **kw):
+ """
Set 3D x limits.
See :meth:`matplotlib.axes.Axes.set_xlim` for full documentation.
- '''
- # TODO: Add compatibility for 'left' and 'right'
- # TODO: support 'emit' and 'auto'
- lims = self._determine_lims(*args, **kwargs)
- self.xy_viewLim.intervalx = lims
- return lims
+
+ """
+ if 'xmin' in kw:
+ left = kw.pop('xmin')
+ if 'xmax' in kw:
+ right = kw.pop('xmax')
+ if kw:
+ raise ValueError("unrecognized kwargs: %s" % kw.keys())
+
+ if right is None and iterable(left):
+ left, right = left
+
+ self._process_unit_info(xdata=(left, right))
+ if left is not None:
+ left = self.convert_xunits(left)
+ if right is not None:
+ right = self.convert_xunits(right)
+
+ old_left, old_right = self.get_xlim()
+ if left is None:
+ left = old_left
+ if right is None:
+ right = old_right
+
+ if left == right:
+ warnings.warn(('Attempting to set identical left==right results\n'
+ 'in singular transformations; automatically expanding.\n'
+ 'left=%s, right=%s') % (left, right))
+ left, right = mtransforms.nonsingular(left, right, increasing=False)
+ left, right = self.xaxis.limit_range_for_scale(left, right)
+ self.xy_viewLim.intervalx = (left, right)
+
+ if auto is not None:
+ self._autoscaleXon = bool(auto)
+
+ if emit:
+ self.callbacks.process('xlim_changed', self)
+ # 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.xy_viewLim.intervalx,
+ emit=False, auto=auto)
+ if (other.figure != self.figure and
+ other.figure.canvas is not None):
+ other.figure.canvas.draw_idle()
+
+ return left, right
set_xlim = set_xlim3d
- def set_ylim3d(self, *args, **kwargs):
- '''
+ def set_ylim3d(self, bottom=None, top=None, emit=True, auto=False, **kw):
+ """
Set 3D y limits.
See :meth:`matplotlib.axes.Axes.set_ylim` for full documentation.
- '''
- # TODO: Add compatibility for 'top' and 'bottom'
- # TODO: support 'emit' and 'auto'
- lims = self._determine_lims(*args, **kwargs)
- self.xy_viewLim.intervaly = lims
- return lims
+
+ """
+ if 'ymin' in kw:
+ bottom = kw.pop('ymin')
+ if 'ymax' in kw:
+ top = kw.pop('ymax')
+ if kw:
+ raise ValueError("unrecognized kwargs: %s" % kw.keys())
+
+ if top is None and iterable(bottom):
+ bottom, top = bottom
+
+ self._process_unit_info(ydata=(bottom, top))
+ if bottom is not None:
+ bottom = self.convert_yunits(bottom)
+ if top is not None:
+ top = self.convert_yunits(top)
+
+ old_bottom, old_top = self.get_ylim()
+ if bottom is None:
+ bottom = old_bottom
+ if top is None:
+ top = old_top
+
+ if top == bottom:
+ warnings.warn(('Attempting to set identical bottom==top results\n'
+ 'in singular transformations; automatically expanding.\n'
+ 'bottom=%s, top=%s') % (bottom, top))
+ bottom, top = mtransforms.nonsingular(bottom, top, increasing=False)
+ bottom, top = self.yaxis.limit_range_for_scale(bottom, top)
+ self.xy_viewLim.intervaly = (bottom, top)
+
+ if auto is not None:
+ self._autoscaleYon = bool(auto)
+
+ if emit:
+ self.callbacks.process('ylim_changed', self)
+ # Call all of the other y-axes that are shared with this one
+ for other in self._shared_y_axes.get_siblings(self):
+ if other is not self:
+ other.set_ylim(self.xy_viewLim.intervaly,
+ emit=False, auto=auto)
+ if (other.figure != self.figure and
+ other.figure.canvas is not None):
+ other.figure.canvas.draw_idle()
+
+ return bottom, top
set_ylim = set_ylim3d
- def set_zlim3d(self, *args, **kwargs):
- '''
+ def set_zlim3d(self, bottom=None, top=None, emit=True, auto=False, **kw):
+ """
Set 3D z limits.
- See :meth:`matplotlib.axes.Axes.set_ylim` for full documentation.
- '''
- # TODO: Add compatibility for 'top' and 'bottom'
- # TODO: support 'emit' and 'auto'
- lims = self._determine_lims(*args, **kwargs)
- self.zz_viewLim.intervalx = lims
- return lims
+ See :meth:`matplotlib.axes.Axes.set_ylim` for full documentation
+
+ """
+ if 'zmin' in kw:
+ bottom = kw.pop('zmin')
+ if 'zmax' in kw:
+ top = kw.pop('zmax')
+ if kw:
+ raise ValueError("unrecognized kwargs: %s" % kw.keys())
+
+ if top is None and iterable(bottom):
+ bottom, top = bottom
+
+ self._process_unit_info(zdata=(bottom, top))
+ if bottom is not None:
+ bottom = self.convert_zunits(bottom)
+ if top is not None:
+ top = self.convert_zunits(top)
+
+ old_bottom, old_top = self.get_zlim()
+ if bottom is None:
+ bottom = old_bottom
+ if top is None:
+ top = old_top
+
+ if top == bottom:
+ warnings.warn(('Attempting to set identical bottom==top results\n'
+ 'in singular transformations; automatically expanding.\n'
+ 'bottom=%s, top=%s') % (bottom, top))
+ bottom, top = mtransforms.nonsingular(bottom, top, increasing=False)
+ bottom, top = self.zaxis.limit_range_for_scale(bottom, top)
+ self.zz_viewLim.intervalx = (bottom, top)
+
+ if auto is not None:
+ self._autoscaleZon = bool(auto)
+
+ if emit:
+ self.callbacks.process('zlim_changed', self)
+ # Call all of the other y-axes that are shared with this one
+ for other in self._shared_z_axes.get_siblings(self):
+ if other is not self:
+ other.set_zlim(self.zz_viewLim.intervalx,
+ emit=False, auto=auto)
+ if (other.figure != self.figure and
+ other.figure.canvas is not None):
+ other.figure.canvas.draw_idle()
+
+ return bottom, top
set_zlim = set_zlim3d
def get_xlim3d(self):
@@ -823,16 +1022,14 @@ def can_pan(self) :
return False
def cla(self):
- """Clear axes and disable mouse button callbacks.
+ """
+ Clear axes
"""
# Disabling mouse interaction might have been needed a long
# time ago, but I can't find a reason for it now - BVR (2012-03)
#self.disable_mouse_rotation()
self.zaxis.cla()
- # TODO: Support sharez
- self._sharez = None
-
if self._sharez is not None:
self.zaxis.major = self._sharez.zaxis.major
self.zaxis.minor = self._sharez.zaxis.minor
@@ -1962,6 +2159,9 @@ def scatter(self, xs, ys, zs=0, zdir='z', s=20, c='b', *args, **kwargs):
is_2d = False
art3d.patch_collection_2d_to_3d(patches, zs=zs, zdir=zdir)
+ if self._zmargin < 0.05 and xs.size > 0:
+ self.set_zmargin(0.05)
+
#FIXME: why is this necessary?
if not is_2d:
self.auto_scale_xyz(xs, ys, zs, had_data)
Something went wrong with that request. Please try again.