Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 6e60dea

Browse filesBrowse files
raamanaQuLogic
andcommitted
Add clear methods for check and radio buttons
Co-authored-by: Elliott Sales de Andrade <quantum.analyst@gmail.com>
1 parent efd66d4 commit 6e60dea
Copy full SHA for 6e60dea

File tree

Expand file treeCollapse file tree

2 files changed

+116
-9
lines changed
Filter options
Expand file treeCollapse file tree

2 files changed

+116
-9
lines changed

‎lib/matplotlib/tests/test_widgets.py

Copy file name to clipboardExpand all lines: lib/matplotlib/tests/test_widgets.py
+24-1Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -999,10 +999,23 @@ def test_lasso_selector_set_props(ax):
999999

10001000

10011001
def test_CheckButtons(ax):
1002-
check = widgets.CheckButtons(ax, ('a', 'b', 'c'), (True, False, True))
1002+
labels = ('a', 'b', 'c')
1003+
check = widgets.CheckButtons(ax, labels, (True, False, True))
10031004
assert check.get_status() == [True, False, True]
10041005
check.set_active(0)
10051006
assert check.get_status() == [False, False, True]
1007+
assert check.get_checked_labels() == ['c']
1008+
check.clear()
1009+
assert not any(check.get_status())
1010+
assert len(check.get_checked_labels()) == 0
1011+
1012+
for invalid_index in [-1, len(labels), len(labels)+5]:
1013+
with pytest.raises(ValueError):
1014+
check.set_active(index=invalid_index)
1015+
1016+
for invalid_value in ['invalid', -1]:
1017+
with pytest.raises(TypeError):
1018+
check.set_active(1, state=invalid_value)
10061019

10071020
cid = check.on_clicked(lambda: None)
10081021
check.disconnect(cid)
@@ -1040,6 +1053,16 @@ def test_TextBox(ax, toolbar):
10401053
assert text_change_event.call_count == 3
10411054

10421055

1056+
def test_RadioButtons(ax):
1057+
radio = widgets.RadioButtons(ax, ('Radio 1', 'Radio 2', 'Radio 3'))
1058+
radio.set_active(1)
1059+
assert radio.value_selected == 'Radio 2'
1060+
assert radio.index_selected == 1
1061+
radio.clear()
1062+
assert radio.value_selected is None
1063+
assert radio.index_selected is None
1064+
1065+
10431066
@image_comparison(['check_radio_buttons.png'], style='mpl20', remove_text=True)
10441067
def test_check_radio_buttons_image():
10451068
ax = get_ax()

‎lib/matplotlib/widgets.py

Copy file name to clipboardExpand all lines: lib/matplotlib/widgets.py
+92-8Lines changed: 92 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,7 +1196,7 @@ def set_check_props(self, props):
11961196
# If new colours are supplied, then we must re-apply the status.
11971197
self._init_status(actives)
11981198

1199-
def set_active(self, index):
1199+
def set_active(self, index, state=None):
12001200
"""
12011201
Toggle (activate or deactivate) a check button by index.
12021202
@@ -1207,22 +1207,27 @@ def set_active(self, index):
12071207
index : int
12081208
Index of the check button to toggle.
12091209
1210+
state : bool, optional
1211+
Sets the target state of the button. If a boolean value, set the
1212+
state explicitly. If no value is provided, the state is toggled.
1213+
12101214
Raises
12111215
------
12121216
ValueError
12131217
If *index* is invalid.
1218+
TypeError
1219+
If *state* is not boolean.
12141220
"""
12151221
if index not in range(len(self.labels)):
12161222
raise ValueError(f'Invalid CheckButton index: {index}')
1223+
_api.check_isinstance((bool, None), state=state)
12171224

12181225
invisible = colors.to_rgba('none')
12191226

12201227
facecolors = self._checks.get_facecolor()
1221-
facecolors[index] = (
1222-
self._active_check_colors[index]
1223-
if colors.same_color(facecolors[index], invisible)
1224-
else invisible
1225-
)
1228+
if state is None:
1229+
state = colors.same_color(facecolors[index], invisible)
1230+
facecolors[index] = self._active_check_colors[index] if state else invisible
12261231
self._checks.set_facecolor(facecolors)
12271232

12281233
if hasattr(self, "_lines"):
@@ -1262,18 +1267,55 @@ def _init_status(self, actives):
12621267
[ec if active else "none"
12631268
for ec, active in zip(self._active_check_colors, actives)])
12641269

1270+
def clear(self):
1271+
"""Clear all checkboxes."""
1272+
1273+
self._checks.set_facecolor(['none'] * len(self._active_check_colors))
1274+
1275+
if hasattr(self, '_lines'):
1276+
for l1, l2 in self._lines:
1277+
l1.set_visible(False)
1278+
l2.set_visible(False)
1279+
1280+
if self.drawon:
1281+
self.canvas.draw()
1282+
1283+
if self.eventson:
1284+
# Call with no label, as all checkboxes are being cleared.
1285+
self._observers.process('clicked', None)
1286+
12651287
def get_status(self):
12661288
"""
12671289
Return a list of the status (True/False) of all of the check buttons.
12681290
"""
12691291
return [not colors.same_color(color, colors.to_rgba("none"))
12701292
for color in self._checks.get_facecolors()]
12711293

1294+
def get_checked_labels(self):
1295+
"""Return a list of labels currently checked by user."""
1296+
1297+
return [l.get_text() for l, box_checked in
1298+
zip(self.labels, self.get_status())
1299+
if box_checked]
1300+
12721301
def on_clicked(self, func):
12731302
"""
12741303
Connect the callback function *func* to button click events.
12751304
1276-
Returns a connection id, which can be used to disconnect the callback.
1305+
Parameters
1306+
----------
1307+
func : callable
1308+
When the button is clicked, call *func* with button label.
1309+
When all buttons are cleared, call *func* with None.
1310+
The callback func must have the signature::
1311+
1312+
def func(label: str | None) -> Any
1313+
1314+
Return values may exist, but are ignored.
1315+
1316+
Returns
1317+
-------
1318+
A connection id, which can be used to disconnect the callback.
12771319
"""
12781320
return self._observers.connect('clicked', lambda text: func(text))
12791321

@@ -1618,6 +1660,8 @@ class RadioButtons(AxesWidget):
16181660
The buttons.
16191661
value_selected : str
16201662
The label text of the currently selected button.
1663+
index_selected : int
1664+
The index of the selected button.
16211665
"""
16221666

16231667
def __init__(self, ax, labels, active=0, activecolor=None, *,
@@ -1676,6 +1720,7 @@ def __init__(self, ax, labels, active=0, activecolor=None, *,
16761720

16771721
self._activecolor = activecolor
16781722
self.value_selected = labels[active]
1723+
self.index_selected = active
16791724

16801725
ax.set_xticks([])
16811726
ax.set_yticks([])
@@ -1814,10 +1859,21 @@ def set_active(self, index):
18141859
Select button with number *index*.
18151860
18161861
Callbacks will be triggered if :attr:`eventson` is True.
1862+
1863+
Parameters
1864+
----------
1865+
index : int
1866+
The index of the button to activate.
1867+
1868+
Raises
1869+
------
1870+
ValueError
1871+
If the index is invalid.
18171872
"""
18181873
if index not in range(len(self.labels)):
18191874
raise ValueError(f'Invalid RadioButton index: {index}')
18201875
self.value_selected = self.labels[index].get_text()
1876+
self.index_selected = index
18211877
button_facecolors = self._buttons.get_facecolor()
18221878
button_facecolors[:] = colors.to_rgba("none")
18231879
button_facecolors[index] = colors.to_rgba(self._active_colors[index])
@@ -1842,11 +1898,39 @@ def set_active(self, index):
18421898
if self.eventson:
18431899
self._observers.process('clicked', self.labels[index].get_text())
18441900

1901+
def clear(self):
1902+
"""Deactivate any previously activated button."""
1903+
if self.index_selected is not None:
1904+
button_facecolors = self._buttons.get_facecolor()
1905+
button_facecolors[:] = colors.to_rgba('none')
1906+
self._buttons.set_facecolor(button_facecolors)
1907+
if hasattr(self, '_circles'): # Remove once circles is removed.
1908+
self._circles[self.index_selected].set_facecolor('none')
1909+
self.value_selected = None
1910+
self.index_selected = None
1911+
1912+
# calling it with no label, as all buttons are being cleared
1913+
if self.eventson:
1914+
self._observers.process('clicked', None)
1915+
18451916
def on_clicked(self, func):
18461917
"""
18471918
Connect the callback function *func* to button click events.
18481919
1849-
Returns a connection id, which can be used to disconnect the callback.
1920+
Parameters
1921+
----------
1922+
func : callable
1923+
When the button is clicked, call *func* with button label.
1924+
When all buttons are cleared, call *func* with None.
1925+
The callback func must have the signature::
1926+
1927+
def func(label: str | None) -> Any
1928+
1929+
Return values may exist, but are ignored.
1930+
1931+
Returns
1932+
-------
1933+
A connection id, which can be used to disconnect the callback.
18501934
"""
18511935
return self._observers.connect('clicked', func)
18521936

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.