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 dcd02b2

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 fff2a79 commit dcd02b2
Copy full SHA for dcd02b2

File tree

Expand file treeCollapse file tree

3 files changed

+112
-12
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+112
-12
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
@@ -1006,10 +1006,23 @@ def test_lasso_selector_set_props(ax):
10061006

10071007

10081008
def test_CheckButtons(ax):
1009-
check = widgets.CheckButtons(ax, ('a', 'b', 'c'), (True, False, True))
1009+
labels = ('a', 'b', 'c')
1010+
check = widgets.CheckButtons(ax, labels, (True, False, True))
10101011
assert check.get_status() == [True, False, True]
10111012
check.set_active(0)
10121013
assert check.get_status() == [False, False, True]
1014+
assert check.get_checked_labels() == ['c']
1015+
check.clear()
1016+
assert not any(check.get_status())
1017+
assert len(check.get_checked_labels()) == 0
1018+
1019+
for invalid_index in [-1, len(labels), len(labels)+5]:
1020+
with pytest.raises(ValueError):
1021+
check.set_active(index=invalid_index)
1022+
1023+
for invalid_value in ['invalid', -1]:
1024+
with pytest.raises(TypeError):
1025+
check.set_active(1, state=invalid_value)
10131026

10141027
cid = check.on_clicked(lambda: None)
10151028
check.disconnect(cid)
@@ -1047,6 +1060,16 @@ def test_TextBox(ax, toolbar):
10471060
assert text_change_event.call_count == 3
10481061

10491062

1063+
def test_RadioButtons(ax):
1064+
radio = widgets.RadioButtons(ax, ('Radio 1', 'Radio 2', 'Radio 3'))
1065+
radio.set_active(1)
1066+
assert radio.value_selected == 'Radio 2'
1067+
assert radio.index_selected == 1
1068+
radio.clear()
1069+
assert radio.value_selected is None
1070+
assert radio.index_selected is None
1071+
1072+
10501073
@image_comparison(['check_radio_buttons.png'], style='mpl20', remove_text=True)
10511074
def test_check_radio_buttons_image():
10521075
ax = get_ax()

‎lib/matplotlib/widgets.py

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

1201-
def set_active(self, index):
1201+
def set_active(self, index, state=None):
12021202
"""
12031203
Toggle (activate or deactivate) a check button by index.
12041204
@@ -1209,22 +1209,27 @@ def set_active(self, index):
12091209
index : int
12101210
Index of the check button to toggle.
12111211
1212+
state : bool, optional
1213+
Sets the target state of the button. If a boolean value, set the
1214+
state explicitly. If no value is provided, the state is toggled.
1215+
12121216
Raises
12131217
------
12141218
ValueError
12151219
If *index* is invalid.
1220+
TypeError
1221+
If *state* is not boolean.
12161222
"""
12171223
if index not in range(len(self.labels)):
12181224
raise ValueError(f'Invalid CheckButton index: {index}')
1225+
_api.check_isinstance((bool, None), state=state)
12191226

12201227
invisible = colors.to_rgba('none')
12211228

12221229
facecolors = self._checks.get_facecolor()
1223-
facecolors[index] = (
1224-
self._active_check_colors[index]
1225-
if colors.same_color(facecolors[index], invisible)
1226-
else invisible
1227-
)
1230+
if state is None:
1231+
state = colors.same_color(facecolors[index], invisible)
1232+
facecolors[index] = self._active_check_colors[index] if state else invisible
12281233
self._checks.set_facecolor(facecolors)
12291234

12301235
if hasattr(self, "_lines"):
@@ -1264,18 +1269,55 @@ def _init_status(self, actives):
12641269
[ec if active else "none"
12651270
for ec, active in zip(self._active_check_colors, actives)])
12661271

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

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

@@ -1620,6 +1662,8 @@ class RadioButtons(AxesWidget):
16201662
The buttons.
16211663
value_selected : str
16221664
The label text of the currently selected button.
1665+
index_selected : int
1666+
The index of the selected button.
16231667
"""
16241668

16251669
def __init__(self, ax, labels, active=0, activecolor=None, *,
@@ -1677,7 +1721,9 @@ def __init__(self, ax, labels, active=0, activecolor=None, *,
16771721
activecolor = 'blue' # Default.
16781722

16791723
self._activecolor = activecolor
1724+
self._initial_active = active
16801725
self.value_selected = labels[active]
1726+
self.index_selected = active
16811727

16821728
ax.set_xticks([])
16831729
ax.set_yticks([])
@@ -1816,10 +1862,21 @@ def set_active(self, index):
18161862
Select button with number *index*.
18171863
18181864
Callbacks will be triggered if :attr:`eventson` is True.
1865+
1866+
Parameters
1867+
----------
1868+
index : int
1869+
The index of the button to activate.
1870+
1871+
Raises
1872+
------
1873+
ValueError
1874+
If the index is invalid.
18191875
"""
18201876
if index not in range(len(self.labels)):
18211877
raise ValueError(f'Invalid RadioButton index: {index}')
18221878
self.value_selected = self.labels[index].get_text()
1879+
self.index_selected = index
18231880
button_facecolors = self._buttons.get_facecolor()
18241881
button_facecolors[:] = colors.to_rgba("none")
18251882
button_facecolors[index] = colors.to_rgba(self._active_colors[index])
@@ -1844,11 +1901,28 @@ def set_active(self, index):
18441901
if self.eventson:
18451902
self._observers.process('clicked', self.labels[index].get_text())
18461903

1904+
def clear(self):
1905+
"""Reset active button."""
1906+
self.set_active(self._initial_active)
1907+
18471908
def on_clicked(self, func):
18481909
"""
18491910
Connect the callback function *func* to button click events.
18501911
1851-
Returns a connection id, which can be used to disconnect the callback.
1912+
Parameters
1913+
----------
1914+
func : callable
1915+
When the button is clicked, call *func* with button label.
1916+
When all buttons are cleared, call *func* with None.
1917+
The callback func must have the signature::
1918+
1919+
def func(label: str | None) -> Any
1920+
1921+
Return values may exist, but are ignored.
1922+
1923+
Returns
1924+
-------
1925+
A connection id, which can be used to disconnect the callback.
18521926
"""
18531927
return self._observers.connect('clicked', func)
18541928

‎lib/matplotlib/widgets.pyi

Copy file name to clipboardExpand all lines: lib/matplotlib/widgets.pyi
+6-3Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,9 +159,11 @@ class CheckButtons(AxesWidget):
159159
def set_label_props(self, props: dict[str, Any]) -> None: ...
160160
def set_frame_props(self, props: dict[str, Any]) -> None: ...
161161
def set_check_props(self, props: dict[str, Any]) -> None: ...
162-
def set_active(self, index: int) -> None: ...
162+
def set_active(self, index: int, state: bool | None = ...) -> None: ... # type: ignore[override]
163+
def clear(self) -> None: ...
163164
def get_status(self) -> list[bool]: ...
164-
def on_clicked(self, func: Callable[[str], Any]) -> int: ...
165+
def get_checked_labels(self) -> list[str]: ...
166+
def on_clicked(self, func: Callable[[str | None], Any]) -> int: ...
165167
def disconnect(self, cid: int) -> None: ...
166168
@property
167169
def lines(self) -> list[tuple[Line2D, Line2D]]: ...
@@ -213,7 +215,8 @@ class RadioButtons(AxesWidget):
213215
def set_label_props(self, props: dict[str, Any]) -> None: ...
214216
def set_radio_props(self, props: dict[str, Any]) -> None: ...
215217
def set_active(self, index: int) -> None: ...
216-
def on_clicked(self, func: Callable[[str], Any]) -> int: ...
218+
def clear(self) -> None: ...
219+
def on_clicked(self, func: Callable[[str | None], Any]) -> int: ...
217220
def disconnect(self, cid: int) -> None: ...
218221
@property
219222
def circles(self) -> list[Circle]: ...

0 commit comments

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