Skip to content

Commit 9d5f71f

Browse files
committed
Add set_props and set_handle_props to selectors.
1 parent 233a05d commit 9d5f71f

File tree

2 files changed

+146
-10
lines changed

2 files changed

+146
-10
lines changed

lib/matplotlib/tests/test_widgets.py

Lines changed: 101 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,36 @@ def onselect(epress, erelease):
9090
assert tool.center == (180, 190)
9191

9292

93+
def test_rectangle_selector_set_props_handle_props():
94+
ax = get_ax()
95+
96+
def onselect(epress, erelease):
97+
pass
98+
99+
tool = widgets.RectangleSelector(ax, onselect, interactive=True,
100+
props=dict(facecolor='b', alpha=0.2),
101+
handle_props=dict(alpha=0.5))
102+
# Create rectangle
103+
do_event(tool, 'press', xdata=0, ydata=10, button=1)
104+
do_event(tool, 'onmove', xdata=100, ydata=120, button=1)
105+
do_event(tool, 'release', xdata=100, ydata=120, button=1)
106+
107+
artist = tool.artists[0]
108+
assert artist.get_facecolor() == mcolors.to_rgba('b', alpha=0.2)
109+
props = dict(facecolor='r', alpha=0.3)
110+
tool.set_props(**props)
111+
assert artist.get_facecolor() == mcolors.to_rgba(*props.values())
112+
113+
for artist in tool._handles_artists:
114+
assert artist.get_markeredgecolor() == 'black'
115+
assert artist.get_alpha() == 0.5
116+
handle_props = dict(markeredgecolor='r', alpha=0.3)
117+
tool.set_handle_props(**handle_props)
118+
for artist in tool._handles_artists:
119+
assert artist.get_markeredgecolor() == 'r'
120+
assert artist.get_alpha() == 0.3
121+
122+
93123
def test_ellipse():
94124
"""For ellipse, test out the key modifiers"""
95125
ax = get_ax()
@@ -185,9 +215,9 @@ def onselect(epress, erelease):
185215

186216
# Check that marker_props worked.
187217
assert mcolors.same_color(
188-
tool._corner_handles.artist.get_markerfacecolor(), 'r')
218+
tool._corner_handles.artists[0].get_markerfacecolor(), 'r')
189219
assert mcolors.same_color(
190-
tool._corner_handles.artist.get_markeredgecolor(), 'b')
220+
tool._corner_handles.artists[0].get_markeredgecolor(), 'b')
191221

192222

193223
@pytest.mark.parametrize('interactive', [True, False])
@@ -404,6 +434,36 @@ def onselect(*args):
404434
tool.direction = 'invalid_string'
405435

406436

437+
def test_span_selector_set_props_handle_props():
438+
ax = get_ax()
439+
440+
def onselect(epress, erelease):
441+
pass
442+
443+
tool = widgets.SpanSelector(ax, onselect, 'horizontal', interactive=True,
444+
props=dict(facecolor='b', alpha=0.2),
445+
handle_props=dict(alpha=0.5))
446+
# Create rectangle
447+
do_event(tool, 'press', xdata=0, ydata=10, button=1)
448+
do_event(tool, 'onmove', xdata=100, ydata=120, button=1)
449+
do_event(tool, 'release', xdata=100, ydata=120, button=1)
450+
451+
artist = tool.artists[0]
452+
assert artist.get_facecolor() == mcolors.to_rgba('b', alpha=0.2)
453+
props = dict(facecolor='r', alpha=0.3)
454+
tool.set_props(**props)
455+
assert artist.get_facecolor() == mcolors.to_rgba(*props.values())
456+
457+
for artist in tool._handles_artists:
458+
assert artist.get_color() == 'b'
459+
assert artist.get_alpha() == 0.5
460+
handle_props = dict(color='r', alpha=0.3)
461+
tool.set_handle_props(**handle_props)
462+
for artist in tool._handles_artists:
463+
assert artist.get_color() == 'r'
464+
assert artist.get_alpha() == 0.3
465+
466+
407467
def test_tool_line_handle():
408468
ax = get_ax()
409469

@@ -781,6 +841,45 @@ def test_polygon_selector():
781841
check_polygon_selector(event_sequence, expected_result, 1)
782842

783843

844+
def test_polygon_selector_set_props_handle_props():
845+
ax = get_ax()
846+
847+
ax._selections_count = 0
848+
849+
def onselect(vertices):
850+
ax._selections_count += 1
851+
ax._current_result = vertices
852+
853+
tool = widgets.PolygonSelector(ax, onselect,
854+
props=dict(color='b', alpha=0.2),
855+
handle_props=dict(alpha=0.5))
856+
857+
event_sequence = (polygon_place_vertex(50, 50)
858+
+ polygon_place_vertex(150, 50)
859+
+ polygon_place_vertex(50, 150)
860+
+ polygon_place_vertex(50, 50))
861+
862+
for (etype, event_args) in event_sequence:
863+
do_event(tool, etype, **event_args)
864+
865+
artist = tool.artists[0]
866+
assert artist.get_color() == 'b'
867+
assert artist.get_alpha() == 0.2
868+
props = dict(color='r', alpha=0.3)
869+
tool.set_props(**props)
870+
assert artist.get_color() == props['color']
871+
assert artist.get_alpha() == props['alpha']
872+
873+
for artist in tool._handles_artists:
874+
assert artist.get_color() == 'b'
875+
assert artist.get_alpha() == 0.5
876+
handle_props = dict(color='r', alpha=0.3)
877+
tool.set_handle_props(**handle_props)
878+
for artist in tool._handles_artists:
879+
assert artist.get_color() == 'r'
880+
assert artist.get_alpha() == 0.3
881+
882+
784883
@pytest.mark.parametrize(
785884
"horizOn, vertOn",
786885
[(True, True), (True, False), (False, True)],

lib/matplotlib/widgets.py

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2016,8 +2016,31 @@ def add_artist(self, artist):
20162016

20172017
@property
20182018
def artists(self):
2019+
"""Tuple of the artists of the selector"""
20192020
return tuple(self._artists)
20202021

2022+
def set_props(self, **props):
2023+
"""
2024+
Set the properties of the selector artist. See the `props` argument
2025+
in the selector docstring to know which properties are supported.
2026+
"""
2027+
self.artists[0].set(**props)
2028+
self.update()
2029+
self._props = props
2030+
2031+
def set_handle_props(self, **handle_props):
2032+
"""
2033+
Set the properties of the handles selector artist. See the
2034+
`handle_props` argument in the selector docstring to know which
2035+
properties are supported.
2036+
"""
2037+
if not hasattr(self, '_handles_artists'):
2038+
raise NotImplementedError("This selector doesn't have handles.")
2039+
for handle in self._handles_artists:
2040+
handle.set(**handle_props)
2041+
self.update()
2042+
self._handle_props = handle_props
2043+
20212044

20222045
class SpanSelector(_SelectorWidget):
20232046
"""
@@ -2150,7 +2173,7 @@ def __init__(self, ax, onselect, direction, minspan=0, useblit=False,
21502173

21512174
if self._interactive:
21522175
self._edge_order = ['min', 'max']
2153-
self._setup_edge_handle(handle_props)
2176+
self._setup_edge_handles(handle_props)
21542177

21552178
self._active_handle = None
21562179

@@ -2203,7 +2226,7 @@ def new_axes(self, ax):
22032226
else:
22042227
self.add_artist(rect_artist)
22052228

2206-
def _setup_edge_handle(self, props):
2229+
def _setup_edge_handles(self, props):
22072230
# Define initial position using the axis bounds to keep the same bounds
22082231
if self.direction == 'horizontal':
22092232
positions = self.ax.get_xbound()
@@ -2283,7 +2306,7 @@ def direction(self, direction):
22832306
self._direction = direction
22842307
self.new_axes(self.ax)
22852308
if self._interactive:
2286-
self._setup_edge_handle(self._edge_handles._line_props)
2309+
self._setup_edge_handles(self._edge_handles._line_props)
22872310
else:
22882311
self._direction = direction
22892312

@@ -2439,6 +2462,10 @@ def extents(self, extents):
24392462
self.set_visible(self.visible)
24402463
self.update()
24412464

2465+
@property
2466+
def _handles_artists(self):
2467+
return self._edge_handles.artists
2468+
24422469

24432470
class ToolLineHandles:
24442471
"""
@@ -2575,7 +2602,6 @@ def __init__(self, ax, x, y, marker='o', marker_props=None, useblit=True):
25752602
**cbook.normalize_kwargs(marker_props, Line2D._alias_map)}
25762603
self._markers = Line2D(x, y, animated=useblit, **props)
25772604
self.ax.add_line(self._markers)
2578-
self.artist = self._markers
25792605

25802606
@property
25812607
def x(self):
@@ -2585,6 +2611,10 @@ def x(self):
25852611
def y(self):
25862612
return self._markers.get_ydata()
25872613

2614+
@property
2615+
def artists(self):
2616+
return (self._markers, )
2617+
25882618
def set_data(self, pts, y=None):
25892619
"""Set x and y positions of handles."""
25902620
if y is not None:
@@ -2808,9 +2838,7 @@ def __init__(self, ax, onselect, drawtype='box',
28082838

28092839
self._active_handle = None
28102840

2811-
self._artists.extend([self._center_handle.artist,
2812-
self._corner_handles.artist,
2813-
self._edge_handles.artist])
2841+
self._artists.extend(self._handles_artists)
28142842

28152843
self._extents_on_press = None
28162844

@@ -2826,6 +2854,11 @@ def __init__(self, ax, onselect, drawtype='box',
28262854
property(lambda self: self.grab_range,
28272855
lambda self, value: setattr(self, "grab_range", value)))
28282856

2857+
@property
2858+
def _handles_artists(self):
2859+
return (self._center_handle.artists + self._corner_handles.artists +
2860+
self._edge_handles.artists)
2861+
28292862
def _press(self, event):
28302863
"""Button press event handler."""
28312864
# make the drawn box/line visible get the click-coordinates,
@@ -3335,7 +3368,7 @@ def __init__(self, ax, onselect, useblit=False,
33353368
self._active_handle_idx = -1
33363369
self.grab_range = grab_range
33373370

3338-
self._artists = [line, self._polygon_handles.artist]
3371+
self._artists = [line] + list(self._handles_artists)
33393372
self.set_visible(True)
33403373

33413374
vertex_select_radius = _api.deprecated("3.5", name="vertex_select_radius",
@@ -3348,6 +3381,10 @@ def __init__(self, ax, onselect, useblit=False,
33483381
def _nverts(self):
33493382
return len(self._xs)
33503383

3384+
@property
3385+
def _handles_artists(self):
3386+
return self._polygon_handles.artists
3387+
33513388
def _remove_vertex(self, i):
33523389
"""Remove vertex with index i."""
33533390
if (self._nverts > 2 and

0 commit comments

Comments
 (0)