From 2fd2dd004ff565f470ffbb1b5c11d72934fbc3c8 Mon Sep 17 00:00:00 2001 From: Thomas Robitaille Date: Thu, 1 Jun 2017 15:40:10 +0100 Subject: [PATCH 1/4] ENH: add two new modes for 'adjustable' option The new modes are 'xlim' and 'ylim' - these behave like the 'datalim' option except that only the x or y limits are adjusted, in a deterministic way. --- lib/matplotlib/axes/_base.py | 32 ++++++++--- lib/matplotlib/tests/test_axes.py | 90 +++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+), 6 deletions(-) diff --git a/lib/matplotlib/axes/_base.py b/lib/matplotlib/axes/_base.py index 7948c14de8e9..4bfd78f3eeac 100644 --- a/lib/matplotlib/axes/_base.py +++ b/lib/matplotlib/axes/_base.py @@ -438,7 +438,8 @@ def __init__(self, fig, rect, ================ ========================================= Keyword Description ================ ========================================= - *adjustable* [ 'box' | 'datalim' | 'box-forced'] + *adjustable* [ 'box' | 'datalim' | 'xlim' | 'ylim' | + 'box-forced' ] *alpha* float: the alpha transparency (can be None) *anchor* [ 'C', 'SW', 'S', 'SE', 'E', 'NE', 'N', 'NW', 'W' ] @@ -1271,6 +1272,8 @@ def set_aspect(self, aspect, adjustable=None, anchor=None): ============ ===================================== 'box' change physical size of axes 'datalim' change xlim or ylim + 'xlim' change xlim + 'ylim' change ylim 'box-forced' same as 'box', but axes can be shared ============ ===================================== @@ -1307,9 +1310,9 @@ def get_adjustable(self): def set_adjustable(self, adjustable): """ - ACCEPTS: [ 'box' | 'datalim' | 'box-forced'] + ACCEPTS: [ 'box' | 'datalim' | 'xlim' | 'ylim' | 'box-forced'] """ - if adjustable in ('box', 'datalim', 'box-forced'): + if adjustable in ('box', 'datalim', 'xlim', 'ylim', 'box-forced'): if self in self._shared_x_axes or self in self._shared_y_axes: if adjustable == 'box': raise ValueError( @@ -1482,11 +1485,27 @@ def apply_aspect(self, position=None): self not in self._shared_x_axes) changey = (self in self._shared_x_axes and self not in self._shared_y_axes) + if changex and changey: - warnings.warn("adjustable='datalim' cannot work with shared " - "x and y axes") + warnings.warn("adjustable='{0}' cannot work with shared " + "x and y axes".format(self._adjustable)) + return + + if self._adjustable == 'xlim' and changey: + warnings.warn("adjustable='xlim' cannot work with shared " + "x axes".format(self._adjustable)) + return + + if self._adjustable == 'ylim' and changex: + warnings.warn("adjustable='ylim' cannot work with shared " + "y axes".format(self._adjustable)) return - if changex: + + if self._adjustable == 'xlim': + adjust_y = False + elif self._adjustable == 'ylim': + adjust_y = True + elif changex: adjust_y = False else: if xmarg > xm and ymarg > ym: @@ -1495,6 +1514,7 @@ def apply_aspect(self, position=None): else: adjy = y_expander > 0 adjust_y = changey or adjy # (Ymarg > xmarg) + if adjust_y: yc = 0.5 * (ymin + ymax) y0 = yc - Ysize / 2.0 diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index 86b6f2a3ddc2..2be34364bd3d 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -5149,3 +5149,93 @@ def test_twinx_knows_limits(): ax2.plot([0, 0.5], [1, 2]) assert((xtwin.viewLim.intervalx == ax2.viewLim.intervalx).all()) + + +def test_adjustable_limits(): + + # Test the 'datalim', 'xlim', and 'ylim' options + + image = np.ones((5, 5)) + + # First, we test adjustable='datalim'. Here, whether xlim or ylim are + # changed is up to Matplotlib. + + fig = plt.figure(figsize=(6, 4)) + ax = fig.add_axes([0, 0, 1, 1], aspect='equal') + ax.imshow(image, origin='lower') + + # Since the axes has a landscape aspect ratio, the image should fit + # vertically and have white padding horizontally: + ax.set_adjustable('datalim') + ax.apply_aspect() + assert_allclose(ax.get_xlim(), [-1.75, 5.75]) + assert_allclose(ax.get_ylim(), [-0.5, 4.5]) + + # Because of the way Matplotlib computes the aspect internally, it turns out + # that in this scenario ylim is the adjustable, so even if we change ylim, + # xlim will stay the same and ylim will get adjusted. This could be improved + # in future by checking in set_xlim and set_ylim whether adjustable='datalim' + # and try and make sure this value is respected. + ax.set_ylim(4, 5) + ax.apply_aspect() + assert_allclose(ax.get_xlim(), [-1.75, 5.75]) + assert_allclose(ax.get_ylim(), [2, 7]) + + # Similarly, if xlim is changed, the values are not necessarily respected + # and in fact ylim is the one that stays constant. This behavior is the + # reason for adding explicit adjustable='xlim' and adjustable='ylim' options. + ax.set_xlim(1, 4) + ax.apply_aspect() + assert_allclose(ax.get_xlim(), [-1.25, 6.25]) + assert_allclose(ax.get_ylim(), [2, 7]) + + # We now test adjustable='xlim', which should behave in a much more + # predictable way. + + fig = plt.figure(figsize=(6, 4)) + ax = fig.add_axes([0, 0, 1, 1], aspect='equal') + ax.imshow(image, origin='lower') + + ax.set_adjustable('xlim') + ax.apply_aspect() + assert_allclose(ax.get_xlim(), [-1.75, 5.75]) + assert_allclose(ax.get_ylim(), [-0.5, 4.5]) + + # Changing ylim results in ylim changing predictably and xlim getting + # adjusted + ax.set_ylim(4, 6) + ax.apply_aspect() + assert_allclose(ax.get_xlim(), [0.5, 3.5]) + assert_allclose(ax.get_ylim(), [4, 6]) + + # Changing xlim results in xlim adjusting itself and ylim staying the same + ax.set_xlim(2, 4) + ax.apply_aspect() + assert_allclose(ax.get_xlim(), [1.5, 4.5]) + assert_allclose(ax.get_ylim(), [4, 6]) + + # Finally we test adjustable='ylim', which should behave similarly to 'xlim' + + fig = plt.figure(figsize=(6, 4)) + ax = fig.add_axes([0, 0, 1, 1], aspect='equal') + ax.imshow(image, origin='lower') + + # In the case where ylim is the adjustable, the image will fill the axes + # horizontally. + ax.set_adjustable('ylim') + ax.apply_aspect() + assert_allclose(ax.get_xlim(), [-0.5, 4.5]) + assert_allclose(ax.get_ylim(), [1 / 3., 11 / 3.]) + + # Changing xlim results in xlim changing predictably and ylim getting + # adjusted + ax.set_xlim(4, 6) + ax.apply_aspect() + assert_allclose(ax.get_xlim(), [4, 6]) + assert_allclose(ax.get_ylim(), [4 / 3., 8 / 3.]) + + # Changing ylim results in ylim adjusting itself and xlim staying the same + ax.set_ylim(2, 4) + ax.apply_aspect() + assert_allclose(ax.get_xlim(), [4, 6]) + assert_allclose(ax.get_ylim(), [7 / 3., 11 / 3.]) From 4a15e9ab5b533df33e4a7e768842b8f678cc0a6a Mon Sep 17 00:00:00 2001 From: Thomas Robitaille Date: Thu, 1 Jun 2017 17:18:16 +0100 Subject: [PATCH 2/4] Added 'What's new' entry --- doc/users/whats_new/adjustable_xlim_ylim.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 doc/users/whats_new/adjustable_xlim_ylim.rst diff --git a/doc/users/whats_new/adjustable_xlim_ylim.rst b/doc/users/whats_new/adjustable_xlim_ylim.rst new file mode 100644 index 000000000000..3b85aad4ae43 --- /dev/null +++ b/doc/users/whats_new/adjustable_xlim_ylim.rst @@ -0,0 +1,13 @@ +New ``'xlim'`` and ``'ylim'`` options for ``adjustable`` argument +----------------------------------------------------------------- + +The ``adjustable`` argument to the :meth:`~matplotlib.axes.Axes.set_aspect` +method (and the same argument which can be specified when initializing +:meth:`~matplotlib.axes.Axes`) can take two new values: ``'xlim'`` and +``'ylim'``. Previously, users could pass the ``'datalim'`` value to indicate +that Matplotlib should adjust the limits as needed so as to be able to avoid +modifying the position and aspect ratio of the axes, but it was impossible to +know deterministically whether Matplotlib would modify the x or y limits. The +new ``'xlim'`` and ``'ylim'`` options behave like ``'datalim'`` except that +``'xlim'`` causes only the x limits to be adjusted, and ``'ylim'`` causes only +the y limits to be adjusted. From 5365621a5564d2bf7f7e44f2268e8f96feaafb66 Mon Sep 17 00:00:00 2001 From: Thomas Robitaille Date: Thu, 1 Jun 2017 17:29:10 +0100 Subject: [PATCH 3/4] Fix PEP8 failures --- lib/matplotlib/tests/test_axes.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index 2be34364bd3d..9303c494cb94 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -5171,11 +5171,11 @@ def test_adjustable_limits(): assert_allclose(ax.get_xlim(), [-1.75, 5.75]) assert_allclose(ax.get_ylim(), [-0.5, 4.5]) - # Because of the way Matplotlib computes the aspect internally, it turns out - # that in this scenario ylim is the adjustable, so even if we change ylim, - # xlim will stay the same and ylim will get adjusted. This could be improved - # in future by checking in set_xlim and set_ylim whether adjustable='datalim' - # and try and make sure this value is respected. + # Because of the way Matplotlib computes the aspect internally, it turns + # out that in this scenario ylim is the adjustable, so even if we change + # ylim, xlim will stay the same and ylim will get adjusted. This could be + # improved in future by checking in set_xlim and set_ylim whether + # adjustable='datalim' and try and make sure this value is respected. ax.set_ylim(4, 5) ax.apply_aspect() assert_allclose(ax.get_xlim(), [-1.75, 5.75]) @@ -5183,7 +5183,8 @@ def test_adjustable_limits(): # Similarly, if xlim is changed, the values are not necessarily respected # and in fact ylim is the one that stays constant. This behavior is the - # reason for adding explicit adjustable='xlim' and adjustable='ylim' options. + # reason for adding explicit adjustable='xlim' and adjustable='ylim' + # options. ax.set_xlim(1, 4) ax.apply_aspect() assert_allclose(ax.get_xlim(), [-1.25, 6.25]) @@ -5214,7 +5215,8 @@ def test_adjustable_limits(): assert_allclose(ax.get_xlim(), [1.5, 4.5]) assert_allclose(ax.get_ylim(), [4, 6]) - # Finally we test adjustable='ylim', which should behave similarly to 'xlim' + # Finally we test adjustable='ylim', which should behave similarly to + # 'xlim' fig = plt.figure(figsize=(6, 4)) ax = fig.add_axes([0, 0, 1, 1], aspect='equal') From c37354c51ace5b715b9f3f638646ea1a4531fd27 Mon Sep 17 00:00:00 2001 From: Thomas Robitaille Date: Sat, 10 Jun 2017 12:52:34 +0100 Subject: [PATCH 4/4] Add trailing \ in docstring --- lib/matplotlib/axes/_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/axes/_base.py b/lib/matplotlib/axes/_base.py index 4bfd78f3eeac..d6459afd7162 100644 --- a/lib/matplotlib/axes/_base.py +++ b/lib/matplotlib/axes/_base.py @@ -438,7 +438,7 @@ def __init__(self, fig, rect, ================ ========================================= Keyword Description ================ ========================================= - *adjustable* [ 'box' | 'datalim' | 'xlim' | 'ylim' | + *adjustable* [ 'box' | 'datalim' | 'xlim' | 'ylim' | \ 'box-forced' ] *alpha* float: the alpha transparency (can be None) *anchor* [ 'C', 'SW', 'S', 'SE', 'E', 'NE', 'N', pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy