import matplotlib.pyplot as plt | |
def zoom_factory(ax,base_scale = 2.): | |
def zoom_fun(event): | |
# get the current x and y limits | |
cur_xlim = ax.get_xlim() | |
cur_ylim = ax.get_ylim() | |
# set the range | |
cur_xrange = (cur_xlim[1] - cur_xlim[0])*.5 | |
cur_yrange = (cur_ylim[1] - cur_ylim[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 = 1/base_scale | |
elif event.button == 'down': | |
# deal with zoom out | |
scale_factor = base_scale | |
else: | |
# deal with something that should never happen | |
scale_factor = 1 | |
print event.button | |
# set new limits | |
ax.set_xlim([xdata - cur_xrange*scale_factor, | |
xdata + cur_xrange*scale_factor]) | |
ax.set_ylim([ydata - cur_yrange*scale_factor, | |
ydata + cur_yrange*scale_factor]) | |
ax.figure.canvas.draw() # force re-draw | |
fig = ax.get_figure() # get the figure of interest | |
# attach the call back | |
fig.canvas.mpl_connect('scroll_event',zoom_fun) | |
#return the function | |
return zoom_fun |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Show comment Hide comment
jdreaver
commented
Nov 19, 2012
Very nice! One modification I made for my PyQt4 GUI: instead of using ax as a parameter, I pass in the parent canvas and say ax = canvas.ax on the first line. Then, instead of plt.draw(), I use canvas.draw(). However, your version works better for subplot zooming. |
@jdreaver I didn't see your comment till recently. I am glad it was helpful! If you think your changes would be helpful for other people you should fork the gist. I also tweaked it a bit to not call |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Show comment Hide comment
giadang
Jan 17, 2015
IMHO, I think we don't have to calculate the cur_xrange
and cur_yrange
. Instead we can calculate the relative distance from the cursor position to the frame like this:
# Get distance from the cursor to the edge of the figure frame
x_left = xdata - cur_xlim[0]
x_right = cur_xlim[1] - xdata
y_top = ydata - cur_ylim[0]
y_bottom = cur_ylim[1] - ydata
then set the new xlim
, ylim
like this:
ax.set_xlim([xdata - x_left*scale_factor,
xdata + x_right*scale_factor])
ax.set_ylim([ydata - y_top*scale_factor,
ydata + y_bottom*scale_factor])
By this way, when zooming in and zooming out, the pixel which the cursor is pointing to won't be changed.
giadang
commented
Jan 17, 2015
IMHO, I think we don't have to calculate the # Get distance from the cursor to the edge of the figure frame
x_left = xdata - cur_xlim[0]
x_right = cur_xlim[1] - xdata
y_top = ydata - cur_ylim[0]
y_bottom = cur_ylim[1] - ydata then set the new ax.set_xlim([xdata - x_left*scale_factor,
xdata + x_right*scale_factor])
ax.set_ylim([ydata - y_top*scale_factor,
ydata + y_bottom*scale_factor]) By this way, when zooming in and zooming out, the pixel which the cursor is pointing to won't be changed. |
@giadang good point! That fixes one of the more annoying behaviors of this. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Show comment Hide comment
PeterPablo
Jul 12, 2016
Thank you for this gist. Zooming in and out with the mousewheel (without moving the mouse pointer) does not restore the original view. It seems that the underlying view is paned.
PeterPablo
commented
Jul 12, 2016
Thank you for this gist. Zooming in and out with the mousewheel (without moving the mouse pointer) does not restore the original view. It seems that the underlying view is paned. |
Very nice!
One modification I made for my PyQt4 GUI: instead of using ax as a parameter, I pass in the parent canvas and say ax = canvas.ax on the first line. Then, instead of plt.draw(), I use canvas.draw(). However, your version works better for subplot zooming.