Skip to content

Commit 1918f00

Browse files
committed
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.
1 parent da711e1 commit 1918f00

File tree

2 files changed

+115
-6
lines changed

2 files changed

+115
-6
lines changed

lib/matplotlib/axes/_base.py

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,7 @@ def __init__(self, fig, rect,
438438
================ =========================================
439439
Keyword Description
440440
================ =========================================
441-
*adjustable* [ 'box' | 'datalim' | 'box-forced']
441+
*adjustable* [ 'box' | 'datalim' | 'xlim' | 'ylim' | 'box-forced' ]
442442
*alpha* float: the alpha transparency (can be None)
443443
*anchor* [ 'C', 'SW', 'S', 'SE', 'E', 'NE', 'N',
444444
'NW', 'W' ]
@@ -1271,6 +1271,8 @@ def set_aspect(self, aspect, adjustable=None, anchor=None):
12711271
============ =====================================
12721272
'box' change physical size of axes
12731273
'datalim' change xlim or ylim
1274+
'xlim' change xlim
1275+
'ylim' change ylim
12741276
'box-forced' same as 'box', but axes can be shared
12751277
============ =====================================
12761278
@@ -1307,9 +1309,9 @@ def get_adjustable(self):
13071309

13081310
def set_adjustable(self, adjustable):
13091311
"""
1310-
ACCEPTS: [ 'box' | 'datalim' | 'box-forced']
1312+
ACCEPTS: [ 'box' | 'datalim' | 'xlim' | 'ylim' | 'box-forced']
13111313
"""
1312-
if adjustable in ('box', 'datalim', 'box-forced'):
1314+
if adjustable in ('box', 'datalim', 'xlim', 'ylim', 'box-forced'):
13131315
if self in self._shared_x_axes or self in self._shared_y_axes:
13141316
if adjustable == 'box':
13151317
raise ValueError(
@@ -1482,11 +1484,27 @@ def apply_aspect(self, position=None):
14821484
self not in self._shared_x_axes)
14831485
changey = (self in self._shared_x_axes and
14841486
self not in self._shared_y_axes)
1487+
14851488
if changex and changey:
1486-
warnings.warn("adjustable='datalim' cannot work with shared "
1487-
"x and y axes")
1489+
warnings.warn("adjustable='{0}' cannot work with shared "
1490+
"x and y axes".format(self._adjustable))
1491+
return
1492+
1493+
if self._adjustable == 'xlim' and changey:
1494+
warnings.warn("adjustable='xlim' cannot work with shared "
1495+
"x axes".format(self._adjustable))
1496+
return
1497+
1498+
if self._adjustable == 'ylim' and changex:
1499+
warnings.warn("adjustable='ylim' cannot work with shared "
1500+
"y axes".format(self._adjustable))
14881501
return
1489-
if changex:
1502+
1503+
if self._adjustable == 'xlim':
1504+
adjust_y = False
1505+
elif self._adjustable == 'ylim':
1506+
adjust_y = True
1507+
elif changex:
14901508
adjust_y = False
14911509
else:
14921510
if xmarg > xm and ymarg > ym:
@@ -1495,6 +1513,7 @@ def apply_aspect(self, position=None):
14951513
else:
14961514
adjy = y_expander > 0
14971515
adjust_y = changey or adjy # (Ymarg > xmarg)
1516+
14981517
if adjust_y:
14991518
yc = 0.5 * (ymin + ymax)
15001519
y0 = yc - Ysize / 2.0

lib/matplotlib/tests/test_axes.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5149,3 +5149,93 @@ def test_twinx_knows_limits():
51495149
ax2.plot([0, 0.5], [1, 2])
51505150

51515151
assert((xtwin.viewLim.intervalx == ax2.viewLim.intervalx).all())
5152+
5153+
5154+
def test_adjustable_limits():
5155+
5156+
# Test the 'datalim', 'xlim', and 'ylim' options
5157+
5158+
image = np.ones((5, 5))
5159+
5160+
# First, we test adjustable='datalim'. Here, whether xlim or ylim are
5161+
# changed is up to Matplotlib.
5162+
5163+
fig = plt.figure(figsize=(6, 4))
5164+
ax = fig.add_axes([0, 0, 1, 1], aspect='equal')
5165+
ax.imshow(image, origin='lower')
5166+
5167+
# Since the axes has a landscape aspect ratio, the image should fit
5168+
# vertically and have white padding horizontally:
5169+
ax.set_adjustable('datalim')
5170+
ax.apply_aspect()
5171+
assert_allclose(ax.get_xlim(), [-1.75, 5.75])
5172+
assert_allclose(ax.get_ylim(), [-0.5, 4.5])
5173+
5174+
# Because of the way Matplotlib computes the aspect internally, it turns out
5175+
# that in this scenario ylim is the adjustable, so even if we change ylim,
5176+
# xlim will stay the same and ylim will get adjusted. This could be improved
5177+
# in future by checking in set_xlim and set_ylim whether adjustable='datalim'
5178+
# and try and make sure this value is respected.
5179+
ax.set_ylim(4, 5)
5180+
ax.apply_aspect()
5181+
assert_allclose(ax.get_xlim(), [-1.75, 5.75])
5182+
assert_allclose(ax.get_ylim(), [2, 7])
5183+
5184+
# Similarly, if xlim is changed, the values are not necessarily respected
5185+
# and in fact ylim is the one that stays constant. This behavior is the
5186+
# reason for adding explicit adjustable='xlim' and adjustable='ylim' options.
5187+
ax.set_xlim(1, 4)
5188+
ax.apply_aspect()
5189+
assert_allclose(ax.get_xlim(), [-1.25, 6.25])
5190+
assert_allclose(ax.get_ylim(), [2, 7])
5191+
5192+
# We now test adjustable='xlim', which should behave in a much more
5193+
# predictable way.
5194+
5195+
fig = plt.figure(figsize=(6, 4))
5196+
ax = fig.add_axes([0, 0, 1, 1], aspect='equal')
5197+
ax.imshow(image, origin='lower')
5198+
5199+
ax.set_adjustable('xlim')
5200+
ax.apply_aspect()
5201+
assert_allclose(ax.get_xlim(), [-1.75, 5.75])
5202+
assert_allclose(ax.get_ylim(), [-0.5, 4.5])
5203+
5204+
# Changing ylim results in ylim changing predictably and xlim getting
5205+
# adjusted
5206+
ax.set_ylim(4, 6)
5207+
ax.apply_aspect()
5208+
assert_allclose(ax.get_xlim(), [0.5, 3.5])
5209+
assert_allclose(ax.get_ylim(), [4, 6])
5210+
5211+
# Changing xlim results in xlim adjusting itself and ylim staying the same
5212+
ax.set_xlim(2, 4)
5213+
ax.apply_aspect()
5214+
assert_allclose(ax.get_xlim(), [1.5, 4.5])
5215+
assert_allclose(ax.get_ylim(), [4, 6])
5216+
5217+
# Finally we test adjustable='ylim', which should behave similarly to 'xlim'
5218+
5219+
fig = plt.figure(figsize=(6, 4))
5220+
ax = fig.add_axes([0, 0, 1, 1], aspect='equal')
5221+
ax.imshow(image, origin='lower')
5222+
5223+
# In the case where ylim is the adjustable, the image will fill the axes
5224+
# horizontally.
5225+
ax.set_adjustable('ylim')
5226+
ax.apply_aspect()
5227+
assert_allclose(ax.get_xlim(), [-0.5, 4.5])
5228+
assert_allclose(ax.get_ylim(), [1 / 3., 11 / 3.])
5229+
5230+
# Changing xlim results in xlim changing predictably and ylim getting
5231+
# adjusted
5232+
ax.set_xlim(4, 6)
5233+
ax.apply_aspect()
5234+
assert_allclose(ax.get_xlim(), [4, 6])
5235+
assert_allclose(ax.get_ylim(), [4 / 3., 8 / 3.])
5236+
5237+
# Changing ylim results in ylim adjusting itself and xlim staying the same
5238+
ax.set_ylim(2, 4)
5239+
ax.apply_aspect()
5240+
assert_allclose(ax.get_xlim(), [4, 6])
5241+
assert_allclose(ax.get_ylim(), [7 / 3., 11 / 3.])

0 commit comments

Comments
 (0)
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