Skip to content

Commit cc9e7ba

Browse files
Add equalxy, equalyz, equalxz aspect ratios
Update docstrings
1 parent 5b9f3c0 commit cc9e7ba

File tree

3 files changed

+51
-41
lines changed

3 files changed

+51
-41
lines changed

doc/users/next_whats_new/3d_plot_aspects.rst

+6-2
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,17 @@ Users can set the aspect ratio for the X, Y, Z axes of a 3D plot to be 'equal',
77
.. plot::
88
:include-source: true
99

10+
import matplotlib.pyplot as plt
11+
import numpy as np
12+
from itertools import combinations, product
13+
1014
aspects = ('auto', 'equal', 'equalxy', 'equalyz', 'equalxz')
1115
fig, axs = plt.subplots(1, len(aspects), subplot_kw={'projection': '3d'})
1216

1317
# Draw rectangular cuboid with side lengths [1, 1, 2]
1418
r = [0, 1]
1519
scale = np.array([1, 1, 2])
16-
pts = itertools.combinations(np.array(list(itertools.product(r, r, r))), 2)
20+
pts = combinations(np.array(list(product(r, r, r))), 2)
1721
for start, end in pts:
1822
if np.sum(np.abs(start - end)) == r[1] - r[0]:
1923
for ax in axs:
@@ -23,6 +27,6 @@ Users can set the aspect ratio for the X, Y, Z axes of a 3D plot to be 'equal',
2327
for i, ax in enumerate(axs):
2428
ax.set_box_aspect((3, 4, 5))
2529
ax.set_aspect(aspects[i])
26-
ax.title(f"set_aspect('{aspects[i]}')")
30+
ax.set_title("set_aspect('{aspects[i]}')")
2731

2832
plt.show()

lib/mpl_toolkits/mplot3d/axes3d.py

+29-18
Original file line numberDiff line numberDiff line change
@@ -274,14 +274,17 @@ def set_aspect(self, aspect, adjustable=None, anchor=None, share=False):
274274
275275
Parameters
276276
----------
277-
aspect : {'auto', 'equal'}
277+
aspect : {'auto', 'equal', 'equalxy', 'equalxz', 'equalyz'}
278278
Possible values:
279279
280280
========= ==================================================
281281
value description
282282
========= ==================================================
283283
'auto' automatic; fill the position rectangle with data.
284-
'equal' adapt the axes to have equal aspect ratios.
284+
'equal' adapt all the axes to have equal aspect ratios.
285+
'equalxy' adapt the x and y axes to have equal aspect ratios.
286+
'equalxz' adapt the x and z axes to have equal aspect ratios.
287+
'equalyz' adapt the y and z axes to have equal aspect ratios.
285288
========= ==================================================
286289
287290
adjustable : None
@@ -315,25 +318,33 @@ def set_aspect(self, aspect, adjustable=None, anchor=None, share=False):
315318
--------
316319
mpl_toolkits.mplot3d.axes3d.Axes3D.set_box_aspect
317320
"""
318-
if aspect not in ('auto', 'equal'):
319-
raise NotImplementedError(
320-
"Axes3D currently only supports the aspect argument "
321-
f"'auto' or 'equal'. You passed in {aspect!r}."
322-
)
321+
_api.check_in_list(('auto', 'equal', 'equalxy', 'equalyz', 'equalxz'),
322+
aspect=aspect)
323323
super().set_aspect(
324-
aspect, adjustable=adjustable, anchor=anchor, share=share)
325-
326-
if aspect == 'equal':
327-
v_intervals = np.vstack((self.xaxis.get_view_interval(),
328-
self.yaxis.get_view_interval(),
329-
self.zaxis.get_view_interval()))
330-
mean = np.mean(v_intervals, axis=1)
331-
delta = np.max(np.ptp(v_intervals, axis=1))
324+
aspect='auto', adjustable=adjustable, anchor=anchor, share=share)
325+
326+
if aspect in ('equal', 'equalxy', 'equalxz', 'equalyz'):
327+
if aspect == 'equal':
328+
axis_indices = [0, 1, 2]
329+
elif aspect == 'equalxy':
330+
axis_indices = [0, 1]
331+
elif aspect == 'equalxz':
332+
axis_indices = [0, 2]
333+
elif aspect == 'equalyz':
334+
axis_indices = [1, 2]
335+
336+
view_intervals = np.array([self.xaxis.get_view_interval(),
337+
self.yaxis.get_view_interval(),
338+
self.zaxis.get_view_interval()])
339+
mean = np.mean(view_intervals, axis=1)
340+
delta = np.max(np.ptp(view_intervals, axis=1))
332341
deltas = delta * self._box_aspect / min(self._box_aspect)
333342

334-
self.set_xlim3d(mean[0] - deltas[0] / 2., mean[0] + deltas[0] / 2.)
335-
self.set_ylim3d(mean[1] - deltas[1] / 2., mean[1] + deltas[1] / 2.)
336-
self.set_zlim3d(mean[2] - deltas[2] / 2., mean[2] + deltas[2] / 2.)
343+
for i, set_lim in enumerate((self.set_xlim3d,
344+
self.set_ylim3d,
345+
self.set_zlim3d)):
346+
if i in axis_indices:
347+
set_lim(mean[i] - deltas[i]/2., mean[i] + deltas[i]/2.)
337348

338349
def set_box_aspect(self, aspect, *, zoom=1):
339350
"""

lib/mpl_toolkits/tests/test_mplot3d.py

+16-21
Original file line numberDiff line numberDiff line change
@@ -27,27 +27,22 @@ def test_invisible_axes(fig_test, fig_ref):
2727
ax.set_visible(False)
2828

2929

30-
@mpl3d_image_comparison(['aspect_equal.png'], remove_text=False)
31-
def test_aspect_equal():
32-
fig = plt.figure()
33-
ax = fig.add_subplot(projection='3d')
34-
35-
points = np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 0],
36-
[0, 0, 3], [1, 0, 3], [0, 1, 3], [1, 1, 3]])
37-
38-
x = np.asarray([coord[0] for coord in points])
39-
y = np.asarray([coord[1] for coord in points])
40-
z = np.asarray([coord[2] for coord in points])
41-
42-
def plot_edge(i, j):
43-
ax.plot([x[i], x[j]], [y[i], y[j]], [z[i], z[j]], c='r')
44-
45-
# hexaedron creation
46-
plot_edge(0, 1), plot_edge(1, 3), plot_edge(3, 2), plot_edge(2, 0)
47-
plot_edge(4, 5), plot_edge(5, 7), plot_edge(7, 6), plot_edge(6, 4)
48-
plot_edge(0, 4), plot_edge(1, 5), plot_edge(3, 7), plot_edge(2, 6)
49-
50-
ax.set_aspect('equal')
30+
@mpl3d_image_comparison(['aspects.png'], remove_text=False)
31+
def test_aspects():
32+
aspects = ('auto', 'equal', 'equalxy', 'equalyz', 'equalxz')
33+
fig, axs = plt.subplots(1, len(aspects), subplot_kw={'projection': '3d'})
34+
35+
# Draw rectangular cuboid with side lengths [1, 1, 2]
36+
r = [0, 1]
37+
scale = np.array([1, 1, 2])
38+
pts = itertools.combinations(np.array(list(itertools.product(r, r, r))), 2)
39+
for start, end in pts:
40+
if np.sum(np.abs(start - end)) == r[1] - r[0]:
41+
for ax in axs:
42+
ax.plot3D(*zip(start*scale, end*scale))
43+
for i, ax in enumerate(axs):
44+
ax.set_box_aspect((3, 4, 5))
45+
ax.set_aspect(aspects[i])
5146

5247

5348
@mpl3d_image_comparison(['bar3d.png'])

0 commit comments

Comments
 (0)