@@ -129,7 +129,9 @@ def __init__(
129
129
130
130
self .xy_viewLim = Bbox .unit ()
131
131
self .zz_viewLim = Bbox .unit ()
132
- self .xy_dataLim = Bbox .unit ()
132
+ xymargin = 0.05 * 10 / 11 # match mpl3.7 appearance
133
+ self .xy_dataLim = Bbox ([[xymargin , xymargin ],
134
+ [1 - xymargin , 1 - xymargin ]])
133
135
# z-limits are encoded in the x-component of the Bbox, y is un-used
134
136
self .zz_dataLim = Bbox .unit ()
135
137
@@ -157,6 +159,9 @@ def __init__(
157
159
self .set_axis_on ()
158
160
self .M = None
159
161
162
+ self ._view_margin = 1 / 48 # default value to match mpl3.7
163
+ self .autoscale_view ()
164
+
160
165
# func used to format z -- fall back on major formatters
161
166
self .fmt_zdata = None
162
167
@@ -336,7 +341,8 @@ def set_aspect(self, aspect, adjustable=None, anchor=None, share=False):
336
341
self .set_ylim3d ,
337
342
self .set_zlim3d )):
338
343
if i in ax_indices :
339
- set_lim (mean [i ] - deltas [i ]/ 2. , mean [i ] + deltas [i ]/ 2. )
344
+ set_lim (mean [i ] - deltas [i ]/ 2. , mean [i ] + deltas [i ]/ 2. ,
345
+ auto = None , view_margin = self ._view_margin )
340
346
else : # 'box'
341
347
# Change the box aspect such that the ratio of the length of
342
348
# the unmodified axis to the length of the diagonal
@@ -404,8 +410,8 @@ def set_box_aspect(self, aspect, *, zoom=1):
404
410
else :
405
411
aspect = np .asarray (aspect , dtype = float )
406
412
_api .check_shape ((3 ,), aspect = aspect )
407
- # default scale tuned to match the mpl32 appearance.
408
- aspect *= 1.8294640721620434 * zoom / np .linalg .norm (aspect )
413
+ # default scale tuned to match the mpl3.2 appearance.
414
+ aspect *= 1.8294640721620434 * 25 / 24 * zoom / np .linalg .norm (aspect )
409
415
410
416
self ._box_aspect = aspect
411
417
self .stale = True
@@ -575,17 +581,17 @@ def autoscale(self, enable=True, axis='both', tight=None):
575
581
scalez = True
576
582
else :
577
583
if axis in ['x' , 'both' ]:
578
- self .set_autoscalex_on (bool ( enable ) )
584
+ self .set_autoscalex_on (enable )
579
585
scalex = self .get_autoscalex_on ()
580
586
else :
581
587
scalex = False
582
588
if axis in ['y' , 'both' ]:
583
- self .set_autoscaley_on (bool ( enable ) )
589
+ self .set_autoscaley_on (enable )
584
590
scaley = self .get_autoscaley_on ()
585
591
else :
586
592
scaley = False
587
593
if axis in ['z' , 'both' ]:
588
- self .set_autoscalez_on (bool ( enable ) )
594
+ self .set_autoscalez_on (enable )
589
595
scalez = self .get_autoscalez_on ()
590
596
else :
591
597
scalez = False
@@ -610,8 +616,8 @@ def auto_scale_xyz(self, X, Y, Z=None, had_data=None):
610
616
# Let autoscale_view figure out how to use this data.
611
617
self .autoscale_view ()
612
618
613
- def autoscale_view (self , tight = None , scalex = True , scaley = True ,
614
- scalez = True ):
619
+ def autoscale_view (self , tight = None ,
620
+ scalex = True , scaley = True , scalez = True ):
615
621
"""
616
622
Autoscale the view limits using the data limits.
617
623
@@ -643,7 +649,7 @@ def autoscale_view(self, tight=None, scalex=True, scaley=True,
643
649
x1 += delta
644
650
if not _tight :
645
651
x0 , x1 = xlocator .view_limits (x0 , x1 )
646
- self .set_xbound (x0 , x1 )
652
+ self .set_xbound (x0 , x1 , self . _view_margin )
647
653
648
654
if scaley and self .get_autoscaley_on ():
649
655
y0 , y1 = self .xy_dataLim .intervaly
@@ -655,7 +661,7 @@ def autoscale_view(self, tight=None, scalex=True, scaley=True,
655
661
y1 += delta
656
662
if not _tight :
657
663
y0 , y1 = ylocator .view_limits (y0 , y1 )
658
- self .set_ybound (y0 , y1 )
664
+ self .set_ybound (y0 , y1 , self . _view_margin )
659
665
660
666
if scalez and self .get_autoscalez_on ():
661
667
z0 , z1 = self .zz_dataLim .intervalx
@@ -667,7 +673,7 @@ def autoscale_view(self, tight=None, scalex=True, scaley=True,
667
673
z1 += delta
668
674
if not _tight :
669
675
z0 , z1 = zlocator .view_limits (z0 , z1 )
670
- self .set_zbound (z0 , z1 )
676
+ self .set_zbound (z0 , z1 , self . _view_margin )
671
677
672
678
def get_w_lims (self ):
673
679
"""Get 3D world limits."""
@@ -676,28 +682,116 @@ def get_w_lims(self):
676
682
minz , maxz = self .get_zlim3d ()
677
683
return minx , maxx , miny , maxy , minz , maxz
678
684
679
- # set_xlim, set_ylim are directly inherited from base Axes.
685
+ def _set_bound3d (self , get_bound , set_lim , axis_inverted ,
686
+ lower = None , upper = None , view_margin = None ):
687
+ """
688
+ Set 3D axis bounds.
689
+ """
690
+ if upper is None and np .iterable (lower ):
691
+ lower , upper = lower
692
+
693
+ old_lower , old_upper = get_bound ()
694
+ if lower is None :
695
+ lower = old_lower
696
+ if upper is None :
697
+ upper = old_upper
698
+
699
+ set_lim (sorted ((lower , upper ), reverse = bool (axis_inverted ())),
700
+ auto = None , view_margin = view_margin )
701
+
702
+ def set_xbound (self , lower = None , upper = None , view_margin = None ):
703
+ # docstring inherited
704
+ self ._set_bound3d (self .get_xbound , self .set_xlim , self .xaxis_inverted ,
705
+ upper , lower , view_margin )
706
+
707
+ def set_ybound (self , lower = None , upper = None , view_margin = None ):
708
+ # docstring inherited
709
+ self ._set_bound3d (self .get_ybound , self .set_ylim , self .yaxis_inverted ,
710
+ upper , lower , view_margin )
711
+
712
+ def set_zbound (self , lower = None , upper = None , view_margin = None ):
713
+ """
714
+ Set the lower and upper numerical bounds of the z-axis.
715
+ This method will honor axis inversion regardless of parameter order.
716
+ It will not change the autoscaling setting (`.get_autoscaley_on()`).
717
+ Parameters
718
+ ----------
719
+ lower, upper : float or None
720
+ The lower and upper bounds. If *None*, the respective axis bound
721
+ is not modified.
722
+ view_margin : float or None
723
+ The margin to apply to the bounds. If *None*, the margin is handled
724
+ by set_zlim.
725
+ See Also
726
+ --------
727
+ get_zbound
728
+ get_zlim, set_zlim
729
+ invert_zaxis, zaxis_inverted
730
+ """
731
+ self ._set_bound3d (self .get_zbound , self .set_zlim , self .zaxis_inverted ,
732
+ upper , lower , view_margin )
733
+
734
+ def _set_lim3d (self , axis , lower = None , upper = None , * , emit = True ,
735
+ auto = False , view_margin = None , axmin = None , axmax = None ):
736
+ """
737
+ Set 3D axis limits.
738
+ See `.Axes.set_ylim` for full documentation
739
+ """
740
+ if upper is None :
741
+ if np .iterable (lower ):
742
+ lower , upper = lower
743
+ else :
744
+ raise ValueError ("Must provide an upper bound." )
745
+ if lower is None :
746
+ raise ValueError ("Must provide a lower bound." )
747
+ if axmin is not None :
748
+ if lower is not None :
749
+ raise TypeError ("Cannot pass both 'lower' and 'min'" )
750
+ lower = axmin
751
+ if axmax is not None :
752
+ if upper is not None :
753
+ raise TypeError ("Cannot pass both 'upper' and 'max'" )
754
+ upper = axmax
755
+ if view_margin is None :
756
+ if mpl .rcParams ['axes3d.automargin' ]:
757
+ view_margin = self ._view_margin
758
+ else :
759
+ view_margin = 0
760
+ delta = (upper - lower ) * view_margin
761
+ lower -= delta
762
+ upper += delta
763
+ return axis ._set_lim (lower , upper , emit = emit , auto = auto )
764
+
765
+ def set_xlim (self , left = None , right = None , * , emit = True , auto = False ,
766
+ view_margin = None , xmin = None , xmax = None ):
767
+ """
768
+ Set 3D x limits.
769
+ See `.Axes.set_xlim` for full documentation
770
+ """
771
+ return self ._set_lim3d (self .xaxis , left , right , emit = emit , auto = auto ,
772
+ view_margin = view_margin , axmin = xmin , axmax = xmax )
773
+
774
+ def set_ylim (self , bottom = None , top = None , * , emit = True , auto = False ,
775
+ view_margin = None , ymin = None , ymax = None ):
776
+ """
777
+ Set 3D y limits.
778
+ See `.Axes.set_ylim` for full documentation
779
+ """
780
+ return self ._set_lim3d (self .yaxis , bottom , top , emit = emit , auto = auto ,
781
+ view_margin = view_margin , axmin = ymin , axmax = ymax )
782
+
680
783
def set_zlim (self , bottom = None , top = None , * , emit = True , auto = False ,
681
- zmin = None , zmax = None ):
784
+ view_margin = None , zmin = None , zmax = None ):
682
785
"""
683
786
Set 3D z limits.
684
787
685
788
See `.Axes.set_ylim` for full documentation
686
789
"""
687
- if top is None and np .iterable (bottom ):
688
- bottom , top = bottom
689
- if zmin is not None :
690
- if bottom is not None :
691
- raise TypeError ("Cannot pass both 'bottom' and 'zmin'" )
692
- bottom = zmin
693
- if zmax is not None :
694
- if top is not None :
695
- raise TypeError ("Cannot pass both 'top' and 'zmax'" )
696
- top = zmax
697
- return self .zaxis ._set_lim (bottom , top , emit = emit , auto = auto )
698
-
699
- set_xlim3d = maxes .Axes .set_xlim
700
- set_ylim3d = maxes .Axes .set_ylim
790
+ return self ._set_lim3d (self .zaxis , bottom , top , emit = emit , auto = auto ,
791
+ view_margin = view_margin , axmin = zmin , axmax = zmax )
792
+
793
+ set_xlim3d = set_xlim
794
+ set_ylim3d = set_ylim
701
795
set_zlim3d = set_zlim
702
796
703
797
def get_xlim (self ):
@@ -982,6 +1076,15 @@ def clear(self):
982
1076
self ._zmargin = mpl .rcParams ['axes.zmargin' ]
983
1077
else :
984
1078
self ._zmargin = 0.
1079
+
1080
+ xymargin = 0.05 * 10 / 11 # match mpl3.7 appearance
1081
+ self .xy_dataLim = Bbox ([[xymargin , xymargin ],
1082
+ [1 - xymargin , 1 - xymargin ]])
1083
+ # z-limits are encoded in the x-component of the Bbox, y is un-used
1084
+ self .zz_dataLim = Bbox .unit ()
1085
+ self ._view_margin = 1 / 48 # default value to match mpl3.7
1086
+ self .autoscale_view ()
1087
+
985
1088
self .grid (mpl .rcParams ['axes3d.grid' ])
986
1089
987
1090
def _button_press (self , event ):
@@ -1162,9 +1265,9 @@ def drag_pan(self, button, key, x, y):
1162
1265
dz = (maxz - minz ) * duvw_projected [2 ]
1163
1266
1164
1267
# Set the new axis limits
1165
- self .set_xlim3d (minx + dx , maxx + dx )
1166
- self .set_ylim3d (miny + dy , maxy + dy )
1167
- self .set_zlim3d (minz + dz , maxz + dz )
1268
+ self .set_xlim3d (minx + dx , maxx + dx , auto = None )
1269
+ self .set_ylim3d (miny + dy , maxy + dy , auto = None )
1270
+ self .set_zlim3d (minz + dz , maxz + dz , auto = None )
1168
1271
1169
1272
def _calc_view_axes (self , eye ):
1170
1273
"""
@@ -1301,9 +1404,9 @@ def _scale_axis_limits(self, scale_x, scale_y, scale_z):
1301
1404
dz = (maxz - minz )* scale_z
1302
1405
1303
1406
# Set the scaled axis limits
1304
- self .set_xlim3d (cx - dx / 2 , cx + dx / 2 )
1305
- self .set_ylim3d (cy - dy / 2 , cy + dy / 2 )
1306
- self .set_zlim3d (cz - dz / 2 , cz + dz / 2 )
1407
+ self .set_xlim3d (cx - dx / 2 , cx + dx / 2 , auto = None )
1408
+ self .set_ylim3d (cy - dy / 2 , cy + dy / 2 , auto = None )
1409
+ self .set_zlim3d (cz - dz / 2 , cz + dz / 2 , auto = None )
1307
1410
1308
1411
def set_zlabel (self , zlabel , fontdict = None , labelpad = None , ** kwargs ):
1309
1412
"""
@@ -1392,26 +1495,6 @@ def get_zbound(self):
1392
1495
else :
1393
1496
return top , bottom
1394
1497
1395
- def set_zbound (self , lower = None , upper = None ):
1396
- """
1397
- Set the lower and upper numerical bounds of the z-axis.
1398
-
1399
- This method will honor axes inversion regardless of parameter order.
1400
- It will not change the autoscaling setting (`.get_autoscalez_on()`).
1401
- """
1402
- if upper is None and np .iterable (lower ):
1403
- lower , upper = lower
1404
-
1405
- old_lower , old_upper = self .get_zbound ()
1406
- if lower is None :
1407
- lower = old_lower
1408
- if upper is None :
1409
- upper = old_upper
1410
-
1411
- self .set_zlim (sorted ((lower , upper ),
1412
- reverse = bool (self .zaxis_inverted ())),
1413
- auto = None )
1414
-
1415
1498
def text (self , x , y , z , s , zdir = None , ** kwargs ):
1416
1499
"""
1417
1500
Add text to the plot.
0 commit comments