pythonmatplotlibmatplotlib-widget

Displaying Radio buttons horizontally in matplotlib


I am using the matplotlib.widgets to create radio buttons in my widgets, the buttons coming are stacked vertically, I would like them to be stacked horizontally.

MVCE:

import matplotlib.pyplot as plt
from matplotlib.widgets import RadioButtons
plt.subplots_adjust(left=0.2)
rax = plt.axes([0.5,0.05,0.1,0.1])
radio =  RadioButtons(rax ,['1','2','3'], active=0, activecolor='blue' )
plt.show()

As you can see with this example you can get the radio buttons like this Plot with radio buttons stacked vertically,

I am wondering is there a way to stack these radio buttons horizontally.


Solution

  • There is currently an attempt to introduce an orientation argument to RadioButtons in PR #13374; this has not yet been finalized.

    As I had commented in this PR, an alternative option would be to use a scatter plot for the buttons. The following shows how I would imagine this implementation. There are two main enhancements compared to the usual buttons:

    This is achieved by creating a legend internally, which has all the required options readily available. Any valid arguments to Legend can be used for the Buttons as well.

    import matplotlib.pyplot as plt
    from matplotlib.widgets import AxesWidget, RadioButtons
    
    class MyRadioButtons(RadioButtons):
    
        def __init__(self, ax, labels, active=0, activecolor='blue', size=49,
                     orientation="vertical", **kwargs):
            """
            Add radio buttons to an `~.axes.Axes`.
            Parameters
            ----------
            ax : `~matplotlib.axes.Axes`
                The axes to add the buttons to.
            labels : list of str
                The button labels.
            active : int
                The index of the initially selected button.
            activecolor : color
                The color of the selected button.
            size : float
                Size of the radio buttons
            orientation : str
                The orientation of the buttons: 'vertical' (default), or 'horizontal'.
            Further parameters are passed on to `Legend`.
            """
            AxesWidget.__init__(self, ax)
            self.activecolor = activecolor
            axcolor = ax.get_facecolor()
            self.value_selected = None
    
            ax.set_xticks([])
            ax.set_yticks([])
            ax.set_navigate(False)
    
            circles = []
            for i, label in enumerate(labels):
                if i == active:
                    self.value_selected = label
                    facecolor = activecolor
                else:
                    facecolor = axcolor
                p = ax.scatter([],[], s=size, marker="o", edgecolor='black',
                               facecolor=facecolor)
                circles.append(p)
            if orientation == "horizontal":
                kwargs.update(ncol=len(labels), mode="expand")
            kwargs.setdefault("frameon", False)    
            self.box = ax.legend(circles, labels, loc="center", **kwargs)
            self.labels = self.box.texts
            self.circles = self.box.legendHandles
            for c in self.circles:
                c.set_picker(5)
            self.cnt = 0
            self.observers = {}
    
            self.connect_event('pick_event', self._clicked)
    
    
        def _clicked(self, event):
            if (self.ignore(event) or event.mouseevent.button != 1 or
                event.mouseevent.inaxes != self.ax):
                return
            if event.artist in self.circles:
                self.set_active(self.circles.index(event.artist))
    

    Use it as

    plt.subplots_adjust(left=0.2)
    rax = plt.axes([0.5,0.05,0.4,0.07])
    radio =  MyRadioButtons(rax ,['1','2','3'], active=0, activecolor='crimson',
                            orientation="horizontal")
    
    plt.show()
    

    enter image description here

    Or

    rax = plt.axes([0.2,0.5,0.25,0.1])
    radio =  MyRadioButtons(rax ,["AA", "BB", "CC", "DD"], ncol=2)
    

    enter image description here