-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
zoom_factory does not preserve canvas position #7
Comments
Hi @antoniovazquezblanco thanks for reporting! one small note - i transferred this issue because I'm try to deprecate the zoom factory from mpl-interactions and move it over to a standalone package here. This is indeed an annoying behavior - happily there is an easy workaround. What seems to matter here is the ordering of plotting vs applying the zoom factory. Modifying your example to have the zoom factory after the plotting calls gives me the expected behavior: from matplotlib import pyplot
from mpl_interactions import zoom_factory
import numpy as np
fig = pyplot.gcf()
t = np.arange(0.0, 2.0, 0.01)
s = 1 + np.sin(2 * np.pi * t)
fig.gca().plot(t, s)
zoom_factory(fig.gca())
pyplot.show() this is a consequence of the auto centering behavior when you zoom far out. The "center" and extents chosen for that are locked in stone when the zoom_factory is created. mpl-pan-zoom/mpl_pan_zoom/_zoom.py Lines 37 to 41 in 9181c25
then we're hitting this code block: mpl-pan-zoom/mpl_pan_zoom/_zoom.py Lines 75 to 78 in 9181c25
I'm not sure there's an obvious to check for updating those, but if there is I'd be happy to accept a PR implementing more nuanced behavior. I'd also accept a PR adding a note to the docs about the above workaround |
Nice to know! I will be updating the graph regularly, I guess this means I have to disable the zoom and then reapply. I currently do not have the time to look into improving this behaviour. I may find some time in the near future :). Thanks. |
ahh - actually probably the simplest fix would be to make that autocentering behavior optional, perhaps even off by default. For your case you should instead just use this version of the function with teh autocentering chopped out: from matplotlib import pyplot
import numpy as np
def zoom_factory(ax, base_scale=1.1):
"""
Add ability to zoom with the scroll wheel.
Parameters
----------
ax : matplotlib axes object
axis on which to implement scroll to zoom
base_scale : float
how much zoom on each tick of scroll wheel
Returns
-------
disconnect_zoom : function
call this to disconnect the scroll listener
"""
def limits_to_range(lim):
return lim[1] - lim[0]
fig = ax.get_figure() # get the figure of interest
if hasattr(fig.canvas, "capture_scroll"):
fig.canvas.capture_scroll = True
has_toolbar = hasattr(fig.canvas, "toolbar") and fig.canvas.toolbar is not None
if has_toolbar:
# it might be possible to have an interactive backend without
# a toolbar. I'm not sure so being safe here
toolbar = fig.canvas.toolbar
toolbar.push_current()
def zoom_fun(event):
if event.inaxes is not ax:
return
# get the current x and y limits
cur_xlim = ax.get_xlim()
cur_ylim = ax.get_ylim()
# set the range
(cur_xlim[1] - cur_xlim[0]) * 0.5
(cur_ylim[1] - cur_ylim[0]) * 0.5
xdata = event.xdata # get event x location
ydata = event.ydata # get event y location
if event.button == "up":
# deal with zoom in
scale_factor = base_scale
elif event.button == "down":
# deal with zoom out
scale_factor = 1 / base_scale
else:
# deal with something that should never happen
scale_factor = 1
# set new limits
new_xlim = [
xdata - (xdata - cur_xlim[0]) / scale_factor,
xdata + (cur_xlim[1] - xdata) / scale_factor,
]
new_ylim = [
ydata - (ydata - cur_ylim[0]) / scale_factor,
ydata + (cur_ylim[1] - ydata) / scale_factor,
]
new_yrange = limits_to_range(new_ylim)
new_xrange = limits_to_range(new_xlim)
ax.set_xlim(new_xlim)
ax.set_ylim(new_ylim)
if has_toolbar:
toolbar.push_current()
ax.figure.canvas.draw_idle() # force re-draw
# attach the call back
cid = fig.canvas.mpl_connect("scroll_event", zoom_fun)
def disconnect_zoom():
fig.canvas.mpl_disconnect(cid)
# return the disconnect function
return disconnect_zoom
fig = pyplot.gcf()
zoom_factory(fig.gca())
t = np.arange(0.0, 2.0, 0.01)
s = 1 + np.sin(2 * np.pi * t)
fig.gca().plot(t, s)
pyplot.show() |
Bug report
When using zoom_factory, scrolling events do not preserve current canvas position...
Code for reproduction
Actual outcome
Whenever I pan my figure, if an scroll event takes place, I am automatically panned to the previous location...
Expected outcome
Whenever I pan my figure, if an scroll event takes place, only zoom should be affected and no panning should take place...
Version Info
The text was updated successfully, but these errors were encountered: