diff --git a/doc/api/api_changes.rst b/doc/api/api_changes.rst index 119816a18c74..85d823b18d08 100644 --- a/doc/api/api_changes.rst +++ b/doc/api/api_changes.rst @@ -11,6 +11,19 @@ sources of the changes you are experiencing. For new features that were added to matplotlib, please see :ref:`whats-new`. +Changes in 2.1.0 +================ + +Code changes +------------ + +autoscale is now a context manager +`````````````````````````````````` + +Instead of returning None, ``plt.autoscale`` and ``Axes.autoscale`` +now return a context manager, which allows one to restore the previous +autoscaling status upon exiting the block. + Changes in 2.0.0 ================ diff --git a/doc/users/whats_new.rst b/doc/users/whats_new.rst index c1657092b6ce..7107cb88c920 100644 --- a/doc/users/whats_new.rst +++ b/doc/users/whats_new.rst @@ -23,6 +23,18 @@ revision, see the :ref:`github-stats`. .. contents:: Table of Contents :depth: 3 +.. _whats-new-2-1: + +new in matplotlib-2.1 +===================== + +autoscale is now a context manager +---------------------------------- + +Instead of returning None, ``plt.autoscale`` and ``Axes.autoscale`` +now return a context manager, which allows one to restore the previous +autoscaling status upon exiting the block. + .. _whats-new-1-5: new in matplotlib-1.5 diff --git a/lib/matplotlib/axes/_base.py b/lib/matplotlib/axes/_base.py index b0637aef6500..094b86a461c3 100644 --- a/lib/matplotlib/axes/_base.py +++ b/lib/matplotlib/axes/_base.py @@ -4,6 +4,7 @@ from matplotlib.externals import six from matplotlib.externals.six.moves import xrange +from contextlib import contextmanager import itertools import warnings import math @@ -2103,22 +2104,31 @@ def autoscale(self, enable=True, axis='both', tight=None): The *tight* setting is retained for future autoscaling until it is explicitly changed. + This returns a context-manager/decorator that allows temporarily + setting the autoscale status, i.e.:: - Returns None. + with axes.autoscale(enable): ... + + will keep the autoscale status to `enable` for the duration of the + block only. """ - if enable is None: - scalex = True - scaley = True - else: - scalex = False - scaley = False + orig_autoscale = self._autoscaleXon, self._autoscaleYon + if enable is not None: if axis in ['x', 'both']: self._autoscaleXon = bool(enable) - scalex = self._autoscaleXon if axis in ['y', 'both']: self._autoscaleYon = bool(enable) - scaley = self._autoscaleYon - self.autoscale_view(tight=tight, scalex=scalex, scaley=scaley) + self.autoscale_view( + tight=tight, scalex=self._autoscaleXon, scaley=self._autoscaleYon) + + @contextmanager + def restore_autoscaling(): + try: + yield + finally: + self._autoscaleXon, self._autoscaleYon = orig_autoscale + + return restore_autoscaling() def autoscale_view(self, tight=None, scalex=True, scaley=True): """ diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index 5a3e6ee70e13..8d391ba08ca0 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -4118,6 +4118,22 @@ def test_axisbg_warning(): ("The axisbg attribute was deprecated in version 2.0."))) +@cleanup +def test_autoscale(): + plt.plot([0, 1], [0, 1]) + assert_equal(plt.xlim(), (0, 1)) + plt.autoscale(False) + plt.plot([2, 3], [2, 3]) + assert_equal(plt.xlim(), (0, 1)) + plt.autoscale(None) + assert_equal(plt.xlim(), (0, 3)) + with plt.autoscale(False): + plt.plot([3, 4], [3, 4]) + assert_equal(plt.xlim(), (0, 3)) + plt.plot([4, 5], [4, 5]) + assert_equal(plt.xlim(), (0, 5)) + + if __name__ == '__main__': import nose import sys diff --git a/lib/mpl_toolkits/mplot3d/axes3d.py b/lib/mpl_toolkits/mplot3d/axes3d.py index 59ce4e6626f3..78e8cfcd4d45 100755 --- a/lib/mpl_toolkits/mplot3d/axes3d.py +++ b/lib/mpl_toolkits/mplot3d/axes3d.py @@ -11,6 +11,7 @@ """ from __future__ import (absolute_import, division, print_function, unicode_literals) +from contextlib import contextmanager import math from matplotlib.externals import six @@ -342,7 +343,7 @@ def set_autoscalez_on(self, b) : .. versionadded :: 1.1.0 This function was added, but not tested. Please report any bugs. """ - self._autoscalez_on = b + self._autoscaleZon = b def set_zmargin(self, m) : """ @@ -438,25 +439,29 @@ def autoscale(self, enable=True, axis='both', tight=None) : .. versionadded :: 1.1.0 This function was added, but not tested. Please report any bugs. """ - if enable is None: - scalex = True - scaley = True - scalez = True - else: - scalex = False - scaley = False - scalez = False + orig_autoscale = ( + self._autoscaleXon, self._autoscaleYon, self._autoscaleZon) + if enable is not None: if axis in ['x', 'both']: self._autoscaleXon = bool(enable) - scalex = self._autoscaleXon if axis in ['y', 'both']: self._autoscaleYon = bool(enable) - scaley = self._autoscaleYon if axis in ['z', 'both']: self._autoscaleZon = bool(enable) - scalez = self._autoscaleZon - self.autoscale_view(tight=tight, scalex=scalex, scaley=scaley, - scalez=scalez) + self.autoscale_view(tight=tight, + scalex=self._autoscaleXon, + scaley=self._autoscaleYon, + scalez=self._autoscaleZon) + + @contextmanager + def restore_autoscaling(): + try: + yield + finally: + self._autoscaleXon, self._autoscaleYon, self._autoscaleZon = ( + orig_autoscale) + + return restore_autoscaling() def auto_scale_xyz(self, X, Y, Z=None, had_data=None): x, y, z = list(map(np.asarray, (X, Y, Z)))