Python matplotlib errorbar legend picking

在 matplotlib 中,当我们使用 errorbar() 函数绘制误差线图时,可能会遇到以下问题:

  • 无法通过点击图例中的误差线或数据点来切换它们的可见性。
  • plt.legend() 生成的图例对象不包含创建图例时所使用的艺术家(artist)的信息。

例如,我们可以使用以下代码绘制一个误差线图:

import numpy as np
import matplotlib.pyplot as plt

fig, ax = plt.subplots()
x = np.linspace(0,10,100)
y = np.sin(x) + np.random.rand(100)
yerr = np.random.rand(100)

erbpl1 = ax.errorbar(x, y, yerr=yerr, fmt='o', label='A')
erbpl2 = ax.errorbar(x, 0.02*y, yerr=yerr, fmt='o', label='B')

leg = ax.legend()

从这里,我们似乎无法使用 leg 对象来访问图例中的艺术家。通常,我们可以使用 get_lines() 方法来获取图例中使用的 Line2D 对象,但对于误差线图,leg.get_lines() 返回一个空列表。这是因为 plt.errorbar() 返回一个 matplotlib.container.ErrorbarContainer 对象,它包含数据点、误差线端点和误差线。我们期望图例也有一个类似的数据容器,但我们看不到它。

2、解决方案

为了解决这个问题,我们可以使用以下 workaround:

  1. 定义一个新的 HandlerErrorbar 子类,它会重新排序艺术家列表,以便将标记作为第一个艺术家添加到图例。
  2. 将我们定义的 HandlerErrorbar 子类作为参数传递给 ax.legend() 函数。
  3. 将图例中的艺术家与原始图中的艺术家相关联。
  4. 定义一个拾取事件处理函数,当用户点击图例中的艺术家时,该函数将切换原始图中相应艺术家的可见性。

以下是如何实现这个解决方案的代码示例:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.legend_handler

from matplotlib.container import ErrorbarContainer

class re_order_errorbarHandler(matplotlib.legend_handler.HandlerErrorbar):
    """
    Sub-class the standard error-bar handler 
    """
    def create_artists(self, *args, **kwargs):
        #  call the parent class function
        a_list = matplotlib.legend_handler.HandlerErrorbar.create_artists(self, *args, **kwargs)
        # re-order the artist list, only the first artist is added to the
        # legend artist list, this is the one that corresponds to the markers
        a_list = a_list[-1:] + a_list[:-1]
        return a_list

my_handler_map = {ErrorbarContainer: re_order_errorbarHandler(numpoints=2)}

fig, ax = plt.subplots()
x = np.linspace(0,10,100)
y = np.sin(x) + np.random.rand(100)
yerr = np.random.rand(100)

erbpl1 = ax.errorbar(x, y, yerr=yerr, fmt='o', label='A')
erbpl2 = ax.errorbar(x, 0.02*y, yerr=yerr, fmt='o', label='B')

leg = ax.legend(handler_map=my_handler_map)

lines = [erbpl1, erbpl2]
lined = dict()
# not strictly sure about ordering, but 
for legline, origline in zip(leg.legendHandles, lines):
    legline.set_picker(5)  # 5 pts tolerance
    lined[legline] = origline


def onpick(event):
    # on the pick event, find the orig line corresponding to the
    # legend proxy line, and toggle the visibility
    legline = event.artist
    origline = lined[legline]
    for a in origline.get_children():
        vis = not a.get_visible()
        a.set_visible(vis)
    # Change the alpha on the line in the legend so we can see what lines
    # have been toggled
    if vis:
        legline.set_alpha(1.0)
    else:
        legline.set_alpha(0.2)
    fig.canvas.draw()

fig.canvas.mpl_connect('pick_event', onpick)

通过这种方式,我们就可以通过点击图例中的误差线或数据点来切换它们的可见性了。

  • 7
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值