Skip to content

Commit 070b912

Browse files
committed
Allow PolygonSelector points to be removed
1 parent 8fda099 commit 070b912

File tree

3 files changed

+80
-5
lines changed

3 files changed

+80
-5
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Removing points on a PolygonSelector
2+
------------------------------------
3+
After fishing drawing a `~matplotlib.widgets.PolygonSelector`, individual
4+
points can now be removed by right-clicking on them.

lib/matplotlib/tests/test_widgets.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,12 @@ def polygon_place_vertex(xdata, ydata):
416416
('release', dict(xdata=xdata, ydata=ydata))]
417417

418418

419+
def polygon_remove_vertex(xdata, ydata):
420+
return [('onmove', dict(xdata=xdata, ydata=ydata)),
421+
('press', dict(xdata=xdata, ydata=ydata, button=3)),
422+
('release', dict(xdata=xdata, ydata=ydata, button=3))]
423+
424+
419425
def test_polygon_selector():
420426
# Simple polygon
421427
expected_result = [(50, 50), (150, 50), (50, 150)]
@@ -564,3 +570,31 @@ def onselect(verts):
564570
tool = widgets.RectangleSelector(ax_test, onselect,
565571
rectprops={'visible': False})
566572
tool.extents = (0.2, 0.8, 0.3, 0.7)
573+
574+
575+
# Change the order that the extra point is inserted in
576+
@pytest.mark.parametrize('idx', [1, 2, 3])
577+
def test_polygon_selector_remove(idx):
578+
verts = [(50, 50), (150, 50), (50, 150)]
579+
event_sequence = [polygon_place_vertex(*verts[0]),
580+
polygon_place_vertex(*verts[1]),
581+
polygon_place_vertex(*verts[2]),
582+
# Finish the polygon
583+
polygon_place_vertex(*verts[0])]
584+
# Add an extra point
585+
event_sequence.insert(idx, polygon_place_vertex(200, 200))
586+
# Remove the extra point
587+
event_sequence.append(polygon_remove_vertex(200, 200))
588+
# Flatten list of lists
589+
event_sequence = sum(event_sequence, [])
590+
check_polygon_selector(event_sequence, verts, 2)
591+
592+
593+
def test_polygon_selector_remove_first_point():
594+
verts = [(50, 50), (150, 50), (50, 150)]
595+
event_sequence = (polygon_place_vertex(*verts[0]) +
596+
polygon_place_vertex(*verts[1]) +
597+
polygon_place_vertex(*verts[2]) +
598+
polygon_place_vertex(*verts[0]) +
599+
polygon_remove_vertex(*verts[0]))
600+
check_polygon_selector(event_sequence, verts[1:], 2)

lib/matplotlib/widgets.py

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2759,11 +2759,17 @@ class PolygonSelector(_SelectorWidget):
27592759
Select a polygon region of an axes.
27602760
27612761
Place vertices with each mouse click, and make the selection by completing
2762-
the polygon (clicking on the first vertex). Hold the *ctrl* key and click
2763-
and drag a vertex to reposition it (the *ctrl* key is not necessary if the
2764-
polygon has already been completed). Hold the *shift* key and click and
2765-
drag anywhere in the axes to move all vertices. Press the *esc* key to
2766-
start a new polygon.
2762+
the polygon (clicking on the first vertex). Once drawn indiviual vertices
2763+
can be moved by clicking and dragging with the left mouse button, or
2764+
deleted by clicking the right mouse button.
2765+
2766+
In addition, the following modifier keys can be used:
2767+
2768+
- Hold *ctrl* and click and drag a vertex to reposition it before the
2769+
polygon has been copleted.
2770+
- Hold the *shift* key and click and drag anywhere in the axes to move
2771+
all vertices.
2772+
- Press the *esc* key to start a new polygon.
27672773
27682774
For the selector to remain responsive you must keep a reference to it.
27692775
@@ -2827,6 +2833,34 @@ def __init__(self, ax, onselect, useblit=False,
28272833
self.artists = [self.line, self._polygon_handles.artist]
28282834
self.set_visible(True)
28292835

2836+
@property
2837+
def _nverts(self):
2838+
return len(self._xs)
2839+
2840+
def _remove_vertex(self, i):
2841+
"""Remove vertex with index i."""
2842+
print(self._nverts)
2843+
if (self._nverts > 2 and
2844+
self._polygon_completed and
2845+
i in (0, self._nverts - 1)):
2846+
# If selecting the first or final vertex, remove both first and
2847+
# last vertex as they are the same for a closed polygon
2848+
self._xs.pop(0)
2849+
self._ys.pop(0)
2850+
self._xs.pop(-1)
2851+
self._ys.pop(-1)
2852+
# Close the polygon again by appending the new first vertex to the
2853+
# end
2854+
self._xs.append(self._xs[0])
2855+
self._ys.append(self._ys[0])
2856+
else:
2857+
self._xs.pop(i)
2858+
self._ys.pop(i)
2859+
if self._nverts <= 2:
2860+
# If only one point left, return to un-complete state to let user
2861+
# start drawing again
2862+
self._polygon_completed = False
2863+
28302864
def _press(self, event):
28312865
"""Button press event handler."""
28322866
# Check for selection of a tool handle.
@@ -2843,6 +2877,9 @@ def _release(self, event):
28432877
"""Button release event handler."""
28442878
# Release active tool handle.
28452879
if self._active_handle_idx >= 0:
2880+
if event.button == 3:
2881+
self._remove_vertex(self._active_handle_idx)
2882+
self._draw_polygon()
28462883
self._active_handle_idx = -1
28472884

28482885
# Complete the polygon.

0 commit comments

Comments
 (0)