@@ -286,9 +286,7 @@ def set_aspect(self, aspect, adjustable=None, anchor=None, share=False):
286
286
'equalyz' adapt the y and z axes to have equal aspect ratios.
287
287
========= ==================================================
288
288
289
- adjustable : None
290
- Currently ignored by Axes3D
291
-
289
+ adjustable : None or {'box', 'datalim'}, optional
292
290
If not *None*, this defines which parameter will be adjusted to
293
291
meet the required aspect. See `.set_adjustable` for further
294
292
details.
@@ -319,34 +317,65 @@ def set_aspect(self, aspect, adjustable=None, anchor=None, share=False):
319
317
"""
320
318
_api .check_in_list (('auto' , 'equal' , 'equalxy' , 'equalyz' , 'equalxz' ),
321
319
aspect = aspect )
320
+ if adjustable is None :
321
+ adjustable = self ._adjustable
322
+ _api .check_in_list (('box' , 'datalim' ), adjustable = adjustable )
322
323
super ().set_aspect (
323
324
aspect = 'auto' , adjustable = adjustable , anchor = anchor , share = share )
324
325
self ._aspect = aspect
325
326
326
327
if aspect in ('equal' , 'equalxy' , 'equalxz' , 'equalyz' ):
327
- if aspect == 'equal' :
328
- ax_indices = [0 , 1 , 2 ]
329
- elif aspect == 'equalxy' :
330
- ax_indices = [0 , 1 ]
331
- elif aspect == 'equalxz' :
332
- ax_indices = [0 , 2 ]
333
- elif aspect == 'equalyz' :
334
- ax_indices = [1 , 2 ]
328
+ ax_idx = self ._equal_aspect_axis_indices (aspect )
335
329
336
330
view_intervals = np .array ([self .xaxis .get_view_interval (),
337
331
self .yaxis .get_view_interval (),
338
332
self .zaxis .get_view_interval ()])
339
- mean = np .mean (view_intervals , axis = 1 )
340
333
ptp = np .ptp (view_intervals , axis = 1 )
341
- delta = max (ptp [ax_indices ])
342
- scale = self ._box_aspect [ptp == delta ][0 ]
343
- deltas = delta * self ._box_aspect / scale
344
-
345
- for i , set_lim in enumerate ((self .set_xlim3d ,
346
- self .set_ylim3d ,
347
- self .set_zlim3d )):
348
- if i in ax_indices :
349
- set_lim (mean [i ] - deltas [i ]/ 2. , mean [i ] + deltas [i ]/ 2. )
334
+ if adjustable == 'datalim' :
335
+ mean = np .mean (view_intervals , axis = 1 )
336
+ delta = max (ptp [ax_idx ])
337
+ scale = self ._box_aspect [ptp == delta ][0 ]
338
+ deltas = delta * self ._box_aspect / scale
339
+
340
+ for i , set_lim in enumerate ((self .set_xlim3d ,
341
+ self .set_ylim3d ,
342
+ self .set_zlim3d )):
343
+ if i in ax_idx :
344
+ set_lim (mean [i ] - deltas [i ]/ 2. , mean [i ] + deltas [i ]/ 2. )
345
+ else : # 'box'
346
+ # Change the box aspect such that the ratio of the length of
347
+ # the unmodified axis to the length of the diagonal
348
+ # perpendicular to it remains unchanged.
349
+ box_aspect = np .array (self ._box_aspect )
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
357
+ self .set_box_aspect (box_aspect )
358
+
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
+
364
+ Parameters
365
+ ----------
366
+ aspect : {'auto', 'equal', 'equalxy', 'equalxz', 'equalyz'}
367
+ See descriptions in docstring for `.set_aspect()`.
368
+ """
369
+ ax_indices = [] # aspect == 'auto'
370
+ if aspect == 'equal' :
371
+ ax_indices = [0 , 1 , 2 ]
372
+ elif aspect == 'equalxy' :
373
+ ax_indices = [0 , 1 ]
374
+ elif aspect == 'equalxz' :
375
+ ax_indices = [0 , 2 ]
376
+ elif aspect == 'equalyz' :
377
+ ax_indices = [1 , 2 ]
378
+ return ax_indices
350
379
351
380
def set_box_aspect (self , aspect , * , zoom = 1 ):
352
381
"""
0 commit comments