Skip to content

Commit 15beb47

Browse files
committed
Add set_props and set_handle_props to selectors.
1 parent e3980fe commit 15beb47

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
def check_span(*args, **kwargs):
@@ -281,6 +311,36 @@ def onselect(epress, erelease):
281311
tool.direction = 'invalid_string'
282312

283313

314+
def test_span_selector_set_props_handle_props():
315+
ax = get_ax()
316+
317+
def onselect(epress, erelease):
318+
pass
319+
320+
tool = widgets.SpanSelector(ax, onselect, 'horizontal', interactive=True,
321+
props=dict(facecolor='b', alpha=0.2),
322+
handle_props=dict(alpha=0.5))
323+
# Create rectangle
324+
do_event(tool, 'press', xdata=0, ydata=10, button=1)
325+
do_event(tool, 'onmove', xdata=100, ydata=120, button=1)
326+
do_event(tool, 'release', xdata=100, ydata=120, button=1)
327+
328+
artist = tool.artists[0]
329+
assert artist.get_facecolor() == mcolors.to_rgba('b', alpha=0.2)
330+
props = dict(facecolor='r', alpha=0.3)
331+
tool.set_props(**props)
332+
assert artist.get_facecolor() == mcolors.to_rgba(*props.values())
333+
334+
for artist in tool._handles_artists:
335+
assert artist.get_color() == 'b'
336+
assert artist.get_alpha() == 0.5
337+
handle_props = dict(color='r', alpha=0.3)
338+
tool.set_handle_props(**handle_props)
339+
for artist in tool._handles_artists:
340+
assert artist.get_color() == 'r'
341+
assert artist.get_alpha() == 0.3
342+
343+
284344
def test_tool_line_handle():
285345
ax = get_ax()
286346

@@ -658,6 +718,45 @@ def test_polygon_selector():
658718
check_polygon_selector(event_sequence, expected_result, 1)
659719

660720

721+
def test_polygon_selector_set_props_handle_props():
722+
ax = get_ax()
723+
724+
ax._selections_count = 0
725+
726+
def onselect(vertices):
727+
ax._selections_count += 1
728+
ax._current_result = vertices
729+
730+
tool = widgets.PolygonSelector(ax, onselect,
731+
props=dict(color='b', alpha=0.2),
732+
handle_props=dict(alpha=0.5))
733+
734+
event_sequence = (polygon_place_vertex(50, 50)
735+
+ polygon_place_vertex(150, 50)
736+
+ polygon_place_vertex(50, 150)
737+
+ polygon_place_vertex(50, 50))
738+
739+
for (etype, event_args) in event_sequence:
740+
do_event(tool, etype, **event_args)
741+
742+
artist = tool.artists[0]
743+
assert artist.get_color() == 'b'
744+
assert artist.get_alpha() == 0.2
745+
props = dict(color='r', alpha=0.3)
746+
tool.set_props(**props)
747+
assert artist.get_color() == props['color']
748+
assert artist.get_alpha() == props['alpha']
749+
750+
for artist in tool._handles_artists:
751+
assert artist.get_color() == 'b'
752+
assert artist.get_alpha() == 0.5
753+
handle_props = dict(color='r', alpha=0.3)
754+
tool.set_handle_props(**handle_props)
755+
for artist in tool._handles_artists:
756+
assert artist.get_color() == 'r'
757+
assert artist.get_alpha() == 0.3
758+
759+
661760
@pytest.mark.parametrize(
662761
"horizOn, vertOn",
663762
[(True, True), (True, False), (False, True)],

lib/matplotlib/widgets.py

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

20142014
@property
20152015
def artists(self):
2016+
"""Tuple of the artists of the selector"""
20162017
return tuple(self._artists)
20172018

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

20192042
class SpanSelector(_SelectorWidget):
20202043
"""
@@ -2137,7 +2160,7 @@ def __init__(self, ax, onselect, direction, minspan=0, useblit=False,
21372160

21382161
if self._interactive:
21392162
self._edge_order = ['min', 'max']
2140-
self._setup_edge_handle(handle_props)
2163+
self._setup_edge_handles(handle_props)
21412164

21422165
self._active_handle = None
21432166

@@ -2187,7 +2210,7 @@ def new_axes(self, ax):
21872210
else:
21882211
self.add_artist(rect_artist)
21892212

2190-
def _setup_edge_handle(self, props):
2213+
def _setup_edge_handles(self, props):
21912214
# Define initial position using the axis bounds to keep the same bounds
21922215
if self.direction == 'horizontal':
21932216
positions = self.ax.get_xbound()
@@ -2267,7 +2290,7 @@ def direction(self, direction):
22672290
self._direction = direction
22682291
self.new_axes(self.ax)
22692292
if self._interactive:
2270-
self._setup_edge_handle(self._edge_handles._line_props)
2293+
self._setup_edge_handles(self._edge_handles._line_props)
22712294
else:
22722295
self._direction = direction
22732296

@@ -2409,6 +2432,10 @@ def extents(self, extents):
24092432
self.set_visible(self.visible)
24102433
self.update()
24112434

2435+
@property
2436+
def _handles_artists(self):
2437+
return self._edge_handles.artists
2438+
24122439

24132440
class ToolLineHandles:
24142441
"""
@@ -2545,7 +2572,6 @@ def __init__(self, ax, x, y, marker='o', marker_props=None, useblit=True):
25452572
**cbook.normalize_kwargs(marker_props, Line2D._alias_map)}
25462573
self._markers = Line2D(x, y, animated=useblit, **props)
25472574
self.ax.add_line(self._markers)
2548-
self.artist = self._markers
25492575

25502576
@property
25512577
def x(self):
@@ -2555,6 +2581,10 @@ def x(self):
25552581
def y(self):
25562582
return self._markers.get_ydata()
25572583

2584+
@property
2585+
def artists(self):
2586+
return (self._markers, )
2587+
25582588
def set_data(self, pts, y=None):
25592589
"""Set x and y positions of handles."""
25602590
if y is not None:
@@ -2765,9 +2795,7 @@ def __init__(self, ax, onselect, drawtype='box',
27652795

27662796
self._active_handle = None
27672797

2768-
self._artists.extend([self._center_handle.artist,
2769-
self._corner_handles.artist,
2770-
self._edge_handles.artist])
2798+
self._artists.extend(self._handles_artists)
27712799

27722800
self._extents_on_press = None
27732801

@@ -2783,6 +2811,11 @@ def __init__(self, ax, onselect, drawtype='box',
27832811
property(lambda self: self.grab_range,
27842812
lambda self, value: setattr(self, "grab_range", value)))
27852813

2814+
@property
2815+
def _handles_artists(self):
2816+
return (self._center_handle.artists + self._corner_handles.artists +
2817+
self._edge_handles.artists)
2818+
27862819
def _press(self, event):
27872820
"""Button press event handler."""
27882821
# make the drawn box/line visible get the click-coordinates,
@@ -3302,7 +3335,7 @@ def __init__(self, ax, onselect, useblit=False,
33023335
self._active_handle_idx = -1
33033336
self.grab_range = grab_range
33043337

3305-
self._artists = [line, self._polygon_handles.artist]
3338+
self._artists = [line] + list(self._handles_artists)
33063339
self.set_visible(True)
33073340

33083341
vertex_select_radius = _api.deprecated("3.5", name="vertex_select_radius",
@@ -3315,6 +3348,10 @@ def __init__(self, ax, onselect, useblit=False,
33153348
def _nverts(self):
33163349
return len(self._xs)
33173350

3351+
@property
3352+
def _handles_artists(self):
3353+
return self._polygon_handles.artists
3354+
33183355
def _remove_vertex(self, i):
33193356
"""Remove vertex with index i."""
33203357
if (self._nverts > 2 and

0 commit comments

Comments
 (0)