Zoom In and Out of the Graph Using the Mouse Wheel in Matplotlib
Introduction
I have enabled zooming in and out of graphs displayed using Python’s matplotlib library by using the mouse wheel. Here are my notes. It would be convenient for tasks that require frequent zooming in and out of graphs.
What I Want to Implement
- Scroll the mouse wheel to zoom in and out on the x-axis.
- Hold down the Ctrl key and scroll the wheel to zoom in and out on the y-axis.
- The zooming center is at the cursor position.
Additionally, in a next article, the functionality to pan the display range has been implemented. Please take a look at this as well.
How to Handle Mouse and Keyboard Inputs
When performing custom mouse and keyboard operations on a graph, the operations triggered by the mouse or keyboard will be received as events. The mpl_connect()
function can be used.
mpl_connect()
The usage of mpl_connect()
is as follows:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
fig.canvas.mpl_connect([event-name], [callback-function])
The event name is specified as a string. The following events are defined:
Event | Desctiption |
---|---|
'button_press_event' | When a mouse button is clicked. |
'button_release_event' | When a mouse button is released. |
'draw_event' | When the graph is drawn. |
'key_press_event' | When the key is pressed. |
'key_release_event' | When the key is released. |
'motion_notify_event' | When the cursor moves within the graph. |
'pick_event' | When a data point is clicked. |
'resize_event' | When the size of the graph changes. |
'scroll_event' | When the mouse wheel is scrolled. |
'figure_enter_event' | When the cursor enters the graph. |
'figure_leave_event' | When the cursor leaves the graph. |
'axes_enter_event' | When the cursor enters a specific graph. |
'axes_leave_event' | When the cursor leaves a specific graph. |
'close_event' | When the graph is closed. |
Example
For example, when the mouse wheel is scrolled, specify 'scroll_event'
.
import matplotlib.pyplot as plt
def on_scroll(event):
if event.button == 'up':
print("wheel up")
elif event.button == 'down':
print("wheel down")
fig, ax = plt.subplots()
fig.canvas.mpl_connect('scroll_event', on_scroll)
The direction of the wheel rotation can be obtained with event.button
. Upward direction is 'up'
, and downward direction is 'down'
. In the example above, the direction of rotation is output to the console each time the wheel is scrolled.
Combining Ctrl
Key and Mouse Operations
When combining keyboard and wheel operations, it is necessary to also receive keyboard operation events. For this, 'key_press_event'
and 'key_release_event'
must also be used. To keep the state of the Ctrl
key being pressed, it needs to be shared using a global variable.
Example Code
import matplotlib.pyplot as plt
ctrl_flag = False
def on_key_press(event):
global ctrl_flag
if event.key == 'control':
ctrl_flag = True
def on_key_release(event):
global ctrl_flag
if event.key == 'control':
ctrl_flag = False
def on_scroll(event):
global ctrl_flag
if event.button == 'up':
if ctrl_flag:
print("wheel up(ctrl)")
else:
print("wheel up")
elif event.button == 'down':
if ctrl_flag:
print("wheel down(ctrl)")
else:
print("wheel down")
fig, ax = plt.subplots()
fig.canvas.mpl_connect('key_press_event', on_key_press)
fig.canvas.mpl_connect('key_release_event', on_key_release)
fig.canvas.mpl_connect('scroll_event', on_scroll)
The pressed key can be obtained with event.key
. When the Ctrl
key is pressed, set a flag in the global variable, and when it is released, clear the flag.
Implementation of Zooming In and Out Using the Mouse Wheel
Applying the above, let’s implement it. Note that when creating multiple graphs, using global variables can be inconvenient for zooming in and out on specific graphs, so we will implement this using a class.
import matplotlib.pyplot as plt
class MplZoomHelper:
def __init__(self, ax):
self.ax = ax
self.ctrl_flag = False
self.zoom_rate = 0.9
ax.figure.canvas.mpl_connect('key_press_event', self.on_key_press)
ax.figure.canvas.mpl_connect('key_release_event', self.on_key_release)
ax.figure.canvas.mpl_connect('scroll_event', self.on_scroll)
def on_key_press(self, event):
if event.inaxes is self.ax and event.key == 'control':
self.ctrl_flag = True
def on_key_release(self, event):
if event.inaxes is self.ax and event.key == 'control':
self.ctrl_flag = False
def on_scroll(self, event):
if event.inaxes is not self.ax:
return
if self.ctrl_flag:
self.on_scroll_y(event)
else:
self.on_scroll_x(event)
self.ax.figure.canvas.draw()
def on_scroll_x(self, event):
x_pos = event.xdata
min_value, max_value = self.ax.get_xlim()
if event.button == 'up':
new_min_value = x_pos - (x_pos - min_value) * self.zoom_rate
new_max_value = (max_value - x_pos) * self.zoom_rate + x_pos
elif event.button == 'down':
new_min_value = x_pos - (x_pos - min_value) / self.zoom_rate
new_max_value = (max_value - x_pos) / self.zoom_rate + x_pos
self.ax.set_xlim(new_min_value, new_max_value)
def on_scroll_y(self, event):
y_pos = event.ydata
min_value, max_value = self.ax.get_ylim()
if event.button == 'up':
new_min_value = y_pos - (y_pos - min_value) * self.zoom_rate
new_max_value = (max_value - y_pos) * self.zoom_rate + y_pos
elif event.button == 'down':
new_min_value = y_pos - (y_pos - min_value) / self.zoom_rate
new_max_value = (max_value - y_pos) / self.zoom_rate + y_pos
self.ax.set_ylim(new_min_value, new_max_value)
if __name__ == "__main__":
fig, axes = plt.subplots(2, 2)
axes[0, 0].plot([-1, 2, 3], [2, 4, 3])
axes[1, 1].plot([0, 5, 9], [-2, 1, 10])
mzh1 = MplZoomHelper(axes[0, 0])
mzh2 = MplZoomHelper(axes[1, 1])
plt.show()
Constructor
Using the constructor of the MplZoomHelper
object, register the graph where you want to use the zoom functionality. The 3 member variables, individual graph (self.ax
), the state of the Ctrl
key (self.ctrl_flag
), and the zoom ratio (self.zoom_rate
) are initialized in the constructor. Then, register the callback function.
Since the constructor’s argument is an individual graph (Axes
object), to register the callback function to receive events, obtain the Figure
object from ax.figure
.
on_key_press()
, on_key_release()
Get and record the state of the Ctrl
key. At this time, check event.inaxes
to inspect if the event occurred on the registered graph (self.ax
).
on_scroll()
Perform zooming in and out with the mouse wheel. Similar to on_key_press()
and on_key_release()
, check event.inaxes
to see if the event occurred on the registered graph (self.ax
). Only if the event occurred on the registered graph, perform zooming in and out.
The results of zooming in and out will not be reflected in the graph until it is redrawn. Therefore, execute self.ax.figure.canvas.draw()
for that purpose.
on_scroll_x()
, on_scroll_y()
The actual zooming takes place. Zooming is performed around the cursor position (event.xdata
, event.ydata
) with a ratio of self.zoom_rate
.
Summary
This is how to implement zooming in and out with the mouse wheel for graphs displayed in matplotlib:
- Use
mpl_connect()
to register a callback function to receive'scroll_event'
. - In the callback function, retrieve the direction of the wheel rotation.
- Depending on the direction of the wheel rotation, adjust the values at both ends of the graph.
- Redraw the graph to reflect the changes.
Discussion
New Comments
No comments yet. Be the first one!