我正在使用matplotlib基于一个嵌套框架制作步骤图,但我希望嵌套框架的一个键/值显示出来(signals_df['Gage']
),而不是坐标作为注解,但我总是得到错误:AttributeError: 'Line2D' object has no attribute 'get_offsets'
当我从下到上点击第一个子图时,注解没有出现。事实上,我注解掉了annot.set_visible(False)
,并将示例中的""
替换为val_gage
,这样当单击子图中的某个点时,看起来就像我希望注解一个接一个地出现。这是有问题的代码:
import pandas as pd
import numpy as np
import matplotlib as mtpl
from matplotlib import pyplot as plt
import matplotlib.ticker as ticker
annot = mtpl.text.Annotation
data = {
# 'Name': ['Status', 'Status', 'HMI', 'Allst', 'Drvr', 'CurrTUBand', 'RUSource', 'RUReqstrPriority', 'RUReqstrSystem', 'RUResReqstStat', 'CurrTUBand', 'DSP', 'SetDSP', 'SetDSP', 'DSP', 'RUSource', 'RUReqstrPriority', 'RUReqstrSystem', 'RUResReqstStat', 'Status', 'Delay', 'Status', 'Delay', 'HMI', 'Status', 'Status', 'HMI', 'DSP'],
# 'Value': [4, 4, 2, 1, 1, 1, 0, 7, 0, 4, 1, 1, 3, 0, 3, 0, 7, 0, 4, 1, 0, 1, 0, 1, 4, 4, 2, 3],
# 'Gage': ['H1', 'H3', 'H3', 'H3', 'H3', 'H3', 'H3', 'H3', 'H3', 'H3', 'H3', 'H3', 'H3', 'H3', 'H3', 'H3', 'H3', 'H3', 'H3', 'H1', 'H1', 'H3', 'H3', 'H3', 'H1', 'H3', 'H3', 'H3'],
# 'Id_Par': [0, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 0, 0, 22, 22, 28, 28, 28, 28, 0, 0, 38, 38, 0, 0, 0, 0, 0]
'Name': ['Lamp_D_Rq', 'Status', 'Status', 'HMI', 'Lck_D_RqDrv3', 'Lck_D_RqDrv3', 'Lck_D_RqDrv3', 'Lck_D_RqDrv3', 'Lamp_D_Rq', 'Lamp_D_Rq', 'Lamp_D_Rq', 'Lamp_D_Rq'],
'Value': [0, 4, 4, 2, 1, 1, 2, 2, 1, 1, 3, 3],
'Gage': ['F1', 'H1', 'H3', 'H3', 'H3', 'F1', 'H3', 'F1', 'F1', 'H3', 'F1', 'H3'],
'Id_Par': [0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0]
}
signals_df = pd.DataFrame(data)
def plot_signals(signals_df):
print(signals_df)
# Count signals by parallel
signals_df['Count'] = signals_df.groupby('Id_Par').cumcount().add(1).mask(signals_df['Id_Par'].eq(0), 0)
# Subtract Parallel values from the index column
signals_df['Sub'] = signals_df.index - signals_df['Count']
id_par_prev = signals_df['Id_Par'].unique()
id_par = np.delete(id_par_prev, 0)
signals_df['Prev'] = [1 if x in id_par else 0 for x in signals_df['Id_Par']]
signals_df['Final'] = signals_df['Prev'] + signals_df['Sub']
# Convert and set Subtract to index
signals_df.set_index('Final', inplace=True)
# Get individual names and variables for the chart
names_list = [name for name in signals_df['Name'].unique()]
num_names_list = len(names_list)
num_axisx = len(signals_df["Name"])
# Matplotlib's categorical feature to convert x-axis values to string
x_values = [-1, ]
x_values += (list(set(signals_df.index)))
x_values = [str(i) for i in sorted(x_values)]
# Creation Graphics
fig, ax = plt.subplots(nrows=num_names_list, figsize=(10, 10), sharex=True)
plt.xticks(np.arange(0, num_axisx), color='SteelBlue', fontweight='bold')
# Loop to build the different graphs
for pos, name in enumerate(names_list):
# Creating a dummy plot and then remove it
dummy, = ax[pos].plot(x_values, np.zeros_like(x_values))
dummy.remove()
# Get names by values and gage data
data = signals_df[signals_df["Name"] == name]["Value"]
data_gage = signals_df[signals_df["Name"] == name]["Gage"]
# Get values axis-x and axis-y
x_ = np.hstack([-1, data.index.values, len(signals_df) - 1])
y_ = np.hstack([0, data.values, data.iloc[-1]])
y_gage = np.hstack(["", "-", data_gage.values])
# print(y_gage)
# Plotting the data by position
steps = ax[pos].plot(x_.astype('str'), y_, drawstyle='steps-post', marker='*', markersize=8, color='k', linewidth=2)
ax[pos].set_ylabel(name, fontsize=8, fontweight='bold', color='SteelBlue', rotation=30, labelpad=35)
ax[pos].yaxis.set_major_formatter(ticker.FormatStrFormatter('%0.1f'))
ax[pos].yaxis.set_tick_params(labelsize=6)
ax[pos].grid(alpha=0.4, color='SteelBlue')
# Labeling the markers with Values and Gage
xy_temp = []
for i in range(len(y_)):
if i == 0:
xy = [x_[0].astype('str'), y_[0]]
xy_temp.append(xy)
else:
xy = [x_[i - 1].astype('str'), y_[i - 1]]
xy_temp.append(xy)
# Creating values in text inside the plot
ax[pos].text(x=xy[0], y=xy[1], s=str(xy[1]), color='k', fontweight='bold', fontsize=12)
for val_gage, xy in zip(y_gage, xy_temp):
annot = ax[pos].annotate(val_gage, xy=xy, xytext=(-20, 20), textcoords="offset points",
bbox=dict(boxstyle="round", fc="w"),
arrowprops=dict(arrowstyle="->"))
# annot.set_visible(False)
# Function for storing and showing the clicked values
def update_annot(ind):
print("Enter update_annot")
coord = steps[0].get_offsets()[ind["ind"][0]]
annot.xy = coord
text = "{}, {}".format(" ".join(list(map(str, ind["ind"]))),
" ".join([y_gage[n] for n in ind["ind"]]))
annot.set_text(text)
annot.get_bbox_patch().set_alpha(0.4)
def on_click(event):
print("Enter on_click")
vis = annot.get_visible()
# print(event.inaxes)
# print(ax[pos])
# print(event.inaxes == ax[pos])
if event.inaxes == ax[pos]:
cont, ind = steps[0].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("button_press_event",on_click)
plt.show()
plot_signals(signals_df)
我已经测试和审查了许多答案和代码,如下所示:
- How to add hovering annotations in matplotlib
- How to make labels appear when hovering over a point in multiple axis?
- ¿Es posible que aparezcan etiquetas al pasar el mouse sobre un punto en matplotlib?
- Matplotlib Cursor — How to Add a Cursor and Annotate Your Plot
我甚至回顾了mplcursors模块很长一段时间,因为它附带了一个示例,其中的步骤图与我正在做的https://mplcursors.readthedocs.io/en/stable/examples/step.html类似,但它给了我同样的结果,我找不到解决方案。
2条答案
按热度按时间sr4lhrrt1#
使用Plotly进行数据标注标签动画鼠标悬停在图形数据点上
更不用说大量其他令人敬畏的,易于使用的,广泛兼容的JS交互式绘图功能,全部免费,全部使用Python。只需使用conda(或pip)安装,无需在线帐户,最新版本中的绘图默认为“离线模式”。
所以用plotly,具体的plotly express,非常简单!
就轴/数据的具体细节而言,我不是100%你想要的,但我认为下面展示了Plotly可以用来创建交互式图形的巨大便利性,以及非常强大的定制功能。
通过the
plotly
docs,您可以轻松地将这些交互式图形调整为您想要的目的。plotly.express
,您仍然可以访问与所有其他子模块相关的内置Fig
功能。所以不要忽略这些功能[例如,上面的文档链接显示了特定于 * 子标绘,自定义annotations/hover annotations,自定义样式格式 * 等的部分,所有这些仍然适用于plotly.express
中的对象!]。I -数据结构设置
和你的一样. Plotly是专门为
pandas.DataFrames
设计的。例如,在一个示例中,
**注意:**然后我通过绘图函数运行
signals_df
,并添加return signals_df
以获得更新的df,即:| 最终|名称|值|盖奇|Id_Par|计数|子|Prev|
| --|--|--|--|--|--|--|--|
| 0 |灯_D_Rq| 0 |F1| 0 | 0 | 0 | 0 |
| 1 |地位| 4 |H1| 0 | 0 | 1 | 0 |
| 2 |地位| 4 |H3| 0 | 0 | 2 | 0 |
| 3 |HMI| 2 |H3| 11 | 1 | 2 | 1 |
| 4 |Lck_D_RqDrv3| 1 |H3| 0 | 0 | 4 | 0 |
| 5 |Lck_D_RqDrv3| 1 |F1| 0 | 0 | 5 | 0 |
| 6 |Lck_D_RqDrv3| 2 |H3| 0 | 0 | 6 | 0 |
| 7 |Lck_D_RqDrv3| 2 |F1| 0 | 0 | 7 | 0 |
| 8 |灯_D_Rq| 1 |F1| 0 | 0 | 8 | 0 |
| 9 |灯_D_Rq| 1 |H3| 0 | 0 | 9 | 0 |
| 10 |灯_D_Rq| 3 |F1| 0 | 0 | 10 | 0 |
| 11 |灯_D_Rq| 3 |H3| 0 | 0 | 11 | 0 |
II -使用
plotly.express
(px)绘制自定义悬停注解这里有一个相对简单的(即
mpl
),可能是多功能的,现代的交互式显示您的数据使用Plotly(通过px
):ckocjqey2#
在不太了解你正在使用的库的情况下,我可以看到你正在创建这些注解对象,然后将它们赋值给一个全局变量,这个全局变量稍后会被重新赋值,因此你失去了使它可见的正确对象。
相反,您可以将注解对象保存在字典中,并在以后需要时根据对象检索它们。
我使用了一个列表来向你展示这个想法,但是我想你需要一个字典来识别正确的对象。
我修改了一下你的代码,如果你调整窗口大小,它会显示所需的行为.我想你必须找到一种方法来刷新图:
我希望这对你有帮助,它会解决你的问题。它看起来更像是一个python/编程问题,如果我理解正确的话,与你正在使用的库没有太大关系:)