Skip to content

Commit 8ea3641

Browse files
mromanieQuLogic
authored andcommitted
Add possibility to have horizontal RadioButtons
A new optional keyword argument 'orientation' is introduced to control it. The new parameter defaults to 'vertical' for backwards compatibility.
1 parent 6378d48 commit 8ea3641

File tree

3 files changed

+55
-8
lines changed

3 files changed

+55
-8
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
RadioButtons widget may now be laid out horizontally
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
4+
The `.RadioButtons` widget's primary layout direction may now be specified with
5+
the *orientation* keyword argument:
6+
7+
.. plot::
8+
:include-source:
9+
10+
import matplotlib.pyplot as plt
11+
from matplotlib.widgets import RadioButtons
12+
13+
fig = plt.figure(figsize=(4, 2))
14+
15+
# Default orientation is vertical:
16+
rbv = RadioButtons(fig.add_axes((0.05, 0.6, 0.2, 0.35)),
17+
('Radio 1', 'Radio 2', 'Radio 3'),
18+
orientation='vertical')
19+
20+
# Alternatively, a horizontal orientation may be used:
21+
rbh = RadioButtons(fig.add_axes((0.3, 0.6, 0.6, 0.35)),
22+
('Radio 1', 'Radio 2', 'Radio 3'),
23+
orientation='horizontal')

lib/matplotlib/tests/test_widgets.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -1096,8 +1096,10 @@ def test_TextBox(ax, toolbar):
10961096
assert text_change_event.call_count == 3
10971097

10981098

1099-
def test_RadioButtons(ax):
1100-
radio = widgets.RadioButtons(ax, ('Radio 1', 'Radio 2', 'Radio 3'))
1099+
@pytest.mark.parametrize('orientation', ['vertical', 'horizontal'])
1100+
def test_RadioButtons(ax, orientation):
1101+
radio = widgets.RadioButtons(ax, ('Radio 1', 'Radio 2', 'Radio 3'),
1102+
orientation=orientation)
11011103
radio.set_active(1)
11021104
assert radio.value_selected == 'Radio 2'
11031105
assert radio.index_selected == 1

lib/matplotlib/widgets.py

+28-6
Original file line numberDiff line numberDiff line change
@@ -1580,7 +1580,8 @@ class RadioButtons(AxesWidget):
15801580
"""
15811581

15821582
def __init__(self, ax, labels, active=0, activecolor=None, *,
1583-
useblit=True, label_props=None, radio_props=None):
1583+
useblit=True, label_props=None, radio_props=None,
1584+
orientation='vertical'):
15841585
"""
15851586
Add radio buttons to an `~.axes.Axes`.
15861587
@@ -1616,9 +1617,15 @@ def __init__(self, ax, labels, active=0, activecolor=None, *,
16161617
button.
16171618
16181619
.. versionadded:: 3.7
1620+
orientation : {'vertical', 'horizontal'}
1621+
The orientation of the buttons: 'vertical' places buttons from top
1622+
to bottom, 'horizontal' places buttons from left to right.
1623+
1624+
.. versionadded:: 3.9
16191625
"""
16201626
super().__init__(ax)
16211627

1628+
_api.check_in_list(['vertical', 'horizontal'], orientation=orientation)
16221629
_api.check_isinstance((dict, None), label_props=label_props,
16231630
radio_props=radio_props)
16241631

@@ -1642,17 +1649,32 @@ def __init__(self, ax, labels, active=0, activecolor=None, *,
16421649
ax.set_yticks([])
16431650
ax.set_navigate(False)
16441651

1645-
ys = np.linspace(1, 0, len(labels) + 2)[1:-1]
1652+
if orientation == 'vertical':
1653+
# Place buttons from top to bottom with buttons at (0.15, y) and labels
1654+
# at (0.25, y), where y is evenly spaced within the Axes.
1655+
button_ys = label_ys = np.linspace(1, 0, len(labels) + 2)[1:-1]
1656+
button_xs = np.full_like(button_ys, 0.15)
1657+
label_xs = np.full_like(label_ys, 0.25)
1658+
label_ha = 'left'
1659+
label_va = 'center'
1660+
else:
1661+
# Place buttons from left to right with buttons at (x, 0.15) and labels
1662+
# at (x, 0.25), where x is evenly spaced within the Axes.
1663+
button_xs = label_xs = np.linspace(0, 1, len(labels) + 2)[1:-1]
1664+
button_ys = np.full_like(button_xs, 0.15)
1665+
label_ys = np.full_like(label_xs, 0.25)
1666+
label_ha = 'center'
1667+
label_va = 'bottom'
16461668

16471669
self._useblit = useblit and self.canvas.supports_blit
16481670
self._background = None
16491671

16501672
label_props = _expand_text_props(label_props)
16511673
self.labels = [
1652-
ax.text(0.25, y, label, transform=ax.transAxes,
1653-
horizontalalignment="left", verticalalignment="center",
1674+
ax.text(x, y, label, transform=ax.transAxes,
1675+
horizontalalignment=label_ha, verticalalignment=label_va,
16541676
**props)
1655-
for y, label, props in zip(ys, labels, label_props)]
1677+
for x, y, label, props in zip(label_xs, label_ys, labels, label_props)]
16561678
text_size = np.array([text.get_fontsize() for text in self.labels]) / 2
16571679

16581680
radio_props = {
@@ -1665,7 +1687,7 @@ def __init__(self, ax, labels, active=0, activecolor=None, *,
16651687
radio_props.setdefault('edgecolor', radio_props.get('color', 'black'))
16661688
radio_props.setdefault('facecolor',
16671689
radio_props.pop('color', activecolor))
1668-
self._buttons = ax.scatter([.15] * len(ys), ys, **radio_props)
1690+
self._buttons = ax.scatter(button_xs, button_ys, **radio_props)
16691691
# The user may have passed custom colours in radio_props, so we need to
16701692
# create the radios, and modify the visibility after getting whatever
16711693
# the user set.

0 commit comments

Comments
 (0)