Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit cdd2843

Browse files
box aspect for axes
1 parent 667a100 commit cdd2843

File tree

4 files changed

+165
-3
lines changed

4 files changed

+165
-3
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
:orphan:
2+
3+
Setting axes box aspect
4+
-----------------------
5+
6+
It is now possible to set the aspect of an axes box directly via
7+
`~Axes.set_box_aspect`. The box aspect is the ratio between axes height
8+
and axes width in physical units, independent of the data limits.
9+
This is useful to e.g. produce a square plot, independent of the data it
10+
contains, or to have a usual plot with the same axes dimensions next to
11+
an image plot with fixed (data-)aspect.
12+
13+
For use cases check out the :doc:`Axes box aspect
14+
</gallery/subplots_axes_and_figures/axes_box_aspect>` example.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
"""
2+
===============
3+
Axes box aspect
4+
===============
5+
6+
This demo shows how to set the aspect of an axes box directly via
7+
`~Axes.set_box_aspect`. The box aspect is the ratio between axes height
8+
and axes width in physical units, independent of the data limits.
9+
This is useful to e.g. produce a square plot, independent of the data it
10+
contains, or to have a usual plot with the same axes dimensions next to
11+
an image plot with fixed (data-)aspect.
12+
"""
13+
14+
import matplotlib
15+
print("Placeholder, still to be filled")
16+
17+
18+
19+
#############################################################################
20+
#
21+
# ------------
22+
#
23+
# References
24+
# """"""""""
25+
#
26+
# The use of the following functions, methods and classes is shown
27+
# in this example:
28+
29+
matplotlib.axes.Axes.set_box_aspect

lib/matplotlib/axes/_base.py

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,7 @@ def __init__(self, fig, rect,
426426
self.axes = self
427427
self._aspect = 'auto'
428428
self._adjustable = 'box'
429+
self._box_aspect = None
429430
self._anchor = 'C'
430431
self._stale_viewlim_x = False
431432
self._stale_viewlim_y = False
@@ -1282,6 +1283,18 @@ def set_aspect(self, aspect, adjustable=None, anchor=None, share=False):
12821283
self.stale = True
12831284

12841285
def get_adjustable(self):
1286+
"""
1287+
Returns the adjustable parameter, *{'box', 'datalim'}* that defines
1288+
which parameter the Axes will change to achieve a given aspect.
1289+
1290+
See Also
1291+
--------
1292+
matplotlib.axes.Axes.set_adjustable
1293+
defining the parameter to adjust in order to meet the required
1294+
aspect.
1295+
matplotlib.axes.Axes.set_aspect
1296+
for a description of aspect handling.
1297+
"""
12851298
return self._adjustable
12861299

12871300
def set_adjustable(self, adjustable, share=False):
@@ -1333,6 +1346,54 @@ def set_adjustable(self, adjustable, share=False):
13331346
ax._adjustable = adjustable
13341347
self.stale = True
13351348

1349+
def get_box_aspect(self):
1350+
"""
1351+
Get the axes box aspect.
1352+
Will be ``None`` if not explicitely specified.
1353+
1354+
See Also
1355+
--------
1356+
matplotlib.axes.Axes.set_box_aspect
1357+
for a description of box aspect.
1358+
matplotlib.axes.Axes.set_aspect
1359+
for a description of aspect handling.
1360+
"""
1361+
return self._box_aspect
1362+
1363+
def set_box_aspect(self, aspect=None):
1364+
"""
1365+
Set the axes box aspect. The box aspect is the ratio of the
1366+
axes height to the axes width in physical units. This is not to be
1367+
confused with the data aspect, set via `~Axes.set_aspect`.
1368+
1369+
Parameters
1370+
----------
1371+
aspect : None, or a number
1372+
Changes the physical dimensions of the Axes, such that the ratio
1373+
of the axes height to the axes width in physical units is equal to
1374+
*aspect*. If *None*, the axes geometry will not be adjusted.
1375+
1376+
Note that this changes the adjustable to *datalim*.
1377+
1378+
See Also
1379+
--------
1380+
matplotlib.axes.Axes.set_aspect
1381+
for a description of aspect handling.
1382+
"""
1383+
axs = {*self._twinned_axes.get_siblings(self),
1384+
*self._twinned_axes.get_siblings(self)}
1385+
1386+
if aspect is not None:
1387+
aspect = float(aspect)
1388+
# when box_aspect is set to other than ´None`,
1389+
# adjustable must be "datalim"
1390+
for ax in axs:
1391+
ax.set_adjustable("datalim")
1392+
1393+
for ax in axs:
1394+
ax._box_aspect = aspect
1395+
ax.stale = True
1396+
13361397
def get_anchor(self):
13371398
"""
13381399
Get the anchor location.
@@ -1464,7 +1525,7 @@ def apply_aspect(self, position=None):
14641525

14651526
aspect = self.get_aspect()
14661527

1467-
if aspect == 'auto':
1528+
if aspect == 'auto' and self._box_aspect is None:
14681529
self._set_position(position, which='active')
14691530
return
14701531

@@ -1484,11 +1545,20 @@ def apply_aspect(self, position=None):
14841545
self._set_position(pb1.anchored(self.get_anchor(), pb), 'active')
14851546
return
14861547

1487-
# self._adjustable == 'datalim'
1548+
# The following is only seen if self._adjustable == 'datalim'
1549+
if self._box_aspect is not None:
1550+
pb = position.frozen()
1551+
pb1 = pb.shrunk_to_aspect(self._box_aspect, pb, fig_aspect)
1552+
self._set_position(pb1.anchored(self.get_anchor(), pb), 'active')
1553+
if aspect == "auto":
1554+
return
14881555

14891556
# reset active to original in case it had been changed by prior use
14901557
# of 'box'
1491-
self._set_position(position, which='active')
1558+
if self._box_aspect is None:
1559+
self._set_position(position, which='active')
1560+
else:
1561+
position = pb1.anchored(self.get_anchor(), pb)
14921562

14931563
x_trf = self.xaxis.get_transform()
14941564
y_trf = self.yaxis.get_transform()

lib/matplotlib/tests/test_axes.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6560,3 +6560,52 @@ def test_aspect_nonlinear_adjustable_datalim():
65606560
ax.margins(0)
65616561
ax.apply_aspect()
65626562
assert ax.get_xlim() == pytest.approx(np.array([1/10, 10]) * np.sqrt(10))
6563+
6564+
6565+
def test_box_aspect():
6566+
# Test if axes with box_aspect=1 has same dimensions
6567+
# as axes with aspect equal and adjustable="box"
6568+
6569+
fig1, ax1 = plt.subplots()
6570+
axtwin = ax1.twinx()
6571+
axtwin.plot([12,344])
6572+
6573+
ax1.set_box_aspect(1)
6574+
6575+
fig2, ax2 = plt.subplots()
6576+
ax2.margins(0)
6577+
ax2.plot([0,2],[6,8])
6578+
ax2.set_aspect("equal", adjustable="box")
6579+
6580+
fig1.canvas.draw()
6581+
fig2.canvas.draw()
6582+
6583+
bb1 = ax1.get_position()
6584+
bbt = axtwin.get_position()
6585+
bb2 = ax2.get_position()
6586+
6587+
assert_array_equal(bb1.extents, bb2.extents)
6588+
assert_array_equal(bbt.extents, bb2.extents)
6589+
6590+
6591+
def test_box_aspect_custom_position():
6592+
# Test if axes with custom position and box_aspect
6593+
# behaves the same independent of the order of setting those.
6594+
6595+
fig1, ax1 = plt.subplots()
6596+
ax1.set_position([0.1, 0.1, 0.9, 0.2])
6597+
fig1.canvas.draw()
6598+
ax1.set_box_aspect(1.)
6599+
6600+
fig2, ax2 = plt.subplots()
6601+
ax2.set_box_aspect(1.)
6602+
fig2.canvas.draw()
6603+
ax2.set_position([0.1, 0.1, 0.9, 0.2])
6604+
6605+
fig1.canvas.draw()
6606+
fig2.canvas.draw()
6607+
6608+
bb1 = ax1.get_position()
6609+
bb2 = ax2.get_position()
6610+
6611+
assert_array_equal(bb1.extents, bb2.extents)

0 commit comments

Comments
 (0)