我见过Possible to make labels appear when hovering over a point in matplotlib?-但不幸的是,它对这个特定情况没有帮助。
考虑以下示例:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import matplotlib
print("matplotlib.__version__ {}".format(matplotlib.__version__))
import matplotlib.pyplot as plt
import numpy as np
def onhover(event, fig, axes):
print(event)
def main():
xdata = np.arange(0, 101, 1) # 0 to 100, both included
ydata1 = np.sin(0.01*xdata*np.pi/2)
fig, ax1 = plt.subplots(1, 1, figsize=(9, 6), dpi=120)
fig.subplots_adjust(hspace=0)
pl11, = ax1.plot(xdata, ydata1, color="Red", label="My plot")
leg = ax1.legend(ncol=1, bbox_to_anchor=(0,1.01), loc="lower left", borderaxespad=0, prop={'size': 8})
fig.canvas.mpl_connect('motion_notify_event', lambda event: onhover(event, fig, (ax1,) ))
plt.show()
# ENTRY POINT
if __name__ == '__main__':
main()
结果如下图所示:
问题是:如果我移动鼠标指针,所以它将鼠标悬停在图例条目上,那么由于事件中的打印输出,我得到的是:
....
motion_notify_event: xy=(175, 652) xydata=(None, None) button=None dblclick=False inaxes=None
motion_notify_event: xy=(174, 652) xydata=(None, None) button=None dblclick=False inaxes=None
motion_notify_event: xy=(173, 652) xydata=(None, None) button=None dblclick=False inaxes=None
motion_notify_event: xy=(172, 652) xydata=(None, None) button=None dblclick=False inaxes=None
...这很有意义,因为我已将图例故意放在情节之外。
但是,现在我不知道如何获得对图例条目的引用?我想做的基本上是获得图例条目的引用,以便我可以在“工具提示”(即本例中为Matplotlib)中编写与图例标签(此处为“我的情节”)相同的文本。注释),后跟其他一些文字;然后,一旦鼠标离开图例条目的区域,工具提示/注释就会消失。
我可以用Matplotlib实现吗?如果可以,怎么办?
答案 0 :(得分:1)
您可以执行以下操作:
def onhover(event):
if leg.get_window_extent().contains(event.x,event.y):
print(event, "In legend! do something!")
xdata = np.arange(0, 101, 1) # 0 to 100, both included
ydata1 = np.sin(0.01*xdata*np.pi/2)
fig, ax1 = plt.subplots(1, 1, figsize=(9, 6), dpi=120)
pl11, = ax1.plot(xdata, ydata1, color="Red", label="My plot")
leg = ax1.legend(ncol=1, bbox_to_anchor=(0,1.01), loc="lower left", borderaxespad=0, prop={'size': 8})
fig.canvas.mpl_connect('motion_notify_event', onhover)
plt.show()
答案 1 :(得分:0)
这是OP的完整翻版,具有两个图和两个图例条目,并且具有实际的悬停-实现有些复杂,因为还要考虑坐标系转换和z顺序:
这是代码-包括注释:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import matplotlib
print("matplotlib.__version__ {}".format(matplotlib.__version__))
import matplotlib.pyplot as plt
import numpy as np
def onhover(event, fig, axes, leg, tooltip):
if leg.get_window_extent().contains(event.x,event.y):
print(event, "In legend! do something!")
ax1 = axes[0]
hand, labl = ax1.get_legend_handles_labels()
#print(hand)
#print(labl)
r = plt.gcf().canvas.get_renderer()
#for ilidx, ilabl in enumerate(labl): # labl contents are just str! so no geometry data
# print(ilabl.get_window_extent())
#for ihidx, ihand in enumerate(hand):
# # NOTE: just ihand.get_window_extent() causes: TypeError: get_window_extent() missing 1 required positional argument: 'renderer'
# print(ihand.get_window_extent(r)) # apparently, this is the original line, not just the legend line, as here it prints: Bbox(x0=173.04545454545456, y0=104.10999999999999, x1=933.9545454545455, y1=606.71)
# if ihand.get_window_extent(r).contains(event.x,event.y):
# print("EEEE")
hoveredtxt = None
for itxt in leg.get_texts():
#print(itxt)
#print(itxt.get_window_extent().contains(event.x,event.y))
if itxt.get_window_extent().contains(event.x,event.y):
#print("Legend hover on: {}".format(itxt))
hoveredtxt = itxt
break
if hoveredtxt is not None:
tooltip.set_text("'{}' is hovered!".format(hoveredtxt.get_text()))
tooltip.set_visible(True)
# see: https://matplotlib.org/3.1.1/gallery/recipes/placing_text_boxes.html
# https://matplotlib.org/3.1.1/tutorials/advanced/transforms_tutorial.html - None for "display" coord system
tooltip.set_transform( None )
tooltip.set_position( (event.x, event.y) ) # is by default in data coords!
else:
tooltip.set_visible(False)
fig.canvas.draw_idle()
def main():
xdata = np.arange(0, 101, 1) # 0 to 100, both included
ydata1 = np.sin(0.01*xdata*np.pi/2)
ydata2 = 10*np.sin(0.01*xdata*np.pi/4)
fig, ax1 = plt.subplots(1, 1, figsize=(9, 6), dpi=120)
fig.subplots_adjust(hspace=0)
pl11, = ax1.plot(xdata, ydata1, color="Red", label="My plot")
pl12, = ax1.plot(xdata, ydata2, color="Blue", label="Other stuff")
leg = ax1.legend(ncol=2, bbox_to_anchor=(0,1.01), loc="lower left", borderaxespad=0, prop={'size': 8})
# NOTE: ax.annotate without an arrow is basically ax.text;
#tooltip = ax.annotate("", xy=(0, 0), xytext=(-20, 20), textcoords="offset points",
# bbox=dict(boxstyle="round", fc="w"),
# arrowprops=dict(arrowstyle="->"))
# however, no `textcoords` in .text; "The default transform specifies that text is in data coords, alternatively, you can specify text in axis coords", via transform=ax.transAxes
# must add zorder of high number too, else the tooltip comes under the legend!
tooltip = ax1.text(0, 0, 'TEST', bbox=dict(boxstyle="round", fc="w"), zorder=10)
tooltip.set_visible(False)
fig.canvas.mpl_connect('motion_notify_event', lambda event: onhover(event, fig, (ax1,), leg, tooltip ))
plt.show()
# ENTRY POINT
if __name__ == '__main__':
main()