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

Skip to content

Commit 6737303

Browse files
committed
Restore autolimits status when pressing "home" key.
When pressing the "home" key, the autoscaling state should be restored as well, as interactive zoom/pan could have turned it off. test_toolbar_home_restores_autoscale shows an example of why. Assume one starts with `plot(range(11), range(11))`. In linear scale this autoscales to (0, 10) (assuming no margins or the old round limits mode); in log scale this autoscales to (1, 10) (dropping the zero). But previously, when "home" did not restore autoscale state, then a manual zoom followed by "home" (in linear scale) would set the limits to (0, 10) and turn off autoscale, after which switching to log scale interactively would give incorrect autolimits.
1 parent 4666bef commit 6737303

File tree

3 files changed

+52
-24
lines changed

3 files changed

+52
-24
lines changed

lib/matplotlib/axes/_base.py

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3985,35 +3985,30 @@ def _get_view(self):
39853985
"""
39863986
Save information required to reproduce the current view.
39873987
3988-
Called before a view is changed, such as during a pan or zoom
3989-
initiated by the user. You may return any information you deem
3990-
necessary to describe the view.
3988+
This method is called before a view is changed, such as during a pan or zoom
3989+
initiated by the user. It returns an opaque object that describes the current
3990+
view, in a format compatible with :meth:`_set_view`.
39913991
3992-
.. note::
3993-
3994-
Intended to be overridden by new projection types, but if not, the
3995-
default implementation saves the view limits. You *must* implement
3996-
:meth:`_set_view` if you implement this method.
3992+
The default implementation saves the view limits and autoscaling state.
3993+
Subclasses may override this as needed, as long as :meth:`_set_view` is also
3994+
adjusted accordingly.
39973995
"""
3998-
xmin, xmax = self.get_xlim()
3999-
ymin, ymax = self.get_ylim()
4000-
return xmin, xmax, ymin, ymax
3996+
return {
3997+
"xlim": self.get_xlim(), "autoscalex_on": self.get_autoscalex_on(),
3998+
"ylim": self.get_ylim(), "autoscaley_on": self.get_autoscaley_on(),
3999+
}
40014000

40024001
def _set_view(self, view):
40034002
"""
40044003
Apply a previously saved view.
40054004
4006-
Called when restoring a view, such as with the navigation buttons.
4005+
This method is called when restoring a view (with the return value of
4006+
:meth:`_get_view` as argument), such as with the navigation buttons.
40074007
4008-
.. note::
4009-
4010-
Intended to be overridden by new projection types, but if not, the
4011-
default implementation restores the view limits. You *must*
4012-
implement :meth:`_get_view` if you implement this method.
4008+
Subclasses that override :meth:`_get_view` also need to override this method
4009+
accordingly.
40134010
"""
4014-
xmin, xmax, ymin, ymax = view
4015-
self.set_xlim((xmin, xmax))
4016-
self.set_ylim((ymin, ymax))
4011+
self.set(**view)
40174012

40184013
def _prepare_view_from_bbox(self, bbox, direction='in',
40194014
mode=None, twinx=False, twiny=False):

lib/matplotlib/tests/test_backend_bases.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,36 @@ def test_toolbar_zoompan():
280280
assert ax.get_navigate_mode() == "PAN"
281281

282282

283+
def test_toolbar_home_restores_autoscale():
284+
fig, ax = plt.subplots()
285+
ax.plot(range(11), range(11))
286+
287+
tb = NavigationToolbar2(fig.canvas)
288+
tb.zoom()
289+
290+
# Switch to log.
291+
KeyEvent("key_press_event", fig.canvas, "k", 100, 100)._process()
292+
KeyEvent("key_press_event", fig.canvas, "l", 100, 100)._process()
293+
assert ax.get_xlim() == ax.get_ylim() == (1, 10) # Autolimits excluding 0.
294+
# Switch back to linear.
295+
KeyEvent("key_press_event", fig.canvas, "k", 100, 100)._process()
296+
KeyEvent("key_press_event", fig.canvas, "l", 100, 100)._process()
297+
assert ax.get_xlim() == ax.get_ylim() == (0, 10) # Autolimits.
298+
299+
# Zoom in from (x, y) = (2, 2) to (5, 5).
300+
start, stop = ax.transData.transform([(2, 2), (5, 5)])
301+
MouseEvent("button_press_event", fig.canvas, *start, MouseButton.LEFT)._process()
302+
MouseEvent("button_release_event", fig.canvas, *stop, MouseButton.LEFT)._process()
303+
# Go back to home.
304+
KeyEvent("key_press_event", fig.canvas, "h")._process()
305+
306+
assert ax.get_xlim() == ax.get_ylim() == (0, 10)
307+
# Switch to log.
308+
KeyEvent("key_press_event", fig.canvas, "k", 100, 100)._process()
309+
KeyEvent("key_press_event", fig.canvas, "l", 100, 100)._process()
310+
assert ax.get_xlim() == ax.get_ylim() == (1, 10) # Autolimits excluding 0.
311+
312+
283313
@pytest.mark.parametrize(
284314
"backend", ['svg', 'ps', 'pdf',
285315
pytest.param('pgf', marks=needs_pgf_xelatex)]

lib/mpl_toolkits/mplot3d/axes3d.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,13 +1000,16 @@ def _button_release(self, event):
10001000

10011001
def _get_view(self):
10021002
# docstring inherited
1003-
return (self.get_xlim(), self.get_ylim(), self.get_zlim(),
1004-
self.elev, self.azim, self.roll)
1003+
return {
1004+
"xlim": self.get_xlim(), "autoscalex_on": self.get_autoscalex_on(),
1005+
"ylim": self.get_ylim(), "autoscaley_on": self.get_autoscaley_on(),
1006+
"zlim": self.get_zlim(), "autoscalez_on": self.get_autoscalez_on(),
1007+
}, (self.elev, self.azim, self.roll)
10051008

10061009
def _set_view(self, view):
10071010
# docstring inherited
1008-
xlim, ylim, zlim, elev, azim, roll = view
1009-
self.set(xlim=xlim, ylim=ylim, zlim=zlim)
1011+
props, (elev, azim, roll) = view
1012+
self.set(**props)
10101013
self.elev = elev
10111014
self.azim = azim
10121015
self.roll = roll

0 commit comments

Comments
 (0)