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

Skip to content

Commit 635562e

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 b3f61d1 commit 635562e

File tree

1 file changed

+37
-55
lines changed

1 file changed

+37
-55
lines changed

lib/matplotlib/widgets.py

Lines changed: 37 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -3643,21 +3643,20 @@ def __init__(self, ax, onselect, useblit=False,
36433643
super().__init__(ax, onselect, useblit=useblit,
36443644
state_modifier_keys=state_modifier_keys)
36453645

3646-
self._xs, self._ys = [0], [0]
3646+
self._xys = [(0, 0)]
36473647

36483648
if props is None:
36493649
props = dict(color='k', linestyle='-', linewidth=2, alpha=0.5)
36503650
props['animated'] = self.useblit
36513651
self._props = props
3652-
line = Line2D(self._xs, self._ys, **self._props)
3652+
self._selection_artist = line = Line2D([], [], **self._props)
36533653
self.ax.add_line(line)
3654-
self._selection_artist = line
36553654

36563655
if handle_props is None:
36573656
handle_props = dict(markeredgecolor='k',
36583657
markerfacecolor=self._props.get('color', 'k'))
36593658
self._handle_props = handle_props
3660-
self._polygon_handles = ToolHandles(self.ax, self._xs, self._ys,
3659+
self._polygon_handles = ToolHandles(self.ax, [], [],
36613660
useblit=self.useblit,
36623661
marker_props=self._handle_props)
36633662

@@ -3729,9 +3728,8 @@ def _scale_polygon(self, event):
37293728
.translate(x1, y1))
37303729

37313730
# Update polygon verts
3732-
new_verts = t.transform(np.array(self.verts))
3733-
self._xs = list(np.append(new_verts[:, 0], new_verts[0, 0]))
3734-
self._ys = list(np.append(new_verts[:, 1], new_verts[0, 1]))
3731+
new_verts = t.transform(np.array(self.verts)).tolist()
3732+
self._xys = [*new_verts, new_verts[0]]
37353733
self._draw_polygon()
37363734
self._old_box_extents = self._box.extents
37373735

@@ -3745,33 +3743,25 @@ def _scale_polygon(self, event):
37453743
lambda self, value: setattr(self, "grab_range", value))
37463744
)
37473745

3748-
@property
3749-
def _nverts(self):
3750-
return len(self._xs)
3751-
37523746
@property
37533747
def _handles_artists(self):
37543748
return self._polygon_handles.artists
37553749

37563750
def _remove_vertex(self, i):
37573751
"""Remove vertex with index i."""
3758-
if (self._nverts > 2 and
3752+
if (len(self._xys) > 2 and
37593753
self._selection_completed and
3760-
i in (0, self._nverts - 1)):
3754+
i in (0, len(self._xys) - 1)):
37613755
# If selecting the first or final vertex, remove both first and
37623756
# last vertex as they are the same for a closed polygon
3763-
self._xs.pop(0)
3764-
self._ys.pop(0)
3765-
self._xs.pop(-1)
3766-
self._ys.pop(-1)
3757+
self._xys.pop(0)
3758+
self._xys.pop(-1)
37673759
# Close the polygon again by appending the new first vertex to the
37683760
# end
3769-
self._xs.append(self._xs[0])
3770-
self._ys.append(self._ys[0])
3761+
self._xys.append(self._xys[0])
37713762
else:
3772-
self._xs.pop(i)
3773-
self._ys.pop(i)
3774-
if self._nverts <= 2:
3763+
self._xys.pop(i)
3764+
if len(self._xys) <= 2:
37753765
# If only one point left, return to incomplete state to let user
37763766
# start drawing again
37773767
self._selection_completed = False
@@ -3781,13 +3771,13 @@ def _press(self, event):
37813771
"""Button press event handler."""
37823772
# Check for selection of a tool handle.
37833773
if ((self._selection_completed or 'move_vertex' in self._state)
3784-
and len(self._xs) > 0):
3774+
and len(self._xys) > 0):
37853775
h_idx, h_dist = self._polygon_handles.closest(event.x, event.y)
37863776
if h_dist < self.grab_range:
37873777
self._active_handle_idx = h_idx
37883778
# Save the vertex positions at the time of the press event (needed to
37893779
# support the 'move_all' state modifier).
3790-
self._xs_at_press, self._ys_at_press = self._xs.copy(), self._ys.copy()
3780+
self._xys_at_press = self._xys.copy()
37913781

37923782
def _release(self, event):
37933783
"""Button release event handler."""
@@ -3799,9 +3789,7 @@ def _release(self, event):
37993789
self._active_handle_idx = -1
38003790

38013791
# Complete the polygon.
3802-
elif (len(self._xs) > 3
3803-
and self._xs[-1] == self._xs[0]
3804-
and self._ys[-1] == self._ys[0]):
3792+
elif len(self._xys) > 3 and self._xys[-1] == self._xys[0]:
38053793
self._selection_completed = True
38063794
if self._draw_box and self._box is None:
38073795
self._add_box()
@@ -3810,8 +3798,7 @@ def _release(self, event):
38103798
elif (not self._selection_completed
38113799
and 'move_all' not in self._state
38123800
and 'move_vertex' not in self._state):
3813-
self._xs.insert(-1, event.xdata)
3814-
self._ys.insert(-1, event.ydata)
3801+
self._xys.insert(-1, (event.xdata, event.ydata))
38153802

38163803
if self._selection_completed:
38173804
self.onselect(self.verts)
@@ -3833,19 +3820,19 @@ def _onmove(self, event):
38333820
# Move the active vertex (ToolHandle).
38343821
if self._active_handle_idx >= 0:
38353822
idx = self._active_handle_idx
3836-
self._xs[idx], self._ys[idx] = event.xdata, event.ydata
3823+
self._xys[idx] = event.xdata, event.ydata
38373824
# Also update the end of the polygon line if the first vertex is
38383825
# the active handle and the polygon is completed.
38393826
if idx == 0 and self._selection_completed:
3840-
self._xs[-1], self._ys[-1] = event.xdata, event.ydata
3827+
self._xys[-1] = event.xdata, event.ydata
38413828

38423829
# Move all vertices.
38433830
elif 'move_all' in self._state and self._eventpress:
38443831
dx = event.xdata - self._eventpress.xdata
38453832
dy = event.ydata - self._eventpress.ydata
3846-
for k in range(len(self._xs)):
3847-
self._xs[k] = self._xs_at_press[k] + dx
3848-
self._ys[k] = self._ys_at_press[k] + dy
3833+
for k in range(len(self._xys)):
3834+
x_at_press, y_at_press = self._xys_at_press[k]
3835+
self._xys[k] = x_at_press + dx, y_at_press + dy
38493836

38503837
# Do nothing if completed or waiting for a move.
38513838
elif (self._selection_completed
@@ -3855,15 +3842,14 @@ def _onmove(self, event):
38553842
# Position pending vertex.
38563843
else:
38573844
# Calculate distance to the start vertex.
3858-
x0, y0 = self._selection_artist.get_transform().transform(
3859-
(self._xs[0], self._ys[0])
3860-
)
3845+
x0, y0 = \
3846+
self._selection_artist.get_transform().transform(self._xys[0])
38613847
v0_dist = np.hypot(x0 - event.x, y0 - event.y)
38623848
# Lock on to the start vertex if near it and ready to complete.
3863-
if len(self._xs) > 3 and v0_dist < self.grab_range:
3864-
self._xs[-1], self._ys[-1] = self._xs[0], self._ys[0]
3849+
if len(self._xys) > 3 and v0_dist < self.grab_range:
3850+
self._xys[-1] = self._xys[0]
38653851
else:
3866-
self._xs[-1], self._ys[-1] = event.xdata, event.ydata
3852+
self._xys[-1] = event.xdata, event.ydata
38673853

38683854
self._draw_polygon()
38693855

@@ -3874,7 +3860,7 @@ def _on_key_press(self, event):
38743860
if (not self._selection_completed
38753861
and ('move_vertex' in self._state or
38763862
'move_all' in self._state)):
3877-
self._xs, self._ys = self._xs[:-1], self._ys[:-1]
3863+
self._xys.pop()
38783864
self._draw_polygon()
38793865

38803866
def _on_key_release(self, event):
@@ -3885,37 +3871,36 @@ def _on_key_release(self, event):
38853871
and
38863872
(event.key == self._state_modifier_keys.get('move_vertex')
38873873
or event.key == self._state_modifier_keys.get('move_all'))):
3888-
self._xs.append(event.xdata)
3889-
self._ys.append(event.ydata)
3874+
self._xys.append((event.xdata, event.ydata))
38903875
self._draw_polygon()
38913876
# Reset the polygon if the released key is the 'clear' key.
38923877
elif event.key == self._state_modifier_keys.get('clear'):
38933878
event = self._clean_event(event)
3894-
self._xs, self._ys = [event.xdata], [event.ydata]
3879+
self._xys = [(event.xdata, event.ydata)]
38953880
self._selection_completed = False
38963881
self._remove_box()
38973882
self.set_visible(True)
38983883

38993884
def _draw_polygon(self):
39003885
"""Redraw the polygon based on the new vertex positions."""
3901-
self._selection_artist.set_data(self._xs, self._ys)
3886+
xs, ys = zip(*self._xys) if self._xys else ([], [])
3887+
self._selection_artist.set_data(xs, ys)
39023888
self._update_box()
39033889
# Only show one tool handle at the start and end vertex of the polygon
39043890
# if the polygon is completed or the user is locked on to the start
39053891
# vertex.
39063892
if (self._selection_completed
3907-
or (len(self._xs) > 3
3908-
and self._xs[-1] == self._xs[0]
3909-
and self._ys[-1] == self._ys[0])):
3910-
self._polygon_handles.set_data(self._xs[:-1], self._ys[:-1])
3893+
or (len(self._xys) > 3
3894+
and self._xys[-1] == self._xys[0])):
3895+
self._polygon_handles.set_data(xs[:-1], ys[:-1])
39113896
else:
3912-
self._polygon_handles.set_data(self._xs, self._ys)
3897+
self._polygon_handles.set_data(xs, ys)
39133898
self.update()
39143899

39153900
@property
39163901
def verts(self):
39173902
"""The polygon vertices, as a list of ``(x, y)`` pairs."""
3918-
return list(zip(self._xs[:-1], self._ys[:-1]))
3903+
return self._xys[:-1]
39193904

39203905
@verts.setter
39213906
def verts(self, xys):
@@ -3925,10 +3910,7 @@ def verts(self, xys):
39253910
This will remove any pre-existing vertices, creating a complete polygon
39263911
with the new vertices.
39273912
"""
3928-
self._xs = [xy[0] for xy in xys]
3929-
self._xs.append(self._xs[0])
3930-
self._ys = [xy[1] for xy in xys]
3931-
self._ys.append(self._ys[0])
3913+
self._xys = [*xys, xys[0]]
39323914
self._selection_completed = True
39333915
self.set_visible(True)
39343916
self._draw_polygon()

0 commit comments

Comments
 (0)
0