Last active

Embed URL

HTTPS clone URL

SSH clone URL

You can clone with HTTPS or SSH.

Download Gist

factory for adding zoom callback to matplotlib graphs

View simp_zoom.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
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

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.

Owner

@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 plt.draw().

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.

Owner

@giadang good point! That fixes one of the more annoying behaviors of this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.