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

Skip to content 10000

Commit 89d09c4

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 89d09c4

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
@@ -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

@@ -3745,33 +3744,25 @@ def _scale_polygon(self, event):
37453744
lambda self, value: setattr(self, "grab_range", value))
37463745
)
37473746

3748-
@property
3749-
def _nverts(self):
3750-
return len(self._xs)
3751-
37523747
@property
37533748
def _handles_artists(self):
37543749
return self._polygon_handles.artists
37553750

37563751
def _remove_vertex(self, i):
37573752
"""Remove vertex with index i."""
3758-
if (self._nverts > 2 and
3753+
if (len(self._xys) > 2 and
37593754
self._selection_completed and
3760-
i in (0, self._nverts - 1)):
3755+
i in (0, len(self._xys) - 1)):
37613756
# If selecting the first or final vertex, remove both first and
37623757
# 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)
3758+
self._xys.pop(0)
3759+
self._xys.pop(-1)
37673760
# Close the polygon again by appending the new first vertex to the
37683761
# end
3769-
self._xs.append(self._xs[0])
3770-
self._ys.append(self._ys[0])
3762+
self._xys.append(self._xys[0])
37713763
else:
3772-
self._xs.pop(i)
3773-
self._ys.pop(i)
3774-
if self._nverts <= 2:
3764+
self._xys.pop(i)
3765+
if len(self._xys) <= 2:
37753766
# If only one point left, return to incomplete state to let user
37763767
# start drawing again
37773768
self._selection_completed = False
@@ -3781,13 +3772,13 @@ def _press(self, event):
37813772
"""Button press event handler."""
37823773
# Check for selection of a tool handle.
37833774
if ((self._selection_completed or 'move_vertex' in self._state)
3784-
and len(self._xs) > 0):
3775+
and len(self._xys) > 0):
37853776
h_idx, h_dist = self._polygon_handles.closest(event.x, event.y)
37863777
if h_dist < self.grab_range:
37873778
self._active_handle_idx = h_idx
37883779
# Save the vertex positions at the time of the press event (needed to
37893780
# support the 'move_all' state modifier).
3790-
self._xs_at_press, self._ys_at_press = self._xs.copy(), self._ys.copy()
3781+
self._xys_at_press = self._xys.copy()
37913782

37923783
def _release(self, event):
37933784
"""Button release event handler."""
@@ -3799,9 +3790,7 @@ def _release(self, event):
37993790
self._active_handle_idx = -1
38003791

38013792
# 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]):
3793+
elif len(self._xys) > 3 and self._xys[-1] == self._xys[0]:
38053794
self._selection_completed = True
38063795
if self._draw_box and self._box is None:
38073796
self._add_box()
@@ -3810,8 +3799,7 @@ def _release(self, event):
38103799
elif (not self._selection_completed
38113800
and 'move_all' not in self._state
38123801
and 'move_vertex' not in self._state):
3813-
self._xs.insert(-1, event.xdata)
3814-
self._ys.insert(-1, event.ydata)
3802+
self._xys.insert(-1, (event.xdata, event.ydata))
38153803

38163804
if self._selection_completed:
38173805
self.onselect(self.verts)
@@ -3833,19 +3821,19 @@ def _onmove(self, event):
38333821
# Move the active vertex (ToolHandle).
38343822
if self._active_handle_idx >= 0:
38353823
idx = self._active_handle_idx
3836-
self._xs[idx], self._ys[idx] = event.xdata, event.ydata
3824+
self._xys[idx] = event.xdata, event.ydata
38373825
# Also update the end of the polygon line if the first vertex is
38383826
# the active handle and the polygon is completed.
38393827
if idx == 0 and self._selection_completed:
3840-
self._xs[-1], self._ys[-1] = event.xdata, event.ydata
3828+
self._xys[-1] = event.xdata, event.ydata
38413829

38423830
# Move all vertices.
38433831
elif 'move_all' in self._state and self._eventpress:
38443832
dx = event.xdata - self._eventpress.xdata
38453833
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
3834+
for k in range(len(self._xys)):
3835+
x_at_press, y_at_press = self._xys_at_press[k]
3836+
self._xys[k] = x_at_press + dx, y_at_press + dy
38493837

38503838
# Do nothing if completed or waiting for a move.
38513839
elif (self._selection_completed
@@ -3855,15 +3843,14 @@ def _onmove(self, event):
38553843
# Position pending vertex.
38563844
else:
38573845
# Calculate distance to the start vertex.
3858-
x0, y0 = self._selection_artist.get_transform().transform(
3859-
(self._xs[0], self._ys[0])
3860-
)
3846+
x0, y0 = \
3847+
self._selection_artist.get_transform().transform(self._xys[0])
38613848
v0_dist = np.hypot(x0 - event.x, y0 - event.y)
38623849
# 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]
3850+
if len(self._xys) > 3 and v0_dist < self.grab_range:
3851+
self._xys[-1] = self._xys[0]
38653852
else:
3866-
self._xs[-1], self._ys[-1] = event.xdata, event.ydata
3853+
self._xys[-1] = event.xdata, event.ydata
38673854

38683855
self._draw_polygon()
38693856

@@ -3874,7 +3861,7 @@ def _on_key_press(self, event):
38743861
if (not self._selection_completed
38753862
and ('move_vertex' in self._state or
38763863
'move_all' in self._state)):
3877-
self._xs, self._ys = self._xs[:-1], self._ys[:-1]
3864+
self._xys.pop()
38783865
self._draw_polygon()
38793866

38803867
def _on_key_release(self, event):
@@ -3885,37 +3872,36 @@ def _on_key_release(self, event):
38853872
and
38863873
(event.key == self._state_modifier_keys.get('move_vertex')
38873874
or event.key == self._state_modifier_keys.get('move_all'))):
3888-
self._xs.append(event.xdata)
3889-
self._ys.append(event.ydata)
3875+
self._xys.append((event.xdata, event.ydata))
38903876
self._draw_polygon()
38913877
# Reset the polygon if the released key is the 'clear' key.
38923878
elif event.key == self._state_modifier_keys.get('clear'):
38933879
event = self._clean_event(event)
3894-
self._xs, self._ys = [event.xdata], [event.ydata]
3880+
self._xys = [(event.xdata, event.ydata)]
38953881
self._selection_completed = False
38963882
self._remove_box()
38973883
self.set_visible(True)
38983884

38993885
def _draw_polygon(self):
39003886
"""Redraw the polygon based on the new vertex positions."""
3901-
self._selection_artist.set_data(self._xs, self._ys)
3887+
xs, ys = zip(*self._xys) if self._xys else ([], [])
3888+
self._selection_artist.set_data(xs, ys)
39023889
self._update_box()
39033890
# Only show one tool handle at the start and end vertex of the polygon
39043891
# if the polygon is completed or the user is locked on to the start
39053892
# vertex.
39063893
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])
3894+
or (len(self._xys) > 3
3895+
and self._xys[-1] == self._xys[0])):
3896+
self._polygon_handles.set_data(xs[:-1], ys[:-1])
39113897
else:
3912-
self._polygon_handles.set_data(self._xs, self._ys)
3898+
self._polygon_handles.set_data(xs, ys)
39133899
self.update()
39143900

39153901
@property
39163902
def verts(self):
39173903
"""The polygon vertices, as a list of ``(x, y)`` pairs."""
3918-
return list(zip(self._xs[:-1], self._ys[:-1]))
3904+
return self._xys[:-1]
39193905

39203906
@verts.setter
39213907
def verts(self, xys):
@@ -3925,10 +3911,7 @@ def verts(self, xys):
39253911
This will remove any pre-existing vertices, creating a complete polygon
39263912
with the new vertices.
39273913
"""
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])
3914+
self._xys = [*xys, xys[0]]
39323915
self._selection_completed = True
39333916
self.set_visible(True)
39343917
self._draw_polygon()

0 commit comments

Comments
 (0)
0