Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 25986cd

Browse files
committed
Implement lazy autoscaling in mplot3d.
Since `Axes3D` derives from 2D `Axes`, this lazy autoscale was partially implemented. This might cause extraneous re-scaling since the 3D case did not always turn it off. It might also cause re-scaling to be missed since 2D `Axes` does not check z. Fixes #18112.
1 parent 29ba9a9 commit 25986cd

File tree

1 file changed

+66
-4
lines changed

1 file changed

+66
-4
lines changed

lib/mpl_toolkits/mplot3d/axes3d.py

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ def __init__(
9292
self.zz_viewLim = Bbox.unit()
9393
self.xy_dataLim = Bbox.unit()
9494
self.zz_dataLim = Bbox.unit()
95+
self._stale_viewlim_z = False
9596

9697
# inhibit autoscale_view until the axes are defined
9798
# they can't be defined until Axes.__init__ has been called
@@ -230,6 +231,24 @@ def w_zaxis(self):
230231
def _get_axis_list(self):
231232
return super()._get_axis_list() + (self.zaxis, )
232233

234+
def _unstale_viewLim(self):
235+
# We should arrange to store this information once per share-group
236+
# instead of on every axis.
237+
scalex = any(ax._stale_viewlim_x
238+
for ax in self._shared_x_axes.get_siblings(self))
239+
scaley = any(ax._stale_viewlim_y
240+
for ax in self._shared_y_axes.get_siblings(self))
241+
scalez = any(ax._stale_viewlim_z
242+
for ax in self._shared_z_axes.get_siblings(self))
243+
if scalex or scaley or scalez:
244+
for ax in self._shared_x_axes.get_siblings(self):
245+
ax._stale_viewlim_x = False
246+
for ax in self._shared_y_axes.get_siblings(self):
247+
ax._stale_viewlim_y = False
248+
for ax in self._shared_z_axes.get_siblings(self):
249+
ax._stale_viewlim_z = False
250+
self.autoscale_view(scalex=scalex, scaley=scaley, scalez=scalez)
251+
233252
def unit_cube(self, vals=None):
234253
minx, maxx, miny, maxy, minz, maxz = vals or self.get_w_lims()
235254
return [(minx, miny, minz),
@@ -478,7 +497,8 @@ def _on_units_changed(self, scalex=False, scaley=False, scalez=False):
478497
Currently forces updates of data limits and view limits.
479498
"""
480499
self.relim()
481-
self.autoscale_view(scalex=scalex, scaley=scaley, scalez=scalez)
500+
self._request_autoscale_view(scalex=scalex, scaley=scaley,
501+
scalez=scalez)
482502

483503
def update_datalim(self, xys, **kwargs):
484504
pass
@@ -527,6 +547,24 @@ def set_autoscalez_on(self, b):
527547
"""
528548
self._autoscaleZon = b
529549

550+
def set_xmargin(self, m):
551+
# docstring inherited
552+
scalez = self._stale_viewlim_z
553+
super().set_xmargin(m)
554+
# Superclass is 2D and will call _request_autoscale_view with defaults
555+
# for unknown Axis, which would be scalez=True, but it shouldn't be for
556+
# this call, so restore it.
557+
self._stale_viewlim_z = scalez
558+
559+
def set_ymargin(self, m):
560+
# docstring inherited
561+
scalez = self._stale_viewlim_z
562+
super().set_ymargin(m)
563+
# Superclass is 2D and will call _request_autoscale_view with defaults
564+
# for unknown Axis, which would be scalez=True, but it shouldn't be for
565+
# this call, so restore it.
566+
self._stale_viewlim_z = scalez
567+
530568
def set_zmargin(self, m):
531569
"""
532570
Set padding of Z data limits prior to autoscaling.
@@ -541,6 +579,7 @@ def set_zmargin(self, m):
541579
if m < 0 or m > 1:
542580
raise ValueError("margin must be in range 0 to 1")
543581
self._zmargin = m
582+
self._request_autoscale_view(scalex=False, scaley=False, scalez=True)
544583
self.stale = True
545584

546585
def margins(self, *margins, x=None, y=None, z=None, tight=True):
@@ -638,8 +677,8 @@ def autoscale(self, enable=True, axis='both', tight=None):
638677
self._autoscaleZon = scalez = bool(enable)
639678
else:
640679
scalez = False
641-
self.autoscale_view(tight=tight, scalex=scalex, scaley=scaley,
642-
scalez=scalez)
680+
self._request_autoscale_view(tight=tight, scalex=scalex, scaley=scaley,
681+
scalez=scalez)
643682

644683
def auto_scale_xyz(self, X, Y, Z=None, had_data=None):
645684
# This updates the bounding boxes as to keep a record as to what the
@@ -655,6 +694,19 @@ def auto_scale_xyz(self, X, Y, Z=None, had_data=None):
655694
# Let autoscale_view figure out how to use this data.
656695
self.autoscale_view()
657696

697+
# API could be better, right now this is just to match the old calls to
698+
# autoscale_view() after each plotting method.
699+
def _request_autoscale_view(self, tight=None, scalex=True, scaley=True,
700+
scalez=True):
701+
if tight is not None:
702+
self._tight = tight
703+
if scalex:
704+
self._stale_viewlim_x = True # Else keep old state.
705+
if scaley:
706+
self._stale_viewlim_y = True
707+
if scalez:
708+
self._stale_viewlim_z = True
709+
658710
def autoscale_view(self, tight=None, scalex=True, scaley=True,
659711
scalez=True):
660712
"""
@@ -765,6 +817,9 @@ def set_xlim3d(self, left=None, right=None, emit=True, auto=False,
765817
left, right = sorted([left, right], reverse=bool(reverse))
766818
self.xy_viewLim.intervalx = (left, right)
767819

820+
# Mark viewlims as no longer stale without triggering an autoscale.
821+
for ax in self._shared_x_axes.get_siblings(self):
822+
ax._stale_viewlim_x = False
768823
if auto is not None:
769824
self._autoscaleXon = bool(auto)
770825

@@ -820,6 +875,9 @@ def set_ylim3d(self, bottom=None, top=None, emit=True, auto=False,
820875
bottom, top = top, bottom
821876
self.xy_viewLim.intervaly = (bottom, top)
822877

878+
# Mark viewlims as no longer stale without triggering an autoscale.
879+
for ax in self._shared_y_axes.get_siblings(self):
880+
ax._stale_viewlim_y = False
823881
if auto is not None:
824882
self._autoscaleYon = bool(auto)
825883

@@ -875,6 +933,9 @@ def set_zlim3d(self, bottom=None, top=None, emit=True, auto=False,
875933
bottom, top = top, bottom
876934
self.zz_viewLim.intervalx = (bottom, top)
877935

936+
# Mark viewlims as no longer stale without triggering an autoscale.
937+
for ax in self._shared_z_axes.get_siblings(self):
938+
ax._stale_viewlim_z = False
878939
if auto is not None:
879940
self._autoscaleZon = bool(auto)
880941

@@ -1331,7 +1392,8 @@ def locator_params(self, axis='both', tight=None, **kwargs):
13311392
self.yaxis.get_major_locator().set_params(**kwargs)
13321393
if _z:
13331394
self.zaxis.get_major_locator().set_params(**kwargs)
1334-
self.autoscale_view(tight=tight, scalex=_x, scaley=_y, scalez=_z)
1395+
self._request_autoscale_view(tight=tight, scalex=_x, scaley=_y,
1396+
scalez=_z)
13351397

13361398
def tick_params(self, axis='both', **kwargs):
13371399
"""

0 commit comments

Comments
 (0)