如何为柱状图使用Pyplot.Widgets.CheckButtons?解决属性错误
问题说明
使用Matplotlib的CheckButtons组件控制柱状图显示/隐藏时,出现错误:
AttributeError: 'BarContainer' object has no attribute 'get_visible'
将官方CheckButtons示例中的plot替换为bar即可复现该问题。
错误原因
ax.bar()返回的是BarContainer对象——它是存储所有柱状图矩形(Patch元素)的容器,而非单个可直接控制可见性的Artist对象。而plot()返回的Line2D对象自带get_visible()和set_visible()方法,这就是折线图正常、柱状图报错的核心差异。
解决办法
有两种简洁的处理方式:
- 直接遍历BarContainer内的所有Patch元素,统一设置它们的可见性
- 给BarContainer对象添加自定义的
get_visible()和set_visible()方法,封装对内部元素的操作
方案一:给BarContainer添加自定义方法(贴近原示例写法)
import numpy as np import matplotlib.pyplot as plt from matplotlib.widgets import CheckButtons 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, ax = plt.subplots() # 绘制柱状图获取BarContainer l0 = ax.bar(t, s0, visible=False, lw=2, color='black', label='1 Hz') l1 = ax.bar(t, s1, lw=2, color='red', label='2 Hz') l2 = ax.bar(t, s2, lw=2, color='green', label='3 Hz') fig.subplots_adjust(left=0.2) # 给BarContainer添加可见性控制方法 def add_visibility_methods(container): def get_visible(): # 取第一个patch的状态代表整体(假设所有柱状元素状态一致) return container.patches[0].get_visible() if container.patches else False def set_visible(visible): for patch in container.patches: patch.set_visible(visible) container.get_visible = get_visible container.set_visible = set_visible # 为每个BarContainer注入方法 for container in [l0, l1, l2]: add_visibility_methods(container) lines_by_label = {l.get_label(): l for l in [l0, l1, l2]} line_colors = [l.get_facecolor()[0] for l in lines_by_label.values()] # 创建CheckButtons组件 rax = fig.add_axes([0.05, 0.4, 0.1, 0.15]) check = CheckButtons( ax=rax, labels=lines_by_label.keys(), actives=[l.get_visible() for l in lines_by_label.values()], label_props={'color': line_colors}, frame_props={'edgecolor': line_colors}, check_props={'facecolor': line_colors}, ) def callback(label): ln = lines_by_label[label] ln.set_visible(not ln.get_visible()) ln.figure.canvas.draw_idle() check.on_clicked(callback) plt.show()
方案二:直接在回调中操作Patch元素(无需修改容器)
如果不想给容器添加方法,可以直接在回调里遍历柱状元素:
# 替换原回调函数即可 def callback(label): ln = lines_by_label[label] current_visible = ln.patches[0].get_visible() if ln.patches else False for patch in ln.patches: patch.set_visible(not current_visible) ln.figure.canvas.draw_idle()
内容的提问来源于stack exchange,提问作者Galedon
相关产品推荐
相关产品推荐

