Skip to content

Commit aa5228b

Browse files
committed
Fixed calculation errors. Updated tests and image.
1 parent 6b3b815 commit aa5228b

File tree

3 files changed

+56
-24
lines changed

3 files changed

+56
-24
lines changed

lib/mpl_toolkits/mplot3d/axes3d.py

+38-23
Original file line numberDiff line numberDiff line change
@@ -267,8 +267,7 @@ def tunit_edges(self, vals=None, M=None):
267267
(tc[7], tc[4])]
268268
return edges
269269

270-
def set_aspect(self, aspect, adjustable='datalim', anchor=None,
271-
share=False):
270+
def set_aspect(self, aspect, adjustable=None, anchor=None, share=False):
272271
"""
273272
Set the aspect ratios.
274273
@@ -287,9 +286,10 @@ def set_aspect(self, aspect, adjustable='datalim', anchor=None,
287286
'equalyz' adapt the y and z axes to have equal aspect ratios.
288287
========= ==================================================
289288
290-
adjustable : {'datalim', 'box'}, default: 'datalim'
291-
This defines which parameter will be adjusted to meet the required
292-
aspect. See `.set_adjustable` for further details.
289+
adjustable : None or {'box', 'datalim'}, optional
290+
If not *None*, this defines which parameter will be adjusted to
291+
meet the required aspect. See `.set_adjustable` for further
292+
details.
293293
294294
anchor : None or str or 2-tuple of float, optional
295295
If not *None*, this defines where the Axes will be drawn if there
@@ -317,50 +317,65 @@ def set_aspect(self, aspect, adjustable='datalim', anchor=None,
317317
"""
318318
_api.check_in_list(('auto', 'equal', 'equalxy', 'equalyz', 'equalxz'),
319319
aspect=aspect)
320-
_api.check_in_list(('datalim', 'box'), adjustable=adjustable)
320+
if adjustable is None:
321+
adjustable = self._adjustable
322+
_api.check_in_list(('box', 'datalim'), adjustable=adjustable)
321323
super().set_aspect(
322324
aspect='auto', adjustable=adjustable, anchor=anchor, share=share)
323325
self._aspect = aspect
324326

325327
if aspect in ('equal', 'equalxy', 'equalxz', 'equalyz'):
326-
if aspect == 'equal':
327-
ax_indices = [0, 1, 2]
328-
elif aspect == 'equalxy':
329-
ax_indices = [0, 1]
330-
elif aspect == 'equalxz':
331-
ax_indices = [0, 2]
332-
elif aspect == 'equalyz':
333-
ax_indices = [1, 2]
328+
ax_idx = self._equal_aspect_axis_indices(aspect)
334329

335330
view_intervals = np.array([self.xaxis.get_view_interval(),
336331
self.yaxis.get_view_interval(),
337332
self.zaxis.get_view_interval()])
338333
ptp = np.ptp(view_intervals, axis=1)
339334
if adjustable == 'datalim':
340335
mean = np.mean(view_intervals, axis=1)
341-
delta = max(ptp[ax_indices])
336+
delta = max(ptp[ax_idx])
342337
scale = self._box_aspect[ptp == delta][0]
343338
deltas = delta * self._box_aspect / scale
344339

345340
for i, set_lim in enumerate((self.set_xlim3d,
346341
self.set_ylim3d,
347342
self.set_zlim3d)):
348-
if i in ax_indices:
343+
if i in ax_idx:
349344
set_lim(mean[i] - deltas[i]/2., mean[i] + deltas[i]/2.)
350345
else: # 'box'
351346
# Change the box aspect such that the ratio of the length of
352347
# the unmodified axis to the length of the diagonal
353348
# perpendicular to it remains unchanged.
354349
box_aspect = np.array(self._box_aspect)
355-
box_aspect[ax_indices] = ptp[ax_indices]
356-
remaining_ax_indices = {0, 1, 2}.difference(ax_indices)
357-
if remaining_ax_indices:
358-
remaining_ax_index = remaining_ax_indices.pop()
359-
old_diag = np.linalg.norm(box_aspect[ax_indices])
360-
new_diag = np.linalg.norm(ptp[ax_indices])
361-
box_aspect[remaining_ax_index] *= new_diag / old_diag
350+
box_aspect[ax_idx] = ptp[ax_idx]
351+
remaining_ax_idx = {0, 1, 2}.difference(ax_idx)
352+
if remaining_ax_idx:
353+
remaining = remaining_ax_idx.pop()
354+
old_diag = np.linalg.norm(self._box_aspect[ax_idx])
355+
new_diag = np.linalg.norm(box_aspect[ax_idx])
356+
box_aspect[remaining] *= new_diag / old_diag
362357
self.set_box_aspect(box_aspect)
363358

359+
def _equal_aspect_axis_indices(self, aspect):
360+
"""
361+
Get the indices for which of the x, y, z axes are constrained to have
362+
equal aspect ratios.
363+
Parameters
364+
----------
365+
aspect : {'auto', 'equal', 'equalxy', 'equalxz', 'equalyz'}
366+
See descriptions in docstring for `.set_aspect()`.
367+
"""
368+
ax_indices = [] # aspect == 'auto'
369+
if aspect == 'equal':
370+
ax_indices = [0, 1, 2]
371+
elif aspect == 'equalxy':
372+
ax_indices = [0, 1]
373+
elif aspect == 'equalxz':
374+
ax_indices = [0, 2]
375+
elif aspect == 'equalyz':
376+
ax_indices = [1, 2]
377+
return ax_indices
378+
364379
def set_box_aspect(self, aspect, *, zoom=1):
365380
"""
366381
Set the Axes box aspect.

lib/mpl_toolkits/tests/test_mplot3d.py

+18-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,24 @@ def test_aspects():
4444
ax.plot3D(*zip(start*scale, end*scale))
4545
for i, ax in enumerate(axs):
4646
ax.set_box_aspect((3, 4, 5))
47-
ax.set_aspect(aspects[i])
47+
ax.set_aspect(aspects[i], adjustable='datalim')
48+
49+
50+
@mpl3d_image_comparison(['aspects_adjust_box.png'], remove_text=False)
51+
def test_aspects_adjust_box():
52+
aspects = ('auto', 'equal', 'equalxy', 'equalyz', 'equalxz')
53+
fig, axs = plt.subplots(1, len(aspects), subplot_kw={'projection': '3d'})
54+
55+
# Draw rectangular cuboid with side lengths [1, 1, 5]
56+
r = [0, 1]
57+
scale = np.array([1, 1, 5])
58+
pts = itertools.combinations(np.array(list(itertools.product(r, r, r))), 2)
59+
for start, end in pts:
60+
if np.sum(np.abs(start - end)) == r[1] - r[0]:
61+
for ax in axs:
62+
ax.plot3D(*zip(start*scale, end*scale))
63+
for i, ax in enumerate(axs):
64+
ax.set_aspect(aspects[i], adjustable='box')
4865

4966

5067
def test_axes3d_repr():

0 commit comments

Comments
 (0)