8000 Merge pull request #21894 from anntzer/polygonselectorxy · matplotlib/matplotlib@51f10e2 · GitHub
[go: up one dir, main page]

Skip to content

Commit 51f10e2

Browse files
authored
Merge pull request #21894 from anntzer/polygonselectorxy
Jointly track x and y in PolygonSelector.
2 parents 742a6e3 + 7f4eb87 commit 51f10e2

File tree

1 file changed

+38
-56
lines changed

1 file changed

+38
-56
lines changed

lib/matplotlib/widgets.py

Lines changed: 38 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -3640,21 +3640,20 @@ def __init__(self, ax, onselect, useblit=False,
36403640
super().__init__(ax, onselect, useblit=useblit,
36413641
state_modifier_keys=state_modifier_keys)
36423642

3643-
self._xs, self._ys = [0], [0]
3643+
self._xys = [(0, 0)]
36443644

36453645
if props is None:
36463646
props = dict(color='k', linestyle='-', linewidth=2, alpha=0.5)
36473647
props['animated'] = self.useblit
36483648
self._props = props
3649-
line = Line2D(self._xs, self._ys, **self._props)
3649+
self._selection_artist = line = Line2D([], [], **self._props)
36503650
self.ax.add_line(line)
3651-
self._selection_artist = line
36523651

36533652
if handle_props is None:
36543653
handle_props = dict(markeredgecolor='k',
36553654
markerfacecolor=self._props.get('color', 'k'))
36563655
self._handle_props = handle_props
3657-
self._polygon_handles = ToolHandles(self.ax, self._xs, self._ys,
3656+
self._polygon_handles = ToolHandles(self.ax, [], [],
36583657
useblit=self.useblit,
36593658
marker_props=self._handle_props)
36603659

@@ -3725,10 +3724,9 @@ def _scale_polygon(self, event):
37253724
.scale(w1, h1)
37263725
.translate(x1, y1))
37273726

3728-
# Update polygon verts
3729-
new_verts = t.transform(np.array(self.verts))
3730-
self._xs = list(np.append(new_verts[:, 0], new_verts[0, 0]))
3731-
self._ys = list(np.append(new_verts[:, 1], new_verts[0, 1]))
3727+
# Update polygon verts. Must be a list of tuples for consistency.
3728+
new_verts = [(x, y) for x, y in t.transform(np.array(self.verts))]
3729+
self._xys = [*new_verts, new_verts[0]]
37323730
self._draw_polygon()
37333731
self._old_box_extents = self._box.extents
37343732

@@ -3742,33 +3740,25 @@ def _scale_polygon(self, event):
37423740
lambda self, value: setattr(self, "grab_range", value))
37433741
)
37443742

3745-
@property
3746-
def _nverts(self):
3747-
return len(self._xs)
3748-
37493743
@property
37503744
def _handles_artists(self):
37513745
return self._polygon_handles.artists
37523746

37533747
def _remove_vertex(self, i):
37543748
"""Remove vertex with index i."""
3755-
if (self._nverts > 2 and
3749+
if (len(self._xys) > 2 and
37563750
self._selection_completed and
3757-
i in (0, self._nverts - 1)):
3751+
i in (0, len(self._xys) - 1)):
37583752
# If selecting the first or final vertex, remove both first and
37593753
# last vertex as they are the same for a closed polygon
3760-
self._xs.pop(0)
3761-
self._ys.pop(0)
3762-
self._xs.pop(-1)
3763-
self._ys.pop(-1)
3754+
self._xys.pop(0)
3755+
self._xys.pop(-1)
37643756
# Close the polygon again by appending the new first vertex to the
37653757
# end
3766-
self._xs.append(self._xs[0])
3767-
self._ys.append(self._ys[0])
3758+
self._xys.append(self._xys[0])
37683759
else:
3769-
self._xs.pop(i)
3770-
self._ys.pop(i)
3771-
if self._nverts <= 2:
3760+
self._xys.pop(i)
3761+
if len(self._xys) <= 2:
37723762
# If only one point left, return to incomplete state to let user
37733763
# start drawing again
37743764
self._selection_completed = False
@@ -3778,13 +3768,13 @@ def _press(self, event):
37783768
"""Button press event handler."""
37793769
# Check for selection of a tool handle.
37803770
if ((self._selection_completed or 'move_vertex' in self._state)
3781-
and len(self._xs) > 0):
3771+
and len(self._xys) > 0):
37823772
h_idx, h_dist = self._polygon_handles.closest(event.x, event.y)
37833773
if h_dist < self.grab_range:
37843774
self._active_handle_idx = h_idx
37853775
# Save the vertex positions at the time of the press event (needed to
37863776
# support the 'move_all' state modifier).
3787-
self._xs_at_press, self._ys_at_press = self._xs.copy(), self._ys.copy()
3777+
self._xys_at_press = self._xys.copy()
37883778

37893779
def _release(self, event):
37903780
"""Button release event handler."""
@@ -3796,9 +3786,7 @@ def _release(self, event):
37963786
self._active_handle_idx = -1
37973787

37983788
# Complete the polygon.
3799-
elif (len(self._xs) > 3
3800-
and self._xs[-1] == self._xs[0]
3801-
and self._ys[-1] == self._ys[0]):
3789+
elif len(self._xys) > 3 and self._xys[-1] == self._xys[0]:
38023790
self._selection_completed = True
38033791
if self._draw_box and self._box is None:
38043792
self._add_box()
@@ -3807,8 +3795,7 @@ def _release(self, event):
38073795
elif (not self._selection_completed
38083796
and 'move_all' not in self._state
38093797
and 'move_vertex' not in self._state):
3810-
self._xs.insert(-1, event.xdata)
3811-
self._ys.insert(-1, event.ydata)
3798+
self._xys.insert(-1, (event.xdata, event.ydata))
38123799

38133800
if self._selection_completed:
38143801
self.onselect(self.verts)
@@ -3830,19 +3817,19 @@ def _onmove(self, event):
38303817
# Move the active vertex (ToolHandle).
38313818
if self._active_handle_idx >= 0:
38323819
idx = self._active_handle_idx
3833-
self._xs[idx], self._ys[idx] = event.xdata, event.ydata
3820+
self._xys[idx] = event.xdata, event.ydata
38343821
# Also update the end of the polygon line if the first vertex is
38353822
# the active handle and the polygon is completed.
38363823
if idx == 0 and self._selection_completed:
3837-
self._xs[-1], self._ys[-1] = event.xdata, event.ydata
3824+
self._xys[-1] = event.xdata, event.ydata
38383825

38393826
# Move all vertices.
38403827
elif 'move_all' in self._state and self._eventpress:
38413828
dx = event.xdata - self._eventpress.xdata
38423829
dy = event.ydata - self._eventpress.ydata
3843-
for k in range(len(self._xs)):
3844-
self._xs[k] = self._xs_at_press[k] + dx
3845-
self._ys[k] = self._ys_at_press[k] + dy
3830+
for k in range(len(self._xys)):
3831+
x_at_press, y_at_press = self._xys_at_press[k]
3832+
self._xys[k] = x_at_press + dx, y_at_press + dy
38463833

38473834
# Do nothing if completed or waiting for a move.
38483835
elif (self._selection_completed
@@ -3852,15 +3839,14 @@ def _onmove(self, event):
38523839
# Position pending vertex.
38533840
else:
38543841
# Calculate distance to the start vertex.
3855-
x0, y0 = self._selection_artist.get_transform().transform(
3856-
(self._xs[0], self._ys[0])
3857-
)
3842+
x0, y0 = \
3843+
self._selection_artist.get_transform().transform(self._xys[0])
38583844
v0_dist = np.hypot(x0 - event.x, y0 - event.y)
38593845
# Lock on to the start vertex if near it and ready to complete.
3860-
if len(self._xs) > 3 and v0_dist < self.grab_range:
3861-
self._xs[-1], self._ys[-1] = self._xs[0], self._ys[0]
3846+
if len(self._xys) > 3 and v0_dist < self.grab_range:
3847+
self._xys[-1] = self._xys[0]
38623848
else:
3863-
self._xs[-1], self._ys[-1] = event.xdata, event.ydata
3849+
self._xys[-1] = event.xdata, event.ydata
38643850

38653851
self._draw_polygon()
38663852

@@ -3871,7 +3857,7 @@ def _on_key_press(self, event):
38713857
if (not self._selection_completed
38723858
and ('move_vertex' in self._state or
38733859
'move_all' in self._state)):
3874-
self._xs, self._ys = self._xs[:-1], self._ys[:-1]
3860+
self._xys.pop()
38753861
self._draw_polygon()
38763862

38773863
def _on_key_release(self, event):
@@ -3882,37 +3868,36 @@ def _on_key_release(self, event):
38823868
and
38833869
(event.key == self._state_modifier_keys.get('move_vertex')
38843870
or event.key == self._state_modifier_keys.get('move_all'))):
3885-
self._xs.append(event.xdata)
3886-
self._ys.append(event.ydata)
3871+
self._xys.append((event.xdata, event.ydata))
38873872
self._draw_polygon()
38883873
# Reset the polygon if the released key is the 'clear' key.
38893874
elif event.key == self._state_modifier_keys.get('clear'):
38903875
event = self._clean_event(event)
3891-
self._xs, self._ys = [event.xdata], [event.ydata]
3876+
self._xys = [(event.xdata, event.ydata)]
38923877
self._selection_completed = False
38933878
self._remove_box()
38943879
self.set_visible(True)
38953880

38963881
def _draw_polygon(self):
38973882
"""Redraw the polygon based on the new vertex positions."""
3898-
self._selection_artist.set_data(self._xs, self._ys)
3883+
xs, ys = zip(*self._xys) if self._xys else ([], [])
3884+
self._selection_artist.set_data(xs, ys)
38993885
self._update_box()
39003886
# Only show one tool handle at the start and end vertex of the polygon
39013887
# if the polygon is completed or the user is locked on to the start
39023888
# vertex.
39033889
if (self._selection_completed
3904-
or (len(self._xs) > 3
3905-
and self._xs[-1] == self._xs[0]
3906-
and self._ys[-1] == self._ys[0])):
3907-
self._polygon_handles.set_data(self._xs[:-1], self._ys[:-1])
3890+
or (len(self._xys) > 3
3891+
and self._xys[-1] == self._xys[0])):
3892+
self._polygon_handles.set_data(xs[:-1], ys[:-1])
39083893
else:
3909-
self._polygon_handles.set_data(self._xs, self._ys)
3894+
self._polygon_handles.set_data(xs, ys)
39103895
self.update()
39113896

39123897
@property
39133898
def verts(self):
39143899
"""The polygon vertices, as a list of ``(x, y)`` pairs."""
3915-
return list(zip(self._xs[:-1], self._ys[:-1]))
3900+
return self._xys[:-1]
39163901

39173902
@verts.setter
39183903
def verts(self, xys):
@@ -3922,10 +3907,7 @@ def verts(self, xys):
39223907
This will remove any pre-existing vertices, creating a complete polygon
39233908
with the new vertices.
39243909
"""
3925-
self._xs = [xy[0] for xy in xys]
3926-
self._xs.append(self._xs[0])
3927-
self._ys = [xy[1] for xy in xys]
3928-
self._ys.append(self._ys[0])
3910+
self._xys = [*xys, xys[0]]
39293911
self._selection_completed = True
39303912
self.set_visible(True)
39313913
self._draw_polygon()

0 commit comments

Comments
 (0)
0