我目前正在尝试编写一个seaborn stripplot,当鼠标悬停时,它会在数据框中显示点的列和索引。 这提出了几个问题:
stripplot.contains()
返回什么?我知道它返回一个布尔值,表示事件是否位于容器艺术家中,并返回一个
dict
给出所选数据点的标签。但是,在 2D DataFrame 的情况下,这个 dict
实际上是什么样的?
如何利用这些数据在数据框中找到数据点?我当前的程序如下所示,大部分取自
这个问题:
#Creating the data frame
A = pd.DataFrame(data = np.random.randint(10,size=(5,5)))
fig,ax = plt.subplots()
strp = sns.stripplot(A)
#Creating an empty annotation
annot = ax.annotate("", xy=(0,0), xytext=(20,20),textcoords="offset points",
bbox=dict(boxstyle="round", fc="w"))
annot.set_visible(False)
#Updating the annotation based on what stripplot.contains() returns
def update_annot(ind):
mX, mY = A[ind["ind"][0]], A[ind["ind"][0]].loc[ [ind["ind"][0]] ]
annot.xy = (mX,mY)
annot.set_text(str(ind["ind"][0])+", "+str(ind["ind"][0]))
annot.get_bbox_patch().set_facecolor("blue")
annot.get_bbox_patch().set_alpha(0.4)
#Linking the annotation update to the event
def hover(event):
vis = annot.get_visible()
#Create the proper annotation if the event occurs within the bounds of the axis
if event.inaxes == ax:
cont, ind = strp.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()
#Call the hover function when the mouse moves
fig.canvas.mpl_connect("motion_notify_event", hover)
plt.show()
我的猜测是,我期望从
dict
输出的
stripplot.contains
的形状存在问题。由于我找不到打印它的方法(一旦运行最后一行,就不再打印任何内容),所以我很难知道......谢谢!
sns.stripplot(...)
返回已创建绘图的
ax
。因此,strp.contains(...)
与 ax.contains(...)
相同。要向绘图添加注释,mplcursors
是一个方便的库。其注释函数中的
sel
参数具有以下字段:
sel.target
sel.artist
PathCollection
分组的点的集合。每个 x 值都有一个这样的集合。sel.index
collection_to_day
是一个字典,它将每个集合映射到其相应的 x 值。如果 x 值不是
pd.Categorical
类型,则可能需要进行一些调整以适应您的具体情况。renumbering
是一个字典,其中包含每个“天”的数组。该数组将点的索引映射到原始数据帧中的索引。原始数据帧不应包含绘图的 x 或 y 值的 NaN 值,因为这些值将被过滤掉。
import matplotlib.pyplot as plt
import seaborn as sns
import mplcursors
def show_annotation(sel):
day = collection_to_day[sel.artist]
index_in_df = renumbering[day][sel.index]
row = tips.iloc[index_in_df]
txt = f"Day: {row['day']})\nTime: {row['time']}\nTip: {row['tip']}\nBill total: {row['total_bill']}"
sel.annotation.set_text(txt)
tips = sns.load_dataset('tips')
fig, ax = plt.subplots()
sns.stripplot(data=tips, x='day', y='tip', hue='time', ax=ax)
days = tips['day'].cat.categories
collection_to_day = dict(zip(ax.collections, days))
renumbering = dict()
for day in days:
renumbering[day] = tips[tips['day'] == day].reset_index()['index']
cursor = mplcursors.cursor(hover=True)
cursor.connect('add', show_annotation)
plt.show()