Matplotlib 连续检查按钮

hhp*_*ram 2 python matplotlib python-3.x

找不到有关如何将 matplotlib 中的复选框“框”格式化为行与列格式的任何信息。我发现我可以移动实际的复选框和标签(get_position在文本对象和set_xy矩形对象上使用),但这似乎不是最好的方法,因为我单独移动它们,而且它们似乎不是使用相同的坐标系。

有没有更简单的方法将我的复选按钮从列变成行?

Imp*_*est 5

没有简单的方法可以使复选框出现在行而不是列中。原因是它们是根据轴坐标进行硬编码的。当然,你可以移动这些零碎的东西,但这听起来相当麻烦。

另一种选择是对CheckButtons类进行子类化并实现您自己的布局。现在,在这样做时,需要考虑很多因素,例如标签和复选框之间有多少空间等。

另一方面,实际上有一个很好的 matplotlib 项目,它可以转动所有关于标签间距、填充等的旋钮,并且可以与行和列一起使用:图例。

现在我在想为什么不将复选框生成为可点击的图例。这就是下面的代码的作用。它将CheckButtons图例子类化并创建到其轴中。该图例将框作为手柄,将标签作为图例标签。好处是,现在您可以使用通常图例允许的所有工具来根据您的喜好布局复选按钮:fontsize, markerfirst, frameon, fancybox, shadow, framealpha, facecolor, edgecolor, mode, bbox_transform, title, borderpad, labelspacing, handlelength, handletextpad, borderaxespad, columnspacing

这里最重要的一项是sure n_col,您可以将其设置为您想要的列数。

我从 matplotlib 页面获取了CheckButtons示例,并在其上使用了这个自定义 Checkbuttons 类。

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import CheckButtons,AxesWidget

class PremiumCheckButtons(CheckButtons,AxesWidget):
    def __init__(self, ax, labels, actives, linecolor="k", showedge=True, **kw):
        AxesWidget.__init__(self, ax)

        ax.set_xticks([])
        ax.set_yticks([])
        ax.set_navigate(False)
        if not showedge:
            ax.axis("off")
        linekw = {'solid_capstyle': 'butt', "color" : linecolor}
        class Handler(object):
            def legend_artist(self, legend, orig_handle, fontsize, handlebox):
                x0, y0 = handlebox.xdescent, handlebox.ydescent
                height = handlebox.height
                self.line1 = plt.Line2D([x0,x0+height],[y0,y0+height], **linekw)
                self.line2 = plt.Line2D([x0,x0+height],[y0+height,y0], **linekw)
                self.rect = plt.Rectangle((x0,y0),height, height, 
                                          edgecolor="k", fill=False)
                handlebox.add_artist(self.rect)
                handlebox.add_artist(self.line1)
                handlebox.add_artist(self.line2)
                return [self.line1, self.line2, self.rect]

        self.box = ax.legend(handles = [object() for i in labels ], 
                             labels = labels,
                             handler_map={object: Handler()}, **kw)

        self.lines = [(h[0],h[1]) for h in self.box.legendHandles]
        self.rectangles = [h[2] for h in self.box.legendHandles]
        self.labels = self.box.texts

        for i,(l1,l2) in enumerate(self.lines):
            l1.set_visible(actives[i])
            l2.set_visible(actives[i])

        self.connect_event('button_press_event', self._clicked)

        self.cnt = 0
        self.observers = {}


t = np.arange(0.0, 2.0, 0.01)
s0 = np.sin(2*np.pi*t)
s1 = np.sin(4*np.pi*t)
s2 = np.sin(6*np.pi*t)

fig, (rax,ax) = plt.subplots(nrows=2, gridspec_kw=dict(height_ratios = [0.1,1]) )
l0, = ax.plot(t, s0, visible=False, lw=2)
l1, = ax.plot(t, s1, lw=2)
l2, = ax.plot(t, s2, lw=2)
plt.subplots_adjust(left=0.2)

check = PremiumCheckButtons(rax, ('2 Hz', '4 Hz', '6 Hz'), (False, True, True),
                           showedge = False, ncol=3)


def func(label):
    if label == '2 Hz':
        l0.set_visible(not l0.get_visible())
    elif label == '4 Hz':
        l1.set_visible(not l1.get_visible())
    elif label == '6 Hz':
        l2.set_visible(not l2.get_visible())
    fig.canvas.draw_idle()
check.on_clicked(func)

plt.show()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

除了所有legend参数之外,上面的PremiumCheckButtons类还使用参数来设置复选框linecolor的颜色(默认为黑色)和。可用于显示“图例”所在的轴的框架,并且可以打开以查看该轴以进行调试。例如,您需要确保完整的图例实际上位于轴内,以便按钮可单击。xshowedgeshowedge