Skip to content

Add new vertex on to PolygonSelection after closing the polygon #28691

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions lib/matplotlib/tests/test_widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -1478,6 +1478,18 @@ def test_polygon_selector(draw_bounding_box):
]
check_selector(event_sequence, expected_result, 2)

# Complete the polygon and add new vertex
expected_result = [(75, 75), (175, 75), (125, 180), (75, 175)]
event_sequence = [
*polygon_place_vertex(75, 75),
*polygon_place_vertex(175, 75),
*polygon_place_vertex(75, 175),
*polygon_place_vertex(75, 75),
('press', dict(xdata=125, ydata=180)),
('release', dict(xdata=125, ydata=180)),
]
check_selector(event_sequence, expected_result, 2)

# Try to move a vertex and move all before placing any vertices.
expected_result = [(50, 50), (150, 50), (50, 150)]
event_sequence = [
Expand Down
40 changes: 39 additions & 1 deletion lib/matplotlib/widgets.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""
GUI neutral widgets
===================
Expand Down Expand Up @@ -3723,14 +3723,32 @@
self.update()


def _dist_to_line(p1, p2, p3):
"""
Calculates the distance of the line connecting the points p1 and p2 to point p3
"""

def dist_sqr(p, q):
return (q[0] - p[0]) ** 2 + (q[1] - p[1]) ** 2

dist = dist_sqr(p1, p2)
if dist == 0:
raise ValueError("p1 and p2 are coincidental, there is no line")

Check warning on line 3736 in lib/matplotlib/widgets.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/widgets.py#L3736

Added line #L3736 was not covered by tests
u = ((p3[0] - p1[0]) * (p2[0] - p1[0]) + (p3[1] - p1[1]) * (p2[1] - p1[1])) / dist
intersection = p1[0] + u * (p2[0] - p1[0]), p1[1] + u * (p2[1] - p1[1])

return dist_sqr(intersection, p3) ** 0.5, u


class PolygonSelector(_SelectorWidget):
"""
Select a polygon region of an Axes.

Place vertices with each mouse click, and make the selection by completing
the polygon (clicking on the first vertex). Once drawn individual vertices
can be moved by clicking and dragging with the left mouse button, or
removed by clicking the right mouse button.
removed by clicking the right mouse button. Also new vertices can be
added by left clicking.

In addition, the following modifier keys can be used:

Expand Down Expand Up @@ -3890,6 +3908,8 @@
if self._old_box_extents == self._box.extents:
return

self._box.add_state("move")

# Create transform from old box to new box
x1, y1, w1, h1 = self._box._rect_bbox
old_bbox = self._get_bbox()
Expand Down Expand Up @@ -3950,6 +3970,24 @@
self._draw_polygon()
self._active_handle_idx = -1

elif (self._selection_completed
and "move_all"
not in self._state
and "move_vertex" not in self._state
and (self._box is None or "move" not in self._box._state)):
if event.button == 1:
p3 = self._get_data_coords(event)
min_dist = np.inf
index = None
for i, (p1, p2) in enumerate(zip(self._xys[:-1], self._xys[1:])):
dist, u = _dist_to_line(p1, p2, p3)
if 1 > u > 0:
if min_dist > dist:
min_dist = dist
index = i
self._xys.insert(index + 1, p3)
self._draw_polygon()

# Complete the polygon.
elif len(self._xys) > 3 and self._xys[-1] == self._xys[0]:
self._selection_completed = True
Expand Down
Loading