微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

将鼠标悬停在图形的图表上时显示标签*具有较高的y轴值*,多条线和多轴

如何解决将鼠标悬停在图形的图表上时显示标签*具有较高的y轴值*,多条线和多轴

我想从使用python制作的图形中读取值,类似于将鼠标悬停在数据点上时数据点值在excel绘图中的显示方式。在这里使用各种解决方案时,我写下了下面的代码标记要悬停的点。

但是,当y轴值较高时(似乎是我对为什么它不起作用的假设),我似乎无法标记一些点,也无法使框具有坚实的背景,以便阅读Here's a picture of how one such point shows up far away from the actual location and with the text blocked by the curves behind it.奇怪的是,当所有y轴值都小于1时,代码可以正常工作。

from matplotlib import pyplot as plt
import numpy as np; np.random.seed(1)

x_data = list(range(0,30))
y1_data_a = np.sort(np.random.rand(30))
y1_data_b = np.sort(np.random.rand(30))
y1_data_c = [0.4 for point in x_data]
y2_data_a = [point**2 for point in x_data]
y2_data_b = [point*0.5 for point in y2_data_a]
y3_data = [(10/(point+1)) for point in x_data]

# #The code works fine with this data
# x_data = list(range(0,30))
# y1_data_a = np.sort(np.random.rand(30))
# y1_data_b = np.sort(np.random.rand(30))
# y1_data_c = [0.4 for point in x_data]
# y2_data_a = np.random.rand(30)
# y2_data_b = np.sort(np.random.rand(30))
# y3_data = np.sort(np.random.rand(30))[::-1]

fig,y1_axis = plt.subplots()
fig.subplots_adjust(right=0.75)

y2_axis = y1_axis.twinx()
y3_axis = y1_axis.twinx()

def make_patch_spines_invisible(ax):
    ax.set_frame_on(True)
    ax.patch.set_visible(False)
    for sp in ax.spines.values():
        sp.set_visible(False)

y3_axis.spines["right"].set_position(("axes",1.2))
make_patch_spines_invisible(y3_axis)
y3_axis.spines["right"].set_visible(True)

plot1,= y1_axis.plot(x_data,y1_data_a,color="#000CFF",label="Temp1 (°C)")
plot2,y1_data_b,color="#FF5100",label="Temp2 (°C)")
plot3,y1_data_c,"r--",label="Critical Temp (°C)")

plot4,= y2_axis.plot(x_data,y2_data_a,color="#000000",label="Pressure1 (atm)")
plot5,y2_data_b,color="#17E111",label="Pressure2 (atm)")

plot6,= y3_axis.plot(x_data,y3_data,color="#D418DE",label="Volume (m3)")

y1_axis.set_xlabel("Time (hrs)")
y1_axis.set_ylabel("Temperature (°C)")
y2_axis.set_ylabel("Pressure (atm)")
y3_axis.set_ylabel("Volume (m3)")

y3_axis.yaxis.label.set_color(plot6.get_color())

tkw = dict(size=4,width=1.5)
y1_axis.tick_params(axis='y',**tkw)
y2_axis.tick_params(axis='y',**tkw)
y3_axis.tick_params(axis='y',colors=plot6.get_color(),**tkw)
y1_axis.tick_params(axis='x',**tkw)

lines = [plot1,plot2,plot4,plot5,plot6]

plt.title("Labeling data points for plots with Multiple Axes and Lines",fontdict=None,loc='center')

annot = y1_axis.annotate("",xy=(0,0),xytext=(20,20),textcoords="offset points",bBox=dict(Boxstyle="round",facecolor="#FFFFFF"),arrowprops=dict(arrowstyle="->"))
annot.set_visible(False)


def update_annot(line,annot,ind):
    posx,posy = [line.get_xdata()[ind],line.get_ydata()[ind]]
    annot.xy = (posx,posy)
    text = f'{line.get_label()}: ({posx:.2f},{posy:.2f})'
    annot.set_text(text)
    annot.get_bBox_patch().set_alpha(1)


def hover(event):
    vis = annot.get_visible()
    if event.inaxes in [y1_axis,y2_axis,y3_axis]:
        for line in lines:
            cont,ind = line.contains(event)
            if cont:
                update_annot(line,ind['ind'][0])
                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()

The ticker on the bottom right of the plot only seems to show the values based on the last axis that has been used.在这里搜索之后,我发现了3种解决方案,可帮助显示包含点坐标的框:

  1. Possible to make labels appear when hovering over a point in matplotlib?(由于用于散点图,因此未完全使用此代码,但从此处找到了其他解决方案)
  2. Annotate lines of a plot with matplotlib when hover with mouse [duplicate](用于将先前的解决方案应用于线/曲线)
  3. How to make labels appear when hovering over a point in multiple axis?(用于将标签应用于具有多个轴的图形)

如何使该框显示在具有较高y轴值的图形中,以及如何使该框显示在图形上方以使其清晰可见?预先感谢!

解决方法

从本质上讲,您的问题是您创建的注释属于轴y1_axis。当您将鼠标悬停在某个点上时,您将在y1_axis的数据坐标中设置注释的位置,而不管该线是在该轴上还是在另一个轴上。

解决方案不仅要更新注释的坐标,还要更新其transform,以将点正确映射到以像素为单位的正确坐标。

注释的背景也是如此。由于您是在最底部的轴上创建的,因此注释在这些轴上的线上方,但在其他轴上的线下方。解决方案是在最上方的轴上创建注释。

(...)
# annotation should be on the top axis to avoid zorder problems
annot = fig.axes[-1].annotate("",xy=(0,0),xytext=(20,20),textcoords="offset points",bbox=dict(boxstyle="round",facecolor="#FFFFFF"),arrowprops=dict(arrowstyle="->"))
annot.set_visible(False)

(...)
def update_annot(line,annot,ind):
    posx,posy = [line.get_xdata()[ind],line.get_ydata()[ind]]
    annot.xycoords = line.axes.transData  # set the correct transform for that line
    annot.xy = (posx,posy)
    text = f'{line.get_label()}: ({posx:.2f},{posy:.2f})'
    annot.set_text(text)
    annot.get_bbox_patch().set_alpha(1)
(...)

完整代码:

from matplotlib import pyplot as plt
import numpy as np; np.random.seed(1)

x_data = list(range(0,30))
y1_data_a = np.sort(np.random.rand(30))
y1_data_b = np.sort(np.random.rand(30))
y1_data_c = [0.4 for point in x_data]
y2_data_a = [point**2 for point in x_data]
y2_data_b = [point*0.5 for point in y2_data_a]
y3_data = [(10/(point+1)) for point in x_data]

# #The code works fine with this data
# x_data = list(range(0,30))
# y1_data_a = np.sort(np.random.rand(30))
# y1_data_b = np.sort(np.random.rand(30))
# y1_data_c = [0.4 for point in x_data]
# y2_data_a = np.random.rand(30)
# y2_data_b = np.sort(np.random.rand(30))
# y3_data = np.sort(np.random.rand(30))[::-1]

fig,y1_axis = plt.subplots()
fig.subplots_adjust(right=0.75)

y2_axis = y1_axis.twinx()
y3_axis = y1_axis.twinx()

def make_patch_spines_invisible(ax):
    ax.set_frame_on(True)
    ax.patch.set_visible(False)
    for sp in ax.spines.values():
        sp.set_visible(False)

y3_axis.spines["right"].set_position(("axes",1.2))
make_patch_spines_invisible(y3_axis)
y3_axis.spines["right"].set_visible(True)

plot1,= y1_axis.plot(x_data,y1_data_a,color="#000CFF",label="Temp1 (°C)")
plot2,y1_data_b,color="#FF5100",label="Temp2 (°C)")
plot3,y1_data_c,"r--",label="Critical Temp (°C)")

plot4,= y2_axis.plot(x_data,y2_data_a,color="#000000",label="Pressure1 (atm)")
plot5,y2_data_b,color="#17E111",label="Pressure2 (atm)")

plot6,= y3_axis.plot(x_data,y3_data,color="#D418DE",label="Volume (m3)")

y1_axis.set_xlabel("Time (hrs)")
y1_axis.set_ylabel("Temperature (°C)")
y2_axis.set_ylabel("Pressure (atm)")
y3_axis.set_ylabel("Volume (m3)")

y3_axis.yaxis.label.set_color(plot6.get_color())

tkw = dict(size=4,width=1.5)
y1_axis.tick_params(axis='y',**tkw)
y2_axis.tick_params(axis='y',**tkw)
y3_axis.tick_params(axis='y',colors=plot6.get_color(),**tkw)
y1_axis.tick_params(axis='x',**tkw)

lines = [plot1,plot2,plot4,plot5,plot6]

plt.title("Labeling data points for plots with Multiple Axes and Lines",fontdict=None,loc='center')

# annotation should be on the top axis to avoid zorder problems
annot = fig.axes[-1].annotate("",arrowprops=dict(arrowstyle="->"))
annot.set_visible(False)


def update_annot(line,line.get_ydata()[ind]]
    annot.xycoords = line.axes.transData
    annot.xy = (posx,{posy:.2f})'
    annot.set_text(text)
    annot.get_bbox_patch().set_alpha(1)


def hover(event):
    vis = annot.get_visible()
    if event.inaxes in [y1_axis,y2_axis,y3_axis]:
        for line in lines:
            cont,ind = line.contains(event)
            if cont:
                update_annot(line,ind['ind'][0])
                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()

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。