Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit dcd02b2

Browse files
raamanaQuLogic
andcommitted
Add clear methods for check and radio buttons
Co-authored-by: Elliott Sales de Andrade <[email protected]>
1 parent fff2a79 commit dcd02b2

File tree

3 files changed

+112
-12
lines changed

3 files changed

+112
-12
lines changed

lib/matplotlib/tests/test_widgets.py

Lines 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

Lines 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

Lines 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)