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

Skip to content

Commit c66942e

Browse files
committed
ENH: Scroll to zoom
Implements a minimal version of #20317, in particular https://github .com//pull/20317#issuecomment-2233156558: When any of the axes manipulation tools is active (pan or zoom tool), a mouse scroll results in a zoom towards the cursor, keeping aspect ratio. I've decided to require an active manipulation tool, so that without any active tool the plot cannot be changed (accidentally) - as before. For convenience, scroll-to-zoom is allowed with both the zoom and pan tools. Limiting further feels unnecessarily restrictive. Zooming is also limited to not having a modifier key pressed. This is because we might later want to add scroll+modifiers for other operations . It's better for now not to react to these at all to not introduce behaviors we later want to change.
1 parent a5e1f60 commit c66942e

File tree

2 files changed

+52
-0
lines changed

2 files changed

+52
-0
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Scroll-to-zoom in GUIs
2+
~~~~~~~~~~~~~~~~~~~~~~
3+
4+
When a plot manipulation tool (pan or zoom tool) in plot windows is selected,
5+
a mouse scroll operation results in a zoom towards the mouse pointer, keeping the
6+
aspect ratio of the axes.
7+
8+
There is no effect if no manipulation tool is selected. This is intentional to
9+
keep a state in which accidental manipulation of the plot is excluded.

lib/matplotlib/backend_bases.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2574,6 +2574,46 @@ def button_press_handler(event, canvas=None, toolbar=None):
25742574
toolbar.forward()
25752575

25762576

2577+
def scroll_handler(event, canvas=None, toolbar=None):
2578+
ax = event.inaxes
2579+
if ax is None:
2580+
return
2581+
2582+
if toolbar is None:
2583+
if canvas is None:
2584+
canvas = event.canvas
2585+
toolbar = canvas.toolbar
2586+
2587+
if toolbar is None or toolbar.mode == _Mode.NONE:
2588+
return
2589+
2590+
if event.key is None: # zoom
2591+
toolbar.push_current()
2592+
2593+
# Get the current x and y limits
2594+
xmin, xmax = ax.get_xlim()
2595+
ymin, ymax = ax.get_ylim()
2596+
2597+
# Get the data coordinates of the mouse
2598+
x = event.xdata
2599+
y = event.ydata
2600+
2601+
# Calculate the scale factor based on the step
2602+
scale_factor = 1.0 - 0.05 * event.step
2603+
2604+
# Calculate the new limits while keeping the mouse position fixed
2605+
new_xmin = x - (x - xmin) * scale_factor
2606+
new_xmax = x + (xmax - x) * scale_factor
2607+
new_ymin = y - (y - ymin) * scale_factor
2608+
new_ymax = y + (ymax - y) * scale_factor
2609+
2610+
# Set the new limits
2611+
ax.set_xlim(new_xmin, new_xmax)
2612+
ax.set_ylim(new_ymin, new_ymax)
2613+
2614+
ax.figure.canvas.draw_idle()
2615+
2616+
25772617
class NonGuiException(Exception):
25782618
"""Raised when trying show a figure in a non-GUI backend."""
25792619
pass
@@ -2653,11 +2693,14 @@ def __init__(self, canvas, num):
26532693

26542694
self.key_press_handler_id = None
26552695
self.button_press_handler_id = None
2696+
self.scroll_handler_id = None
26562697
if rcParams['toolbar'] != 'toolmanager':
26572698
self.key_press_handler_id = self.canvas.mpl_connect(
26582699
'key_press_event', key_press_handler)
26592700
self.button_press_handler_id = self.canvas.mpl_connect(
26602701
'button_press_event', button_press_handler)
2702+
self.scroll_handler_id = self.canvas.mpl_connect(
2703+
'scroll_event', scroll_handler)
26612704

26622705
self.toolmanager = (ToolManager(canvas.figure)
26632706
if mpl.rcParams['toolbar'] == 'toolmanager'

0 commit comments

Comments
 (0)