Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit0e2fdb9

Browse files
box aspect for axes
1 parent667a100 commit0e2fdb9

File tree

4 files changed

+279
-3
lines changed

4 files changed

+279
-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: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
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+
The following lists a few use cases for `~Axes.set_box_aspect`.
14+
"""
15+
16+
############################################################################
17+
# A square axes, independent of data
18+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19+
#
20+
# Produce a square axes, no matter what the data limits are.
21+
22+
importmatplotlib
23+
importnumpyasnp
24+
importmatplotlib.pyplotasplt
25+
26+
fig1,ax=plt.subplots()
27+
28+
ax.set_xlim(300,400)
29+
ax.set_box_aspect(1)
30+
31+
plt.show()
32+
33+
############################################################################
34+
# Shared square axes
35+
# ~~~~~~~~~~~~~~~~~~
36+
#
37+
# Produce shared subplots that are squared in size.
38+
#
39+
fig2, (ax,ax2)=plt.subplots(ncols=2,sharey=True)
40+
41+
ax.plot([1,5], [0,10])
42+
ax2.plot([100,500], [10,15])
43+
44+
ax.set_box_aspect(1)
45+
ax2.set_box_aspect(1)
46+
47+
plt.show()
48+
49+
############################################################################
50+
# Square twin axes
51+
# ~~~~~~~~~~~~~~~~
52+
#
53+
# Produce a square axes, with a twin axes. The twinned axes takes over the
54+
# box aspect of the parent.
55+
#
56+
57+
fig3,ax=plt.subplots()
58+
59+
ax2=ax.twinx()
60+
61+
ax.plot([0,10])
62+
ax2.plot([12,10])
63+
64+
ax.set_box_aspect(1)
65+
66+
plt.show()
67+
68+
69+
############################################################################
70+
# Normal plot next to image
71+
# ~~~~~~~~~~~~~~~~~~~~~~~~~
72+
#
73+
# When creating an image plot with fixed data aspect and the default
74+
# ``adjustable="box"`` next to a normal plot, the axes would be unequal in
75+
# height. `~Axes.set_box_aspect` provides an easy solution to that by allowing
76+
# to have the normal plot's axes use the images dimensions as box aspect.
77+
#
78+
# This example also shows that ``constrained_layout`` interplays nicely with
79+
# a fixed box aspect.
80+
81+
fig4, (ax,ax2)=plt.subplots(ncols=2,constrained_layout=True)
82+
83+
im=np.random.rand(16,27)
84+
ax.imshow(im)
85+
86+
ax2.plot([23,45])
87+
ax2.set_box_aspect(im.shape[0]/im.shape[1])
88+
89+
plt.show()
90+
91+
############################################################################
92+
# Square joint/marginal plot
93+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~
94+
#
95+
# It may be desireable to show marginal distributions next to a plot of joint
96+
# data. The following creates a square plot with the box aspect of the
97+
# marginal axes being equal to the width- and height-ratios of the gridspec.
98+
# This ensures that all axes align perfectly, independent on the size of the
99+
# figure.
100+
101+
fig5,axs=plt.subplots(2,2,sharex="col",sharey="row",
102+
gridspec_kw=dict(height_ratios=[1,3],
103+
width_ratios=[3,1]))
104+
axs[0,1].set_visible(False)
105+
axs[0,0].set_box_aspect(1/3)
106+
axs[1,0].set_box_aspect(1)
107+
axs[1,1].set_box_aspect(3/1)
108+
109+
x,y=np.random.randn(2,400)*np.array([[.5], [180]])
110+
axs[1,0].scatter(x,y)
111+
axs[0,0].hist(x)
112+
axs[1,1].hist(y,orientation="horizontal")
113+
114+
plt.show()
115+
116+
############################################################################
117+
# Square joint/marginal plot
118+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~
119+
#
120+
# When setting the box aspect, one may still set the data aspect as well.
121+
# Here we create an axes with a box twice as long as tall and use an "equal"
122+
# data aspect for its contents, i.e. the circle actually stays circular.
123+
124+
fig6,ax=plt.subplots()
125+
126+
ax.add_patch(plt.Circle((5,3),1))
127+
ax.set_aspect("equal",adjustable="datalim")
128+
ax.set_box_aspect(0.5)
129+
ax.autoscale()
130+
131+
plt.show()
132+
133+
#############################################################################
134+
#
135+
# ------------
136+
#
137+
# References
138+
# """"""""""
139+
#
140+
# The use of the following functions, methods and classes is shown
141+
# in this example:
142+
143+
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
defget_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
returnself._adjustable
12861299

12871300
defset_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+
defget_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+
returnself._box_aspect
1362+
1363+
defset_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+
ifaspectisnotNone:
1387+
aspect=float(aspect)
1388+
# when box_aspect is set to other than ´None`,
1389+
# adjustable must be "datalim"
1390+
foraxinaxs:
1391+
ax.set_adjustable("datalim")
1392+
1393+
foraxinaxs:
1394+
ax._box_aspect=aspect
1395+
ax.stale=True
1396+
13361397
defget_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-
ifaspect=='auto':
1528+
ifaspect=='auto'andself._box_aspectisNone:
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+
ifself._box_aspectisnotNone:
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+
ifaspect=="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+
ifself._box_aspectisNone:
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
assertax.get_xlim()==pytest.approx(np.array([1/10,10])*np.sqrt(10))
6563+
6564+
6565+
deftest_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+
deftest_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)

[8]ページ先頭

©2009-2025 Movatter.jp