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

Skip to content

Commit 74e7684

Browse files
authored
Merge pull request matplotlib#16831 from anntzer/zoom
Simplify interactive zoom handling.
2 parents eb0917b + c8d5bcd commit 74e7684

File tree

1 file changed

+44
-69
lines changed

1 file changed

+44
-69
lines changed

lib/matplotlib/backend_bases.py

Lines changed: 44 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -2722,7 +2722,7 @@ def __init__(self, canvas):
27222722
self._init_toolbar()
27232723
self._id_drag = self.canvas.mpl_connect(
27242724
'motion_notify_event', self.mouse_move)
2725-
self._id_zoom = None
2725+
self._zoom_info = None
27262726

27272727
self._button_pressed = None # determined by button pressed at start
27282728

@@ -2932,37 +2932,24 @@ def press_pan(self, event):
29322932

29332933
def press_zoom(self, event):
29342934
"""Callback for mouse button press in zoom to rect mode."""
2935-
# If we're already in the middle of a zoom, pressing another
2936-
# button works to "cancel"
2937-
if self._id_zoom is not None:
2938-
self.canvas.mpl_disconnect(self._id_zoom)
2939-
self.release(event)
2940-
self.draw()
2941-
self._xypress = None
2942-
self._button_pressed = None
2943-
self._id_zoom = None
2935+
if event.button not in [1, 3]:
29442936
return
2945-
2946-
if event.button in [1, 3]:
2947-
self._button_pressed = event.button
2948-
else:
2949-
self._button_pressed = None
2937+
if event.x is None or event.y is None:
2938+
return
2939+
axes = [a for a in self.canvas.figure.get_axes()
2940+
if a.in_axes(event) and a.get_navigate() and a.can_zoom()]
2941+
if not axes:
29502942
return
2951-
29522943
if self._nav_stack() is None:
2953-
# set the home button to this view
2954-
self.push_current()
2955-
2956-
x, y = event.x, event.y
2957-
self._xypress = []
2958-
for a in self.canvas.figure.get_axes():
2959-
if (x is not None and y is not None and a.in_axes(event) and
2960-
a.get_navigate() and a.can_zoom()):
2961-
self._xypress.append((x, y, a))
2962-
2963-
self._id_zoom = self.canvas.mpl_connect(
2964-
'motion_notify_event', self.drag_zoom)
2965-
2944+
self.push_current() # set the home button to this view
2945+
id_zoom = self.canvas.mpl_connect(
2946+
"motion_notify_event", self.drag_zoom)
2947+
self._zoom_info = {
2948+
"direction": "in" if event.button == 1 else "out",
2949+
"start_xy": (event.x, event.y),
2950+
"axes": axes,
2951+
"cid": id_zoom,
2952+
}
29662953
self.press(event)
29672954

29682955
def push_current(self):
@@ -3007,65 +2994,53 @@ def drag_pan(self, event):
30072994

30082995
def drag_zoom(self, event):
30092996
"""Callback for dragging in zoom mode."""
3010-
if self._xypress:
3011-
x, y = event.x, event.y
3012-
lastx, lasty, a = self._xypress[0]
3013-
(x1, y1), (x2, y2) = np.clip(
3014-
[[lastx, lasty], [x, y]], a.bbox.min, a.bbox.max)
3015-
if event.key == "x":
3016-
y1, y2 = a.bbox.intervaly
3017-
elif event.key == "y":
3018-
x1, x2 = a.bbox.intervalx
3019-
self.draw_rubberband(event, x1, y1, x2, y2)
2997+
start_xy = self._zoom_info["start_xy"]
2998+
ax = self._zoom_info["axes"][0]
2999+
(x1, y1), (x2, y2) = np.clip(
3000+
[start_xy, [event.x, event.y]], ax.bbox.min, ax.bbox.max)
3001+
if event.key == "x":
3002+
y1, y2 = ax.bbox.intervaly
3003+
elif event.key == "y":
3004+
x1, x2 = ax.bbox.intervalx
3005+
self.draw_rubberband(event, x1, y1, x2, y2)
30203006

30213007
def release_zoom(self, event):
30223008
"""Callback for mouse button release in zoom to rect mode."""
3023-
if self._id_zoom is not None:
3024-
self.canvas.mpl_disconnect(self._id_zoom)
3025-
self._id_zoom = None
3009+
if self._zoom_info is None:
3010+
return
30263011

3012+
# We don't check the event button here, so that zooms can be cancelled
3013+
# by (pressing and) releasing another mouse button.
3014+
self.canvas.mpl_disconnect(self._zoom_info["cid"])
30273015
self.remove_rubberband()
30283016

3029-
if not self._xypress:
3030-
return
3031-
3032-
last_a = []
3017+
start_x, start_y = self._zoom_info["start_xy"]
30333018

3034-
for lastx, lasty, a in self._xypress:
3019+
for i, ax in enumerate(self._zoom_info["axes"]):
30353020
x, y = event.x, event.y
30363021
# ignore singular clicks - 5 pixels is a threshold
30373022
# allows the user to "cancel" a zoom action
30383023
# by zooming by less than 5 pixels
3039-
if ((abs(x - lastx) < 5 and event.key != "y") or
3040-
(abs(y - lasty) < 5 and event.key != "x")):
3024+
if ((abs(x - start_x) < 5 and event.key != "y") or
3025+
(abs(y - start_y) < 5 and event.key != "x")):
30413026
self._xypress = None
30423027
self.release(event)
30433028
self.draw()
30443029
return
30453030

3046-
# detect twinx, twiny axes and avoid double zooming
3047-
twinx, twiny = False, False
3048-
if last_a:
3049-
for la in last_a:
3050-
if a.get_shared_x_axes().joined(a, la):
3051-
twinx = True
3052-
if a.get_shared_y_axes().joined(a, la):
3053-
twiny = True
3054-
last_a.append(a)
3055-
3056-
if self._button_pressed == 1:
3057-
direction = 'in'
3058-
elif self._button_pressed == 3:
3059-
direction = 'out'
3060-
else:
3061-
continue
3031+
# Detect whether this axes is twinned with an earlier axes in the
3032+
# list of zoomed axes, to avoid double zooming.
3033+
twinx = any(ax.get_shared_x_axes().joined(ax, prev)
3034+
for prev in self._zoom_info["axes"][:i])
3035+
twiny = any(ax.get_shared_y_axes().joined(ax, prev)
3036+
for prev in self._zoom_info["axes"][:i])
30623037

3063-
a._set_view_from_bbox((lastx, lasty, x, y), direction,
3064-
event.key, twinx, twiny)
3038+
ax._set_view_from_bbox(
3039+
(start_x, start_y, x, y), self._zoom_info["direction"],
3040+
event.key, twinx, twiny)
30653041

30663042
self.draw()
3067-
self._xypress = None
3068-
self._button_pressed = None
3043+
self._zoom_info = None
30693044

30703045
self.push_current()
30713046
self.release(event)

0 commit comments

Comments
 (0)