@@ -271,22 +271,19 @@ def set_aspect(self, aspect, adjustable=None, anchor=None, share=False):
271271 """
272272 Set the aspect ratios.
273273
274- Axes 3D does not current support any aspect but 'auto' which fills
275- the Axes with the data limits.
276-
277- To simulate having equal aspect in data space, set the ratio
278- of your data limits to match the value of `.get_box_aspect`.
279- To control box aspect ratios use `~.Axes3D.set_box_aspect`.
280-
281274 Parameters
282275 ----------
283- aspect : {'auto'}
276+ aspect : {'auto', 'equal', 'equalxy', 'equalxz', 'equalyz' }
284277 Possible values:
285278
286279 ========= ==================================================
287280 value description
288281 ========= ==================================================
289282 'auto' automatic; fill the position rectangle with data.
283+ 'equal' adapt all the axes to have equal aspect ratios.
284+ 'equalxy' adapt the x and y axes to have equal aspect ratios.
285+ 'equalxz' adapt the x and z axes to have equal aspect ratios.
286+ 'equalyz' adapt the y and z axes to have equal aspect ratios.
290287 ========= ==================================================
291288
292289 adjustable : None
@@ -320,13 +317,36 @@ def set_aspect(self, aspect, adjustable=None, anchor=None, share=False):
320317 --------
321318 mpl_toolkits.mplot3d.axes3d.Axes3D.set_box_aspect
322319 """
323- if aspect != 'auto' :
324- raise NotImplementedError (
325- "Axes3D currently only supports the aspect argument "
326- f"'auto'. You passed in { aspect !r} ."
327- )
320+ _api .check_in_list (('auto' , 'equal' , 'equalxy' , 'equalyz' , 'equalxz' ),
321+ aspect = aspect )
328322 super ().set_aspect (
329- aspect , adjustable = adjustable , anchor = anchor , share = share )
323+ aspect = 'auto' , adjustable = adjustable , anchor = anchor , share = share )
324+ self ._aspect = aspect
325+
326+ 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 ]
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+ 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. )
330350
331351 def set_box_aspect (self , aspect , * , zoom = 1 ):
332352 """
0 commit comments