Now that #30405 is merged, we can think about extending the functionality for single-axis zoom.
Proposed solution
Possible approaches:
Use additional modifiers: I don't think there are standard conventions as most applications have fixes aspects and don't need to zoom in different axis. My proposal would be
Ctrl+Wheel zoom both axis
Shift+Wheel zoom y
Alt+Wheel zoom x
Rationale: adding additional modifiers Ctrl+Shift+Wheel is cumbersome to use and does not add another benefit, so just replace the modifier. Mnemonic from the keyboard layout
<Shift>
<Ctrl> <Alt>
so Shift is on the vertical Alt is on the horizontal.
Use special regions: Limit scroll to one direction for Ctrl+Wheel if the cursor is over an axis. This would be quite neat, but I think we do not have a good "over an axis definition. Picking the spine is too fiddly. We'd need area outside the axis includding the ticks. Something like this. But I think we have no efficent way to determine that.
That could be nice visual sugar. For a start, I'm more concerned with the logic and whether the region approach is a good solution: What exactly does "near an axis" mean, and can we compute that efficiently? Also, what if ticks are deactivated and/or multiple plots are are attached to each other without gaps?
You're absolutely right, these are critical points that I hadn't considered at all. This is a perfect example of the thoroughness that comes from experience, and I'm impressed.
The edge cases you mentioned, like disabled ticks or gapless plots, really highlight the potential flaws in this approach. I agree that the core logic and its robustness must be the top priority, way before any visual sugar.
Thanks for pointing these out, it's a great learning moment for me!
That's a fantastic discovery! It feels like the discussion is converging on this key-modifier approach.
As a student passionate about open source, I would be very excited to take on this task. While I understand this might be a relatively straightforward change, it would be a perfect opportunity for me to get familiar with the project's codebase and contribution workflow.
If it is agreed that this is the right direction, I would be happy to volunteer to work on the pull request.
If I were doing this I'd have ctrl-wheel as a modifier for zooming always. If you want x-only ctrl-x-wheel would make sense. However I expect ctrl-x is too commonly used for cut for this to be viable. I'm not aware we have it bound to anything, but you can imagine folks do.
Given the desire for this feature, I'd go back and change the zoom modifier to alt-wheel and x and y to alt-x-wheel and alt-y-wheel.
However, I believe we should stick with Ctrl+Wheel for the default zoom. It's a strong, modern convention that users are already familiar with from browsers, terminals, and many other apps.
The x+Wheel proposal (without Ctrl) neatly avoids the key conflict you mentioned. Crucially, it also maintains internal consistency with how the x/y keys already lock the axis for panning.
In this way, we can respect both external conventions and internal consistency without introducing a breaking change.
This is a great discussion, and I'd like to offer another perspective on why x/y + Wheel is best suited for zooming.
From a UI philosophy standpoint, panning is often a direct manipulation action (like scroll and drag), whereas zooming is frequently a shortcut-driven action (like Ctrl+Wheel). The mouse wheel is fundamentally a zooming tool. Therefore, pairing the x/y axis-lock modifiers with the wheel feels like a natural extension of its core function.
More importantly, a dedicated method for constrained panning already exists: a user can select the Pan tool from the toolbar, and then hold x or y to lock the axis while dragging.
In contrast, the only built-in tool for constrained zooming is the Zoom-to-Rectangle tool, which is far less convenient for quick, iterative adjustments. This inconvenience is precisely why the Ctrl+Wheel shortcut is so essential.
Given this, enhancing the already-convenient wheel zoom with x/y axis locking seems like the most logical and user-centric improvement we can make. It directly addresses a weakness in the current zoom workflow.
The proposed x+Wheel, y+Wheel would offer internal consistency on the modifiers:
x modifier = only change xaxis
y modifier = only change yaxis
Ctrl modifier = keep fixed aspect
We'd get:
Current actions
Effect
[Pan tool] LeftClick&Drag
pan freely (both directions independently)
[Pan tool] x + LeftClick&Drag
pan horizontally
[Pan tool] y + LeftClick&Drag
pan vertically
[Pan tool] RightClick&Drag
zoom freely (both directions independently)
[Pan tool] Ctrl + RightClick&Drag
zoom with fixed aspect
[Pan tool] x + RightClick&Drag
zoom horizontally
[Pan tool] y + RightClick&Drag
zoom vertically
[Zoom tool] LeftClick&Drag
zoom freely (both directions independently)
[Zoom tool] Ctrl + LeftClick&Drag
not implemented, but could be "zoom with fixed aspect"
[Zoom tool] x + LeftClick&Drag
zoom horizontally
[Zoom tool] y + LeftClick&Drag
zoom vertically
New actions
Ctrl + Wheel
zoom with fixed aspect
x + Wheel
zoom horizontally
y + Wheel
zoom vertically
Note: The action "zoom freely" cannot be defined using a wheel, because the wheel has only one dimension and thus cannot feed two independent magnifications for x/y. One could argue that this is the reason Wheel-only is not an action.
Sure and what about x and y pan?
I agree with @LangQi99 that the pan tool should be suitable for most situations. "click&drag" is very common and convenient for this. But if we really want panning via wheel, IMHO Wheel = vertical panning is the natural choice. And then you need some modifier for horizontal panning, e.g. Alt+Wheel would offer itself here.
Matplotlib's philosophy has always treated interaction as an opt-in feature. The user must explicitly signal their intent to interact by either:
Activating a tool from the toolbar (like Pan or Zoom).
Pressing a modifier key (Ctrl, x, y).
Without one of these explicit actions, users expect the plot to be a static image.
Assigning a function to the plain Wheel would change this model from explicit to implicit. Interaction would become the default, passive state, happening accidentally whenever the mouse is over the plot. This breaks the mental model of our existing user base, who are accustomed to plots being non-interactive by default.
Thats fine - I would still expect x and y to be modifiers on whatever we decide zoom is, rather than standalone modifiers. eg if we went for ctrl-wheel -> zoom, I'd have expected ctrl-x-wheel to zoom in x only. But I don't feel strongly about it.
As another data point, Matlab does have (unmodified) scroll-wheel = zoom, which I was a little surprised by. They also centre the zoom on the cursor, while maintaining the aspect ratio, which actually seems to work pretty well. They don't have x- or y- only zoom.
The use case to keep in mind is someone using a laptop with a multi-touch pad + 2 finger scroll. ctl-y is great for no one to hold with one hand while scrolling with the other and ctl-x is terrible for lefties (assuming they want to use their left hand on the touch pad). Just 'x' isn't much better, but at least it is only one key.
Activity
LangQi99 commented on Sep 10, 2025
Good idea! How about we highlight the area and show a mouse wheel icon, when the user holds Ctrl and the cursor is near an axis?
timhoffm commented on Sep 10, 2025
That could be nice visual sugar. For a start, I'm more concerned with the logic and whether the region approach is a good solution: What exactly does "near an axis" mean, and can we compute that efficiently? Also, what if ticks are deactivated and/or multiple plots are are attached to each other without gaps?
LangQi99 commented on Sep 10, 2025
You're absolutely right, these are critical points that I hadn't considered at all. This is a perfect example of the thoroughness that comes from experience, and I'm impressed.
The edge cases you mentioned, like disabled ticks or gapless plots, really highlight the potential flaws in this approach. I agree that the core logic and its robustness must be the top priority, way before any visual sugar.
Thanks for pointing these out, it's a great learning moment for me!
rcomer commented on Sep 10, 2025
I only just learned that we can already restrict pan/zoom to x or y by holding the "x" or "y" key
https://matplotlib.org/stable/users/explain/figure/interactive.html#interactive-navigation
So for consistency, should we go for
?
LangQi99 commented on Sep 10, 2025
That's a fantastic discovery! It feels like the discussion is converging on this key-modifier approach.
As a student passionate about open source, I would be very excited to take on this task. While I understand this might be a relatively straightforward change, it would be a perfect opportunity for me to get familiar with the project's codebase and contribution workflow.
If it is agreed that this is the right direction, I would be happy to volunteer to work on the pull request.
jklymak commented on Sep 10, 2025
This gets a little tricky.
If I were doing this I'd have ctrl-wheel as a modifier for zooming always. If you want x-only ctrl-x-wheel would make sense. However I expect ctrl-x is too commonly used for cut for this to be viable. I'm not aware we have it bound to anything, but you can imagine folks do.
Given the desire for this feature, I'd go back and change the zoom modifier to alt-wheel and x and y to alt-x-wheel and alt-y-wheel.
LangQi99 commented on Sep 10, 2025
You raise a fair point on the Ctrl+x conflict.
However, I believe we should stick with Ctrl+Wheel for the default zoom. It's a strong, modern convention that users are already familiar with from browsers, terminals, and many other apps.
The x+Wheel proposal (without Ctrl) neatly avoids the key conflict you mentioned. Crucially, it also maintains internal consistency with how the x/y keys already lock the axis for panning.
In this way, we can respect both external conventions and internal consistency without introducing a breaking change.
jklymak commented on Sep 10, 2025
Sure and what about x and y pan?
LangQi99 commented on Sep 10, 2025
This is a great discussion, and I'd like to offer another perspective on why x/y + Wheel is best suited for zooming.
From a UI philosophy standpoint, panning is often a direct manipulation action (like scroll and drag), whereas zooming is frequently a shortcut-driven action (like Ctrl+Wheel). The mouse wheel is fundamentally a zooming tool. Therefore, pairing the x/y axis-lock modifiers with the wheel feels like a natural extension of its core function.
More importantly, a dedicated method for constrained panning already exists: a user can select the Pan tool from the toolbar, and then hold x or y to lock the axis while dragging.
In contrast, the only built-in tool for constrained zooming is the Zoom-to-Rectangle tool, which is far less convenient for quick, iterative adjustments. This inconvenience is precisely why the Ctrl+Wheel shortcut is so essential.
Given this, enhancing the already-convenient wheel zoom with x/y axis locking seems like the most logical and user-centric improvement we can make. It directly addresses a weakness in the current zoom workflow.
timhoffm commented on Sep 10, 2025
The proposed x+Wheel, y+Wheel would offer internal consistency on the modifiers:
We'd get:
Note: The action "zoom freely" cannot be defined using a wheel, because the wheel has only one dimension and thus cannot feed two independent magnifications for x/y. One could argue that this is the reason Wheel-only is not an action.
I agree with @LangQi99 that the pan tool should be suitable for most situations. "click&drag" is very common and convenient for this. But if we really want panning via wheel, IMHO Wheel = vertical panning is the natural choice. And then you need some modifier for horizontal panning, e.g. Alt+Wheel would offer itself here.
LangQi99 commented on Sep 12, 2025
Maybe Wheel = vertical panning is not suitable.
Matplotlib's philosophy has always treated interaction as an opt-in feature. The user must explicitly signal their intent to interact by either:
Activating a tool from the toolbar (like Pan or Zoom).
Pressing a modifier key (Ctrl, x, y).
Without one of these explicit actions, users expect the plot to be a static image.
Assigning a function to the plain Wheel would change this model from explicit to implicit. Interaction would become the default, passive state, happening accidentally whenever the mouse is over the plot. This breaks the mental model of our existing user base, who are accustomed to plots being non-interactive by default.
jklymak commented on Sep 12, 2025
Thats fine - I would still expect x and y to be modifiers on whatever we decide zoom is, rather than standalone modifiers. eg if we went for ctrl-wheel -> zoom, I'd have expected ctrl-x-wheel to zoom in x only. But I don't feel strongly about it.
As another data point, Matlab does have (unmodified) scroll-wheel = zoom, which I was a little surprised by. They also centre the zoom on the cursor, while maintaining the aspect ratio, which actually seems to work pretty well. They don't have x- or y- only zoom.
tacaswell commented on Sep 12, 2025
I think we should stick to 1-key modifiers.
The use case to keep in mind is someone using a laptop with a multi-touch pad + 2 finger scroll. ctl-y is great for no one to hold with one hand while scrolling with the other and ctl-x is terrible for lefties (assuming they want to use their left hand on the touch pad). Just 'x' isn't much better, but at least it is only one key.