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

Commit68af0c2

Browse files
box aspect for axes
1 parent1f003b0 commit68af0c2

File tree

4 files changed

+281
-3
lines changed

4 files changed

+281
-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.
@@ -1462,7 +1523,7 @@ def apply_aspect(self, position=None):
14621523

14631524
aspect=self.get_aspect()
14641525

1465-
ifaspect=='auto':
1526+
ifaspect=='auto'andself._box_aspectisNone:
14661527
self._set_position(position,which='active')
14671528
return
14681529

@@ -1482,11 +1543,20 @@ def apply_aspect(self, position=None):
14821543
self._set_position(pb1.anchored(self.get_anchor(),pb),'active')
14831544
return
14841545

1485-
# self._adjustable == 'datalim'
1546+
# The following is only seen if self._adjustable == 'datalim'
1547+
ifself._box_aspectisnotNone:
1548+
pb=position.frozen()
1549+
pb1=pb.shrunk_to_aspect(self._box_aspect,pb,fig_aspect)
1550+
self._set_position(pb1.anchored(self.get_anchor(),pb),'active')
1551+
ifaspect=="auto":
1552+
return
14861553

14871554
# reset active to original in case it had been changed by prior use
14881555
# of 'box'
1489-
self._set_position(position,which='active')
1556+
ifself._box_aspectisNone:
1557+
self._set_position(position,which='active')
1558+
else:
1559+
position=pb1.anchored(self.get_anchor(),pb)
14901560

14911561
x_trf=self.xaxis.get_transform()
14921562
y_trf=self.yaxis.get_transform()

‎lib/matplotlib/tests/test_axes.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6565,5 +6565,56 @@ def test_aspect_nonlinear_adjustable_datalim():
65656565
aspect=1,adjustable="datalim")
65666566
ax.margins(0)
65676567
ax.apply_aspect()
6568+
65686569
assertax.get_xlim()==pytest.approx([1*10**(1/2),100/10**(1/2)])
65696570
assertax.get_ylim()== (1/101,1/11)
6571+
6572+
6573+
deftest_box_aspect():
6574+
# Test if axes with box_aspect=1 has same dimensions
6575+
# as axes with aspect equal and adjustable="box"
6576+
6577+
fig1,ax1=plt.subplots()
6578+
axtwin=ax1.twinx()
6579+
axtwin.plot([12,344])
6580+
6581+
ax1.set_box_aspect(1)
6582+
6583+
fig2,ax2=plt.subplots()
6584+
ax2.margins(0)
6585+
ax2.plot([0,2], [6,8])
6586+
ax2.set_aspect("equal",adjustable="box")
6587+
6588+
fig1.canvas.draw()
6589+
fig2.canvas.draw()
6590+
6591+
bb1=ax1.get_position()
6592+
bbt=axtwin.get_position()
6593+
bb2=ax2.get_position()
6594+
6595+
assert_array_equal(bb1.extents,bb2.extents)
6596+
assert_array_equal(bbt.extents,bb2.extents)
6597+
6598+
6599+
deftest_box_aspect_custom_position():
6600+
# Test if axes with custom position and box_aspect
6601+
# behaves the same independent of the order of setting those.
6602+
6603+
fig1,ax1=plt.subplots()
6604+
ax1.set_position([0.1,0.1,0.9,0.2])
6605+
fig1.canvas.draw()
6606+
ax1.set_box_aspect(1.)
6607+
6608+
fig2,ax2=plt.subplots()
6609+
ax2.set_box_aspect(1.)
6610+
fig2.canvas.draw()
6611+
ax2.set_position([0.1,0.1,0.9,0.2])
6612+
6613+
fig1.canvas.draw()
6614+
fig2.canvas.draw()
6615+
6616+
bb1=ax1.get_position()
6617+
bb2=ax2.get_position()
6618+
6619+
assert_array_equal(bb1.extents,bb2.extents)
6620+

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp