matplotlib堆积面积图中的动态标签

时间:2017-12-04 14:47:51

标签: python pandas matplotlib

我正在处理由熊猫创建的堆积区域图。屏幕截图显示了一个这样的典型图(标签未明确显示): 生成此图的相关代码是

fig, axes = plt.subplots(nrows=2, ncols=1)
coredata = nonzero.loc[:, nonzero.columns != 'Busy'].plot.area(figsize=(9, 8), ax=axes[0], colormap='jet')

其中nonzero是一个更大的数据帧。问题是有太多的列导致拥挤的传说。我没有将图例移出图片,而是想使用matplotlib的事件来告诉我图表中的哪个元素悬停在上面。

def on_move(event):
    if event.inaxes == coredata:
        # help please

fig.canvas.mpl_connect("motion_notify_event", on_move)

事件完全按照需要触发,但我无法提取我悬停在其上的区域(分别是其标签)。 coredata.artists为空,coredata.lines是matplotlib.lines.Line2D元素(假设级别太低)。如何访问光标下的当前区域以显示其标签?

编辑以下是一个最小的例子:

from pandas import DataFrame, Series
from matplotlib import pyplot as plt

# mock data
d = {'one' : Series([1., 2., 3.], index=['a', 'b', 'c']),
     'two' : Series([1., 2., 3., 4.], index=['a', 'b', 'c', 'd']),
     'three': Series([0.5, 0.2, 0.3, 0.1], index=['a', 'b', 'c', 'd']),
     'four': Series([3., 2., 1., 0.3], index=['a', 'b', 'c', 'd']),
}
df = DataFrame(d)

fig, axes = plt.subplots()
chart = df.plot.area(ax=axes)

# create and initially hide annotation
annot = axes.annotate("", xy=(0,0), xytext=(-20,20),textcoords="offset points",
                    bbox=dict(boxstyle="round", fc="w"))
annot.set_visible(False)
def on_move(event):
    if event.inaxes == chart:
        pass # help plz: how do I best check I currently hover over one, two, three or four?
        print(event.xdata, event.ydata)
fig.canvas.mpl_connect("motion_notify_event", on_move)

plt.show()

1 个答案:

答案 0 :(得分:1)

就像悬停分散时一样,请参阅例如herehere您需要检查是否有任何集合包含mouseevent。为此,您将查看感兴趣的集合,进行检查,如果成功,可以在列表中添加标识符。

which = []
for i,c in enumerate(axes.collections):
    if c.contains(event)[0]:
        which.append(i)

然后,您可以使用此列表绘制一个新图例,其中仅包含该列表中标识的集合。由于重绘画布很昂贵并且可能会减慢应用程序的速度,因此很少会尝试这样做。在移动鼠标的过程中,很多时候都会出现完全相同的结果,因此我们可以存储它,只有在需要更改时才创建新的图例。

from pandas import DataFrame, Series
from matplotlib import pyplot as plt

# mock data
d = {'one' : Series([1., 2., 3.], index=['a', 'b', 'c']),
     'two' : Series([1., 2., 3., 4.], index=['a', 'b', 'c', 'd']),
     'three': Series([0.5, 0.2, 0.3, 0.1], index=['a', 'b', 'c', 'd']),
     'four': Series([3., 2., 1., 0.3], index=['a', 'b', 'c', 'd']),
}
df = DataFrame(d)

fig, axes = plt.subplots()
df.plot.area(ax=axes, legend=False)

# create and initially hide annotation
annot = axes.annotate("", xy=(0,0), xytext=(-20,20),textcoords="offset points",
                    bbox=dict(boxstyle="round", fc="w"))
annot.set_visible(False)

last = [None]
def on_move(event):
    if event.inaxes == axes:
        which = []
        for i,c in enumerate(axes.collections):
            if c.contains(event)[0]:
                which.append(i)
        if which != last[0]:
            last[0] = which
            axes.legend([axes.collections[i] for i in which],
                        [df.columns[i] for i in which])
            fig.canvas.draw_idle()

fig.canvas.mpl_connect("motion_notify_event", on_move)

plt.show()

enter image description here