From b63a782ce2653ea0368dfc8c55e825032ac2920b Mon Sep 17 00:00:00 2001 From: LangQi99 <2032771946@qq.com> Date: Wed, 10 Sep 2025 21:21:15 +0800 Subject: [PATCH 1/3] feat: support x/y-axis zoom --- doc/release/next_whats_new/scroll_to_zoom.rst | 3 ++- lib/matplotlib/backend_bases.py | 21 ++++++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/doc/release/next_whats_new/scroll_to_zoom.rst b/doc/release/next_whats_new/scroll_to_zoom.rst index bafa312c32a5..1be522b7a255 100644 --- a/doc/release/next_whats_new/scroll_to_zoom.rst +++ b/doc/release/next_whats_new/scroll_to_zoom.rst @@ -2,7 +2,8 @@ Zooming using mouse wheel ~~~~~~~~~~~~~~~~~~~~~~~~~ ``Ctrl+MouseWheel`` can be used to zoom in the plot windows. +Additionally, ``x+MouseWheel`` zooms only the x-axis and ``y+MouseWheel`` zooms only the y-axis. -The zoom focusses on the mouse pointer, and keeps the aspect ratio of the axes. +The zoom focusses on the mouse pointer. With ``Ctrl``, the axes aspect ratio is kept; with ``x`` or ``y``, only the respective axis is scaled. Zooming is currently only supported on rectilinear Axes. diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index 7560db80d2c1..994e41f9fdba 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -2592,7 +2592,7 @@ def scroll_handler(event, canvas=None, toolbar=None): # is required for interactive navigation. return - if event.key == "control": # zoom towards the mouse position + if event.key in {"control", "x", "X", "y", "Y"}: # zoom towards the mouse position toolbar.push_current() xmin, xmax = ax.get_xlim() @@ -2604,10 +2604,21 @@ def scroll_handler(event, canvas=None, toolbar=None): x, y = ax.transScale.transform((event.xdata, event.ydata)) scale_factor = 0.85 ** event.step - new_xmin = x - (x - xmin) * scale_factor - new_xmax = x + (xmax - x) * scale_factor - new_ymin = y - (y - ymin) * scale_factor - new_ymax = y + (ymax - y) * scale_factor + # Determine which axes to scale based on key + zoom_x = event.key in {"control", "x", "X"} + zoom_y = event.key in {"control", "y", "Y"} + + if zoom_x: + new_xmin = x - (x - xmin) * scale_factor + new_xmax = x + (xmax - x) * scale_factor + else: + new_xmin, new_xmax = xmin, xmax + + if zoom_y: + new_ymin = y - (y - ymin) * scale_factor + new_ymax = y + (ymax - y) * scale_factor + else: + new_ymin, new_ymax = ymin, ymax inv_scale = ax.transScale.inverted() (new_xmin, new_ymin), (new_xmax, new_ymax) = inv_scale.transform( From f8583e08627a98464b21769df681da751dc09055 Mon Sep 17 00:00:00 2001 From: LangQi99 <2032771946@qq.com> Date: Fri, 12 Sep 2025 11:21:12 +0800 Subject: [PATCH 2/3] Update lib/matplotlib/backend_bases.py "X" would be generated by "Shift+x" Co-authored-by: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> --- lib/matplotlib/backend_bases.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index 994e41f9fdba..7a58717db5a4 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -2592,7 +2592,7 @@ def scroll_handler(event, canvas=None, toolbar=None): # is required for interactive navigation. return - if event.key in {"control", "x", "X", "y", "Y"}: # zoom towards the mouse position + if event.key in {"control", "x", "y"}: # zoom towards the mouse position toolbar.push_current() xmin, xmax = ax.get_xlim() From 0a744f0ba180dca0a73bf351db89796a9854c7d6 Mon Sep 17 00:00:00 2001 From: LangQi99 <2032771946@qq.com> Date: Fri, 12 Sep 2025 11:21:26 +0800 Subject: [PATCH 3/3] Update lib/matplotlib/backend_bases.py "X" would be generated by "Shift+x" Co-authored-by: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> --- lib/matplotlib/backend_bases.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index 7a58717db5a4..07a48a768de0 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -2605,8 +2605,8 @@ def scroll_handler(event, canvas=None, toolbar=None): scale_factor = 0.85 ** event.step # Determine which axes to scale based on key - zoom_x = event.key in {"control", "x", "X"} - zoom_y = event.key in {"control", "y", "Y"} + zoom_x = event.key in {"control", "x"} + zoom_y = event.key in {"control", "y"} if zoom_x: new_xmin = x - (x - xmin) * scale_factor