如何使用 mplcursors 对多网格图中的完整数据帧行进行注释

How to use mplcursors to annotate with a complete dataframe row in a multigrid plot

提问人:diyer0001 提问时间:8/29/2023 最后编辑:Trenton McKinneydiyer0001 更新时间:8/30/2023 访问量:92

问:

我正在尝试绘制跨多个视觉属性(面、色调、形状、x、y)的多维散点图。我还尝试在光标悬停时获得工具提示,以显示该点的其他属性。(我正在使用 seaborn + mplcursors,但我没有嫁给这个解决方案。问题在于悬停在数据集中的索引错误,并显示错误的信息。您可以在以下玩具示例中看到相同的内容,该示例由 seaborn 和 mplcursors 网站中的两个示例组装而成。

我相信我已经诊断出 cursor.connect() 的问题没有在数据帧中返回正确的索引。如果我减少修饰符(色调、列、行等)的数量,我可以让这个例子起作用,但它不适用于所有这些修饰符。

import seaborn as sns
import matplotlib.pyplot as plt
import mplcursors


df = sns.load_dataset("tips")

sns.relplot(data=df, x="total_bill", y="tip", hue="day", col="time", row="sex")


def show_hover_panel(get_text_func=None):
    cursor = mplcursors.cursor(
        hover=2,  # Transient
        annotation_kwargs=dict(
            bbox=dict(
                boxstyle="square,pad=0.5",
                facecolor="white",
                edgecolor="#ddd",
                linewidth=0.5,
            ),
            linespacing=1.5,
            arrowprops=None,
        ),
        highlight=True,
        highlight_kwargs=dict(linewidth=2),
    )

    if get_text_func:
        cursor.connect(
            event="add",
            func=lambda sel: sel.annotation.set_text(get_text_func(sel.index)), # <- this doesn't appear to return the correct integer index in the dataframe
        )

    return cursor


def on_add(index):
    item = df.iloc[index] 
    parts = [
        f"total_bill: {item.total_bill}",
        f"tip: {item.tip}",
        f"day: ${item.day}",
        f"time: ${item.time}",
        f"sex: ${item.sex}",
    ]

    return "\n".join(parts)


show_hover_panel(on_add)

plt.show()

example of issue

我试过什么:

  • 最小可行示例
  • 删除修饰符 = 有效
  • 根据数据追溯正确的点位置,但是当我将索引传递给工具提示时,我注意到索引与数据帧中的正确索引不对应。
python seaborn facet-grid mplcursors relplot

评论

1赞 Trenton McKinney 8/29/2023
如图所示,可以很好地显示具有多面的 x 和 y。但是,您需要一种方法来按 和 进行筛选,以便从数据帧中正确选择额外的数据。mplcursorsrelplotcolrow
0赞 diyer0001 8/30/2023
是的,可悲的是,我不相信直接知道这些信息。mplcursors

答:

1赞 JohanC 8/30/2023 #1

sns.relplot返回包含 .这是一个字典,每一列和每一行都告诉哪个是相应的子图()。基于此,您可以创建一个新字典,将 映射到数据帧的相应子集。(请注意,这可能会占用大型数据帧的大量额外内存。FacetGridaxes_dictaxax

中选定的艺术家保留对子情节 () 的引用,该子情节可用作新词典中的键。mplcursorsset.artist.axes

下面是示例的样子。注释函数现在更大了,所以它需要自己的函数。

import seaborn as sns
import matplotlib.pyplot as plt
import mplcursors

df = sns.load_dataset("tips")

g = sns.relplot(data=df, x="total_bill", y="tip", hue="day", col="time", row="sex")

# create a dictionary mapping subplots to their corresponding subset of the dataframe
subplot_df_dict = dict()
for (sex, time), ax in g.axes_dict.items():
    subplot_df_dict[ax] = df[(df['sex'] == sex) & (df['time'] == time)].reset_index(drop=True)

def show_annotation(sel):
    ax = sel.artist.axes
    item = subplot_df_dict[ax].iloc[sel.index]
    parts = [
        f"total_bill: {item.total_bill}",
        f"tip: {item.tip}",
        f"day: ${item.day}",
        f"time: ${item.time}",
        f"sex: ${item.sex}",
    ]
    sel.annotation.set_text("\n".join(parts))

def show_hover_panel(show_annotation_func=None):
    cursor = mplcursors.cursor(
        hover=2,  # Transient
        annotation_kwargs=dict(
            bbox=dict(
                boxstyle="square,pad=0.5",
                facecolor="white",
                edgecolor="#ddd",
                linewidth=0.5,
            ),
            linespacing=1.5,
            arrowprops=None,
        ),
        highlight=True,
        highlight_kwargs=dict(linewidth=2),
    )
    if show_annotation_func is not None:
        cursor.connect(
            event="add",
            func=show_annotation_func
        )
    return cursor

show_hover_panel(show_annotation)
plt.show()

seaborn facetgrid with mplcursors tooltip

评论

0赞 diyer0001 9/1/2023
这行得通。多谢!