8000 Jointly track x and y in PolygonSelector. · matplotlib/matplotlib@6c146b9 · GitHub
[go: up one dir, main page]

Skip to content

Commit 6c146b9

Browse files
committed
Jointly track x and y in PolygonSelector.
It's easier to track them in a single list. Also init _selection_artist and _polygon_handles with empty arrays, as there's no reason to pretend that they start with 0, 0. On the other hand, _xys does need to start as a non-empty array as the last point gets updated as being the cursor position.
1 parent 21b76ae commit 6c146b9

File tree

1 file changed

+35
-52
lines changed

1 file changed

+35
-52
lines changed

lib/matplotlib/widgets.py

Lines changed: 35 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -3586,21 +3586,20 @@ def __init__(self, ax, onselect, useblit=False,
35863586
super().__init__(ax, onselect, useblit=useblit,
35873587
state_modifier_keys=state_modifier_keys)
35883588

3589-
self._xs, self._ys = [0], [0]
3589+
self._xys = [(0, 0)]
35903590

35913591
if props is None:
35923592
props = dict(color='k', linestyle='-', linewidth=2, alpha=0.5)
35933593
props['animated'] = self.useblit
35943594
self._props = props
3595-
line = Line2D(self._xs, self._ys, **self._props)
3595+
self._selection_artist = line = Line2D([], [], **self._props)
35963596
self.ax.add_line(line)
3597-
self._selection_artist = line
35983597

35993598
if handle_props is None:
36003599
handle_props = dict(markeredgecolor='k',
36013600
markerfacecolor=self._props.get('color', 'k'))
36023601
self._handle_props = handle_props
3603-
self._polygon_handles = ToolHandles(self.ax, self._xs, self._ys,
3602+
self._polygon_handles = ToolHandles(self.ax, [], [],
36043603
useblit=self.useblit,
36053604
marker_props=self._handle_props)
36063605

@@ -3619,33 +3618,25 @@ def __init__(self, ax, onselect, useblit=False,
36193618
lambda self, value: setattr(self, "grab_range", value))
36203619
)
36213620

3622-
@property
3623-
def _nverts(self):
3624-
return len(self._xs)
3625-
36263621
@property
36273622
def _handles_artists(self):
36283623
return self._polygon_handles.artists
36293624

36303625
def _remove_vertex(self, i):
36313626
"""Remove vertex with index i."""
3632-
if (self._nverts > 2 and
3627+
if (len(self._xys) > 2 and
36333628
self._selection_completed and
3634-
i in (0, self._nverts - 1)):
3629+
i in (0, len(self._xys) - 1)):
36353630
# If selecting the first or final vertex, remove both first and
36363631
# last vertex as they are the same for a closed polygon
3637-
self._xs.pop(0)
3638-
self._ys.pop(0)
3639-
self._xs.pop(-1)
3640-
self._ys.pop(-1)
3632+
self._xys.pop(0)
3633+
self._xys.pop(-1)
36413634
# Close the polygon again by appending the new first vertex to the
36423635
# end
3643-
self._xs.append(self._xs[0])
3644-
self._ys.append(self._ys[0])
3636+
self._xys.append(self._xys[0])
36453637
else:
3646-
self._xs.pop(i)
3647-
self._ys.pop(i)
3648-
if self._nverts <= 2:
3638+
self._xys.pop(i)
3639+
if len(self._xys) <= 2:
36493640
# If only one point left, return to incomplete state to let user
36503641
# start drawing again
36513642
self._selection_completed = False
@@ -3654,13 +3645,13 @@ def _press(self, event):
36543645
"""Button press event handler."""
36553646
# Check for selection of a tool handle.
36563647
if ((self._selection_completed or 'move_vertex' in self._state)
3657-
and len(self._xs) > 0):
3648+
and len(self._xys) > 0):
36583649
h_idx, h_dist = self._polygon_handles.closest(event.x, event.y)
36593650
if h_dist < self.grab_range:
36603651
self._active_handle_idx = h_idx
36613652
# Save the vertex positions at the time of the press event (needed to
36623653
# support the 'move_all' state modifier).
3663-
self._xs_at_press, self._ys_at_press = self._xs.copy(), self._ys.copy()
3654+
self._xys_at_press = self._xys.copy()
36643655

36653656
def _release(self, event):
36663657
"""Button release event handler."""
@@ -3672,17 +3663,14 @@ def _release(self, event):
36723663
self._active_handle_idx = -1
36733664

36743665
# Complete the polygon.
3675-
elif (len(self._xs) > 3
3676-
and self._xs[-1] == self._xs[0]
3677-
and self._ys[-1] == self._ys[0]):
3666+
elif len(self._xys) > 3 and self._xys[-1] == self._xys[0]:
36783667
self._selection_completed = True
36793668

36803669
# Place new vertex.
36813670
elif (not self._selection_completed
36823671
and 'move_all' not in self._state
36833672
and 'move_vertex' not in self._state):
3684-
self._xs.insert(-1, event.xdata)
3685-
self._ys.insert(-1, event.ydata)
3673+
self._xys.insert(-1, (event.xdata, event.ydata))
36863674

36873675
if self._selection_completed:
36883676
self.onselect(self.verts)
@@ -3704,19 +3692,19 @@ def _onmove(self, event):
37043692
# Move the active vertex (ToolHandle).
37053693
if self._active_handle_idx >= 0:
37063694
idx = self._active_handle_idx
3707-
self._xs[idx], self._ys[idx] = event.xdata, event.ydata
3695+
self._xys[idx] = event.xdata, event.ydata
37083696
# Also update the end of the polygon line if the first vertex is
37093697
# the active handle and the polygon is completed.
37103698
if idx == 0 and self._selection_completed:
3711-
self._xs[-1], self._ys[-1] = event.xdata, event.ydata
3699+
self._xys[-1] = event.xdata, event.ydata
37123700

37133701
# Move all vertices.
37143702
elif 'move_all' in self._state and self._eventpress:
F438 37153703
dx = event.xdata - self._eventpress.xdata
37163704
dy = event.ydata - self._eventpress.ydata
3717-
for k in range(len(self._xs)):
3718-
self._xs[k] = self._xs_at_press[k] + dx
3719-
self._ys[k] = self._ys_at_press[k] + dy
3705+
for k in range(len(self._xys)):
3706+
x_at_press, y_at_press = self._xys_at_press[k]
3707+
self._xys[k] = x_at_press + dx, y_at_press + dy
37203708

37213709
# Do nothing if completed or waiting for a move.
37223710
elif (self._selection_completed
@@ -3726,15 +3714,14 @@ def _onmove(self, event):
37263714
# Position pending vertex.
37273715
else:
37283716
# Calculate distance to the start vertex.
3729-
x0, y0 = self._selection_artist.get_transform().transform(
3730-
(self._xs[0], self._ys[0])
3731-
)
3717+
x0, y0 = \
3718+
self._selection_artist.get_transform().transform(self._xys[0])
37323719
v0_dist = np.hypot(x0 - event.x, y0 - event.y)
37333720
# Lock on to the start vertex if near it and ready to complete.
3734-
if len(self._xs) > 3 and v0_dist < self.grab_range:
3735-
self._xs[-1], self._ys[-1] = self._xs[0], self._ys[0]
3721+
if len(self._xys) > 3 and v0_dist < self.grab_range:
3722+
self._xys[-1] = self._xys[0]
37363723
else:
3737-
self._xs[-1], self._ys[-1] = event.xdata, event.ydata
3724+
self._xys[-1] = event.xdata, event.ydata
37383725

37393726
self._draw_polygon()
37403727

@@ -3745,7 +3732,7 @@ def _on_key_press(self, event):
37453732
if (not self._selection_completed
37463733
and ('move_vertex' in self._state or
37473734
'move_all' in self._state)):
3748-
self._xs, self._ys = self._xs[:-1], self._ys[:-1]
3735+
self._xys.pop()
37493736
self._draw_polygon()
37503737

37513738
def _on_key_release(self, event):
@@ -3756,35 +3743,34 @@ def _on_key_release(self, event):
37563743
and
37573744
(event.key == self._state_modifier_keys.get('move_vertex')
37583745
or event.key == self._state_modifier_keys.get('move_all'))):
3759-
self._xs.append(event.xdata)
3760-
self._ys.append(event.ydata)
3746+
self._xys.append((event.xdata, event.ydata))
37613747
self._draw_polygon()
37623748
# Reset the polygon if the released key is the 'clear' key.
37633749
elif event.key == self._state_modifier_keys.get('clear'):
37643750
event = self._clean_event(event)
3765-
self._xs, self._ys = [event.xdata], [event.ydata]
3751+
self._xys = [(event.xdata, event.ydata)]
37663752
self._selection_completed = False
37673753
self.set_visible(True)
37683754

37693755
def _draw_polygon(self):
37703756
"""Redraw the polygon based on the new vertex positions."""
3771-
self._selection_artist.set_data(self._xs, self._ys)
3757+
xs, ys = zip(*self._xys) if self._xys else ([], [])
3758+
self._selection_artist.set_data(xs, ys)
37723759
# Only show one tool handle at the start and end vertex of the polygon
37733760
# if the polygon is completed or the user is locked on to the start
37743761
# vertex.
37753762
if (self._selection_completed
3776-
or (len(self._xs) > 3
3777-
and self._xs[-1] == self._xs[0]
3778-
and self._ys[-1] == self._ys[0])):
3779-
self._polygon_handles.set_data(self._xs[:-1], self._ys[:-1])
3763+
or (len(self._xys) > 3
3764+
and self._xys[-1] == self._xys[0])):
3765+
self._polygon_handles.set_data(xs[:-1], ys[:-1])
37803766
else:
3781-
self._polygon_handles.set_data(self._xs, self._ys)
3767+
self._polygon_handles.set_data(xs, ys)
37823768
self.update()
37833769

37843770
@property
37853771
def verts(self):
37863772
"""The polygon vertices, as a list of ``(x, y)`` pairs."""
3787-
return list(zip(self._xs[:-1], self._ys[:-1]))
3773+
return self._xys[:-1]
37883774

37893775
@verts.setter
37903776
def verts(self, xys):
@@ -3794,10 +3780,7 @@ def verts(self, xys):
37943780
This will remove any pre-existing vertices, creating a complete polygon
37953781
with the new vertices.
37963782
"""
3797-
self._xs = [xy[0] for xy in xys]
3798-
self._xs.append(self._xs[0])
3799-
self._ys = [xy[1] for xy in xys]
3800-
self._ys.append(self._ys[0])
3783+
self._xys = [*xys, xys[0]]
38013784
self._selection_completed = True
38023785
self.set_visible(True)
38033786
self._draw_polygon()

0 commit comments

Comments
 (0)
0