单击“seaborn”热图以打印该单元格中的元数据

Clicking `seaborn` heatmap to print metadata from that cell

我已经弄清楚如何打印 matplotlib 散点图并根据单击点的元数据单击这些点以提供其他数据的图表。我现在想将类似的想法应用于 seaborn 热图。问题是我用于 matplotlib 图的逻辑似乎是散点图所特有的。以 here 为特色并写在下面的循环不适用于热图。

import matplotlib.pyplot as plt

class custom_objects_to_plot:
    def __init__(self, x, y, name):
        self.x = x
        self.y = y
        self.name = name

a = custom_objects_to_plot(10, 20, "a")
b = custom_objects_to_plot(30, 5, "b")
c = custom_objects_to_plot(40, 30, "c")
d = custom_objects_to_plot(120, 10, "d")

def on_pick(event):
    print(event.artist.obj.name)

fig, ax = plt.subplots()
for obj in [a, b, c, d]:
    artist = ax.plot(obj.x, obj.y, 'ro', picker=5)[0]
    artist.obj = obj

fig.canvas.callbacks.connect('pick_event', on_pick)

plt.show()

为了更详细一点,我有五个对象,每个对象都对十个参数进行评分,总共有 50 个评分。除了我的数据框中的“主题”、“参数”和“评级”列之外,还有一个评论列。当我点击横轴为主题、纵轴为参数的热图时,我希望打印出这些评论。

看来我应该能够使用热图中的位置来识别主题-参数组合并查找该主题对该参数的评论,但从单击的单元格中提取主题和参数我不明白,带有 custom_objects_to_plot 的参考代码似乎不适用于热图。虽然我对如何执行此任务有自己的想法,但如果我能从单击的单元格中获取主题和参数,我欢迎使用不同方法但仍然给我可点击的 seaborn 热图的答案。

您可以尝试 mplcursors,并使用虚拟图像(因为不支持由 sns.heatmap 创建的 QuadMesh)。使用 hover=True,悬停时信息会显示在注释框中。对于 hover=False(默认值),这仅在单击时发生。如果你只是想打印一些东西,你可以设置 sel.annotation.set_visible(False) 并打印一些东西(或更新状态栏)。

这是一个例子:

import matplotlib.pyplot as plt
import mplcursors
import seaborn as sns
import pandas as pd
import numpy as np

def show_annotation(sel):
    x = int(sel.target[0])
    y = int(sel.target[1])
    sel.annotation.set_text(f's:{subjects[y]} p:{parameters[x]} r:{df_rating.iloc[y, x]}\n'
                            f'{df_comment.iloc[y, x]}')
    sel.annotation.get_bbox_patch().set(alpha=0.9)

subjects = np.arange(1, 6)
parameters = [*'ABCDEFGHIJ']
df = pd.DataFrame({'subject': np.repeat(subjects, len(parameters)),
                   'parameter': np.tile(parameters, len(subjects)),
                   'rating': np.random.randint(1, 11, len(subjects) * len(parameters)),
                   'comment': [f'comment subj {i} param {j}' for i in subjects for j in parameters]})
df_rating = df.pivot('subject', 'parameter', 'rating')
df_comment = df.pivot('subject', 'parameter', 'comment')
sns.set_style('white')
ax = sns.heatmap(df_rating, annot=True, lw=2)
dummy_image = ax.imshow(df_rating.to_numpy(), zorder=-1, aspect='auto')
cursor = mplcursors.cursor(dummy_image, hover=True)
cursor.connect('add', show_annotation)
plt.show()