Skip to content

Commit e4831cf

Browse files
committed
Make _request_autoscale_view more generalizable to 3D.
The API of _request_autoscale_view() was originally modelled to match the one of autoscale_view() -- hence the scalex/scaley/scalez kwargs -- but just taking an axis name (or "all") as single arg makes generalization to 3D easier. (In bxp(), the autoscale request does not need to be protected by checking whether the autoscale state is on, as autoscale_view is a noop for non-autoscaling axises.)
1 parent b09aad2 commit e4831cf

File tree

3 files changed

+53
-95
lines changed

3 files changed

+53
-95
lines changed

lib/matplotlib/axes/_axes.py

+11-7
Original file line numberDiff line numberDiff line change
@@ -737,7 +737,8 @@ def axhline(self, y=0, xmin=0, xmax=1, **kwargs):
737737
trans = self.get_yaxis_transform(which='grid')
738738
l = mlines.Line2D([xmin, xmax], [y, y], transform=trans, **kwargs)
739739
self.add_line(l)
740-
self._request_autoscale_view(scalex=False, scaley=scaley)
740+
if scaley:
741+
self._request_autoscale_view("y")
741742
return l
742743

743744
@docstring.dedent_interpd
@@ -804,7 +805,8 @@ def axvline(self, x=0, ymin=0, ymax=1, **kwargs):
804805
trans = self.get_xaxis_transform(which='grid')
805806
l = mlines.Line2D([x, x], [ymin, ymax], transform=trans, **kwargs)
806807
self.add_line(l)
807-
self._request_autoscale_view(scalex=scalex, scaley=False)
808+
if scalex:
809+
self._request_autoscale_view("x")
808810
return l
809811

810812
@staticmethod
@@ -934,7 +936,7 @@ def axhspan(self, ymin, ymax, xmin=0, xmax=1, **kwargs):
934936
p = mpatches.Polygon(verts, **kwargs)
935937
p.set_transform(self.get_yaxis_transform(which="grid"))
936938
self.add_patch(p)
937-
self._request_autoscale_view(scalex=False)
939+
self._request_autoscale_view("y")
938940
return p
939941

940942
@docstring.dedent_interpd
@@ -991,7 +993,7 @@ def axvspan(self, xmin, xmax, ymin=0, ymax=1, **kwargs):
991993
p.set_transform(self.get_xaxis_transform(which="grid"))
992994
p.get_path()._interpolation_steps = 100
993995
self.add_patch(p)
994-
self._request_autoscale_view(scaley=False)
996+
self._request_autoscale_view("x")
995997
return p
996998

997999
@_preprocess_data(replace_names=["y", "xmin", "xmax", "colors"],
@@ -1627,7 +1629,10 @@ def plot(self, *args, scalex=True, scaley=True, data=None, **kwargs):
16271629
lines = [*self._get_lines(*args, data=data, **kwargs)]
16281630
for line in lines:
16291631
self.add_line(line)
1630-
self._request_autoscale_view(scalex=scalex, scaley=scaley)
1632+
if scalex:
1633+
self._request_autoscale_view("x")
1634+
if scaley:
1635+
self._request_autoscale_view("y")
16311636
return lines
16321637

16331638
@_preprocess_data(replace_names=["x", "y"], label_namer="y")
@@ -4045,8 +4050,7 @@ def do_patch(xs, ys, **kwargs):
40454050
axis.set_major_formatter(formatter)
40464051
formatter.seq = [*formatter.seq, *datalabels]
40474052

4048-
self._request_autoscale_view(
4049-
scalex=self._autoscaleXon, scaley=self._autoscaleYon)
4053+
self._request_autoscale_view()
40504054

40514055
return dict(whiskers=whiskers, caps=caps, boxes=boxes,
40524056
medians=medians, fliers=fliers, means=means)

lib/matplotlib/axes/_base.py

+35-33
Original file line numberDiff line numberDiff line change
@@ -781,24 +781,26 @@ def viewLim(self):
781781
self._unstale_viewLim()
782782
return self._viewLim
783783

784-
# API could be better, right now this is just to match the old calls to
785-
# autoscale_view() after each plotting method.
786-
def _request_autoscale_view(self, tight=None, **kwargs):
787-
# kwargs are "scalex", "scaley" (& "scalez" for 3D) and default to True
788-
want_scale = {name: True for name in self._axis_names}
789-
for k, v in kwargs.items(): # Validate args before changing anything.
790-
if k.startswith("scale"):
791-
name = k[5:]
792-
if name in want_scale:
793-
want_scale[name] = v
794-
continue
795-
raise TypeError(
796-
f"_request_autoscale_view() got an unexpected argument {k!r}")
784+
def _request_autoscale_view(self, axis="all", tight=None):
785+
"""
786+
Mark a single axis, or all of them, as stale wrt. autoscaling.
787+
788+
No computation is performed until the next autoscaling; thus, separate
789+
calls to control individual axises incur negligible performance cost.
790+
791+
Parameters
792+
----------
793+
axis : str, default: "all"
794+
Either an element of ``self._axis_names``, or "all".
795+
tight : bool or None, default: None
796+
"""
797+
axis_names = _api.check_getitem(
798+
{**{k: [k] for k in self._axis_names}, "all": self._axis_names},
799+
axis=axis)
800+
for name in axis_names:
801+
self._stale_viewlims[name] = True
797802
if tight is not None:
798803
self._tight = tight
799-
for k, v in want_scale.items():
800-
if v:
801-
self._stale_viewlims[k] = True # Else keep old state.
802804

803805
def _set_lim_and_transforms(self):
804806
"""
@@ -2425,8 +2427,7 @@ def _unit_change_handler(self, axis_name, event=None):
24252427
for line in self.lines:
24262428
line.recache_always()
24272429
self.relim()
2428-
self._request_autoscale_view(scalex=(axis_name == "x"),
2429-
scaley=(axis_name == "y"))
2430+
self._request_autoscale_view(axis_name)
24302431

24312432
def relim(self, visible_only=False):
24322433
"""
@@ -2634,7 +2635,7 @@ def set_xmargin(self, m):
26342635
if m <= -0.5:
26352636
raise ValueError("margin must be greater than -0.5")
26362637
self._xmargin = m
2637-
self._request_autoscale_view(scalex=True, scaley=False)
2638+
self._request_autoscale_view("x")
26382639
self.stale = True
26392640

26402641
def set_ymargin(self, m):
@@ -2657,7 +2658,7 @@ def set_ymargin(self, m):
26572658
if m <= -0.5:
26582659
raise ValueError("margin must be greater than -0.5")
26592660
self._ymargin = m
2660-
self._request_autoscale_view(scalex=False, scaley=True)
2661+
self._request_autoscale_view("y")
26612662
self.stale = True
26622663

26632664
def margins(self, *margins, x=None, y=None, tight=True):
@@ -2774,7 +2775,8 @@ def autoscale(self, enable=True, axis='both', tight=None):
27742775
True turns autoscaling on, False turns it off.
27752776
None leaves the autoscaling state unchanged.
27762777
axis : {'both', 'x', 'y'}, default: 'both'
2777-
Which axis to operate on.
2778+
The axis to on which to operate. (For 3D axes, *axis* can also be
2779+
set to 'z', and 'both' refers to all three axes.)
27782780
tight : bool or None, default: None
27792781
If True, first set the margins to zero. Then, this argument is
27802782
forwarded to `autoscale_view` (regardless of its value); see the
@@ -2796,7 +2798,10 @@ def autoscale(self, enable=True, axis='both', tight=None):
27962798
self._xmargin = 0
27972799
if tight and scaley:
27982800
self._ymargin = 0
2799-
self._request_autoscale_view(tight=tight, scalex=scalex, scaley=scaley)
2801+
if scalex:
2802+
self._request_autoscale_view("x", tight=tight)
2803+
if scaley:
2804+
self._request_autoscale_view("y", tight=tight)
28002805

28012806
def autoscale_view(self, tight=None, scalex=True, scaley=True):
28022807
"""
@@ -3312,8 +3317,8 @@ def locator_params(self, axis='both', tight=None, **kwargs):
33123317
Parameters
33133318
----------
33143319
axis : {'both', 'x', 'y'}, default: 'both'
3315-
The axis on which to operate.
3316-
3320+
The axis on which to operate. (For 3D axes, *axis* can also be
3321+
set to 'z', and 'both' refers to all three axes.)
33173322
tight : bool or None, optional
33183323
Parameter passed to `~.Axes.autoscale_view`.
33193324
Default is None, for no change.
@@ -3335,15 +3340,12 @@ def locator_params(self, axis='both', tight=None, **kwargs):
33353340
ax.locator_params(tight=True, nbins=4)
33363341
33373342
"""
3338-
_api.check_in_list(['x', 'y', 'both'], axis=axis)
3339-
update_x = axis in ['x', 'both']
3340-
update_y = axis in ['y', 'both']
3341-
if update_x:
3342-
self.xaxis.get_major_locator().set_params(**kwargs)
3343-
if update_y:
3344-
self.yaxis.get_major_locator().set_params(**kwargs)
3345-
self._request_autoscale_view(tight=tight,
3346-
scalex=update_x, scaley=update_y)
3343+
_api.check_in_list([*self._axis_names, "both"], axis=axis)
3344+
for name in self._axis_names:
3345+
if axis in [name, "both"]:
3346+
loc = self._get_axis_map()[name].get_major_locator()
3347+
loc.set_params(**kwargs)
3348+
self._request_autoscale_view(name, tight=tight)
33473349
self.stale = True
33483350

33493351
def tick_params(self, axis='both', **kwargs):

lib/mpl_toolkits/mplot3d/axes3d.py

+7-55
Original file line numberDiff line numberDiff line change
@@ -476,17 +476,6 @@ def get_axis_position(self):
476476
zhigh = tc[0][2] > tc[2][2]
477477
return xhigh, yhigh, zhigh
478478

479-
def _unit_change_handler(self, axis_name, event=None):
480-
# docstring inherited
481-
if event is None: # Allow connecting `self._unit_change_handler(name)`
482-
return functools.partial(
483-
self._unit_change_handler, axis_name, event=object())
484-
_api.check_in_list(self._get_axis_map(), axis_name=axis_name)
485-
self.relim()
486-
self._request_autoscale_view(scalex=(axis_name == "x"),
487-
scaley=(axis_name == "y"),
488-
scalez=(axis_name == "z"))
489-
490479
def update_datalim(self, xys, **kwargs):
491480
pass
492481

@@ -514,24 +503,6 @@ def set_autoscalez_on(self, b):
514503
"""
515504
self._autoscaleZon = b
516505

517-
def set_xmargin(self, m):
518-
# docstring inherited
519-
scalez = self._stale_viewlims["z"]
520-
super().set_xmargin(m)
521-
# Superclass is 2D and will call _request_autoscale_view with defaults
522-
# for unknown Axis, which would be scalez=True, but it shouldn't be for
523-
# this call, so restore it.
524-
self._stale_viewlims["z"] = scalez
525-
526-
def set_ymargin(self, m):
527-
# docstring inherited
528-
scalez = self._stale_viewlims["z"]
529-
super().set_ymargin(m)
530-
# Superclass is 2D and will call _request_autoscale_view with defaults
531-
# for unknown Axis, which would be scalez=True, but it shouldn't be for
532-
# this call, so restore it.
533-
self._stale_viewlims["z"] = scalez
534-
535506
def set_zmargin(self, m):
536507
"""
537508
Set padding of Z data limits prior to autoscaling.
@@ -544,7 +515,7 @@ def set_zmargin(self, m):
544515
if m < 0 or m > 1:
545516
raise ValueError("margin must be in range 0 to 1")
546517
self._zmargin = m
547-
self._request_autoscale_view(scalex=False, scaley=False, scalez=True)
518+
self._request_autoscale_view("z")
548519
self.stale = True
549520

550521
def margins(self, *margins, x=None, y=None, z=None, tight=True):
@@ -638,8 +609,12 @@ def autoscale(self, enable=True, axis='both', tight=None):
638609
self._autoscaleZon = scalez = bool(enable)
639610
else:
640611
scalez = False
641-
self._request_autoscale_view(tight=tight, scalex=scalex, scaley=scaley,
642-
scalez=scalez)
612+
if scalex:
613+
self._request_autoscale_view("x", tight=tight)
614+
if scaley:
615+
self._request_autoscale_view("y", tight=tight)
616+
if scalez:
617+
self._request_autoscale_view("z", tight=tight)
643618

644619
def auto_scale_xyz(self, X, Y, Z=None, had_data=None):
645620
# This updates the bounding boxes as to keep a record as to what the
@@ -1343,29 +1318,6 @@ def grid(self, visible=True, **kwargs):
13431318
self._draw_grid = visible
13441319
self.stale = True
13451320

1346-
def locator_params(self, axis='both', tight=None, **kwargs):
1347-
"""
1348-
Convenience method for controlling tick locators.
1349-
1350-
See :meth:`matplotlib.axes.Axes.locator_params` for full
1351-
documentation. Note that this is for Axes3D objects,
1352-
therefore, setting *axis* to 'both' will result in the
1353-
parameters being set for all three axes. Also, *axis*
1354-
can also take a value of 'z' to apply parameters to the
1355-
z axis.
1356-
"""
1357-
_x = axis in ['x', 'both']
1358-
_y = axis in ['y', 'both']
1359-
_z = axis in ['z', 'both']
1360-
if _x:
1361-
self.xaxis.get_major_locator().set_params(**kwargs)
1362-
if _y:
1363-
self.yaxis.get_major_locator().set_params(**kwargs)
1364-
if _z:
1365-
self.zaxis.get_major_locator().set_params(**kwargs)
1366-
self._request_autoscale_view(tight=tight, scalex=_x, scaley=_y,
1367-
scalez=_z)
1368-
13691321
def tick_params(self, axis='both', **kwargs):
13701322
"""
13711323
Convenience method for changing the appearance of ticks and

0 commit comments

Comments
 (0)