Matplotlib fill_between使用legend picking图例拾取无响应问题
问题根因
- 你的判断方向完全正确:
ax.fill_between()返回的是PolyCollection类型的多边形填充对象,不属于Line2D线对象类型,原有逻辑中调用leg.get_lines()只能获取到图例中对应线图的条目,完全拿不到填充区域对应的图例项,后续拾取绑定逻辑根本没有覆盖到填充区的图例,点击自然无响应。 - 该场景下不会抛出报错的原因是:
zip()函数会按最短序列长度截断遍历,当leg.get_lines()返回空列表(全是填充图时没有线图图例项),循环会直接跳过,没有任何异常触发。 - 填充区域对应的图例项是色块补丁(Patch类型),需要通过
leg.get_patches()方法才能获取到。
修正方案
只需要修改图例映射和事件绑定部分的代码即可,填充对象的 get_visible()/set_visible()/set_alpha() 接口和线对象完全一致,不需要调整显隐控制逻辑:
- 不再单独获取图例线集合,改为获取图例的补丁集合和填充对象做映射,给每个图例补丁开启拾取功能
- 回调函数增加非目标图例项的判断,避免其他拾取事件误触发逻辑
修正后的核心代码段(替换原代码中从lined = {}到事件绑定前的部分即可):
art_map = {} # 填充图对应图例为色块补丁,通过get_patches获取 for leg_patch, orig_fill in zip(leg.get_patches(), lines): leg_patch.set_picker(True) art_map[leg_patch] = orig_fill def on_pick(event): leg_art = event.artist if leg_art not in art_map: return orig_art = art_map[leg_art] visible = not orig_art.get_visible() orig_art.set_visible(visible) leg_art.set_alpha(1.0 if visible else 0.2) fig.canvas.draw() fig.canvas.mpl_connect('pick_event', on_pick)
扩展说明
如果后续图表中同时存在plot绘制的线和fill_between绘制的填充区,只需要把两类图例项合并后遍历即可,注意保证存储原始绘图对象的列表顺序和绘图顺序完全一致,避免映射错位:
# 混合线图和填充图时的映射写法 all_leg_artists = leg.get_lines() + leg.get_patches() for leg_art, orig_art in zip(all_leg_artists, all_original_artists_list): leg_art.set_picker(True) art_map[leg_art] = orig_art
内容的提问来源于stack exchange,提问作者one_tick_pony
相关产品推荐
相关产品推荐

