【发布时间】:2021-02-18 05:12:38
【问题描述】:
我的问题是:当使用“motion_notify_event”将鼠标悬停在条上时如何注释 Matplotlib Polycollection 条形图?我花了一天的时间试图完成这项工作,但我无法理解一个多集合对象以及如何索引它。希望有人能帮助解决这个问题,我花了这么多时间,现在不想放弃!
在下面的链接中可以找到使用“motion_notify_event”进行分散、线条和条形注释的绝佳解决方案: Possible to make labels appear when hovering over a point in matplotlib?
但是,上述解决方案不处理“matplotlib.collections.polycollection”对象。我正在努力寻找使用上述解决方案中的代码访问该对象中保存的顶点和数组的方法。是否可以索引多集合;使用索引访问原始数据中的字符串值;然后在悬停时注释位置?
我使用了来自以下链接的 Polycollection 条时间线的修改示例,我已将其与上述链接中的悬停/注释示例融合在一起。 How to individually label bars in Matplotlib plot?
import datetime as dt
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from matplotlib.collections import PolyCollection
data = [(dt.datetime(2018, 7, 17, 0, 15), dt.datetime(2018, 7, 17, 0, 30), 'sleep','nap_1'),
(dt.datetime(2018, 7, 17, 0, 30), dt.datetime(2018, 7, 17, 0, 45), 'eat', 'snack_1'),
(dt.datetime(2018, 7, 17, 0, 45), dt.datetime(2018, 7, 17, 1, 0), 'work', 'meeting_1'),
(dt.datetime(2018, 7, 17, 1, 0), dt.datetime(2018, 7, 17, 1, 30), 'sleep','nap_2'),
(dt.datetime(2018, 7, 17, 1, 15), dt.datetime(2018, 7, 17, 1, 30), 'eat', 'snack_2'),
(dt.datetime(2018, 7, 17, 1, 30), dt.datetime(2018, 7, 17, 1, 45), 'work', 'project_2')]
cats = {"sleep" : 1, "eat" : 2, "work" : 3}
colormapping = {"sleep" : "C0", "eat" : "C1", "work" : "C2"}
verts = []
colors = []
for d in data:
v = [(mdates.date2num(d[0]), cats[d[2]]-.4),
(mdates.date2num(d[0]), cats[d[2]]+.4),
(mdates.date2num(d[1]), cats[d[2]]+.4),
(mdates.date2num(d[1]), cats[d[2]]-.4),
(mdates.date2num(d[0]), cats[d[2]]-.4)]
verts.append(v)
colors.append(colormapping[d[2]])
bars = PolyCollection(verts, facecolors=colors)
fig, ax = plt.subplots()
ax.add_collection(bars)
ax.autoscale()
loc = mdates.MinuteLocator(byminute=[0,15,30,45])
ax.xaxis.set_major_locator(loc)
ax.xaxis.set_major_formatter(mdates.AutoDateFormatter(loc))
ax.set_yticks([1,2,3])
ax.set_yticklabels(["sleep", "eat", "work"])
annot = ax.annotate("", xy=(0, 0), xytext=(20, 20), textcoords="offset points",
bbox=dict(boxstyle="round", fc="w"),
arrowprops=dict(arrowstyle="->"))
annot.set_visible(False)
def update_annot(ind):
# how to index the polycollection? get_offsets causes an error
pos = bars.get_offsets()[ind["ind"][0]]
# causes 'IndexError: index 5 is out of bounds for axis 0 with size 1'
annot.xy = pos
# If we can get an index, can we use it to access the original 'data' to get the
# string value at d[3] from data ('nap_1') and use it to annotate?
text = ""
annot.set_text(text)
annot.get_bbox_patch().set_facecolor(cmap(norm(c[ind["ind"][0]])))
annot.get_bbox_patch().set_alpha(0.4)
def hover(event):
vis = annot.get_visible()
if event.inaxes == ax:
cont, ind = bars.contains(event)
if cont:
update_annot(ind)
annot.set_visible(True)
fig.canvas.draw_idle()
else:
if vis:
annot.set_visible(False)
fig.canvas.draw_idle()
fig.canvas.mpl_connect("motion_notify_event", hover)
plt.show()
【问题讨论】:
标签: python matplotlib