【问题标题】:Plotly Dash scatter plot: pointNumber is assigned to multiple points in hover dataPlotly Dash 散点图:pointNumber 分配给悬停数据中的多个点
【发布时间】:2021-11-20 23:56:14
【问题描述】:

我在使用 Plotly 和 Dash 通过将光标悬停在散点图中的点上来检索悬停数据时遇到了问题。 从 Dash 应用程序检索的悬停数据似乎包含同一图中多个点的相同 pointNumber 和 pointIndex。这使得在将鼠标悬停在相应点上时无法显示与给定实例关联的正确信息。

这是一个可以在 Jupyter 笔记本中运行的简化示例。最后,我希望在悬停时显示图像。

from sklearn.datasets import load_iris
import numpy as np
import pandas as pd
from jupyter_dash import JupyterDash
from dash import dcc, html, Input, Output, no_update
import plotly.express as px

# Loading iris data to pandas dataframe
data = load_iris()
images = data.data
labels = data.target

df = pd.DataFrame(images[:, :2], columns=["feat1", "feat2"])
df["label"] = labels

# Color for each class
color_map = {0: "setosa",
             1: "versicolor",
             2: "virginica"}

colors = [color_map[l] for l in labels]

df["color"] = colors

pd.set_option("display.max_rows", None, "display.max_columns", None)
print(df)

# Setup plotly scatter plot
fig = px.scatter(df, x="feat1", y="feat2", color="color")
fig.update_traces(hoverinfo="none",
                  hovertemplate=None)

# Setup Dash
app = JupyterDash(__name__)
app.layout = html.Div(className="container",
                      children=[dcc.Graph(id="graph-5", figure=fig, clear_on_unhover=True),
                                dcc.Tooltip(id="graph-tooltip-5", direction="bottom")])

@app.callback(Output("graph-tooltip-5", "show"),
              Output("graph-tooltip-5", "bbox"),
              Output("graph-tooltip-5", "children"),
              Input("graph-5", "hoverData"))

def display_hover(hoverData):
    if hoverData is None:
        return False, no_update, no_update
    
    print(hoverData)

    hover_data = hoverData["points"][0]
    bbox = hover_data["bbox"]
    num = hover_data["pointNumber"]
    
    children = [html.Div([html.Img(style={"height": "50px", 
                                          "width": "50px", 
                                          "display": "block", 
                                          "margin": "0 auto"}),
                                   html.P("Feat1: {}".format(str(df.loc[num]["feat1"]))),
                                   html.P("Feat2: {}".format(str(df.loc[num]["feat2"])))])]

    return True, bbox, children

if __name__ == "__main__":
    app.run_server(mode="inline", debug=True)

例如,通过 print(df) 检索到的以下两个实例可以观察到该问题:

索引 feat1 feat2 标签颜色
31 5.4 3.4 0 塞萨
131 7.9 3.8 2 弗吉尼亚

两者都被分配了通过 print(HoverData) 检索到的相同的 pointNumber 和 pointIndex:

{'points': [{'curveNumber': 2, 'pointNumber': 31, 'pointIndex': 31, 'x':7.9,'y':3.8,'bbox':{'x0':1235.5,'x1':1241.5,'y0':152.13, 'y1': 158.13}}]}

{'points': [{'curveNumber': 0, 'pointNumber': 31, 'pointIndex':31,'x':5.4,'y':3.4,'bbox':{'x0':481.33,'x1': 487.33,'y0':197.38,'y1':203.38}}]}

这是将鼠标悬停在两个实例上时的可视化效果。右侧图像的悬停信息是错误的。

有趣的是,使用时问题解决了

fig = px.scatter(df, x="feat1", y="feat2", color="label")

但是,这将导致图例以连续方式显示,并且无法选择性地可视化与 HTML 中特定类关联的实例。

这是一个错误还是我忽略了什么? 非常感谢任何帮助!

【问题讨论】:

    标签: python-3.x plotly-dash


    【解决方案1】:

    事实证明,我错误地认为 pointNumberpointIndex 是唯一的。只要在px.scatter() 中将非数字列用作color 参数,就会为每个类重新编号点编号和索引。可以通过组合curveNumberpointNumberpointIndex 之一来唯一标识散点图中的点。

    一个潜在的解决方案是为每个类生成单独的索引并将它们添加到数据框:

    curve_indices = np.array([np.arange(0, num_samples) for num_samples in np.unique(class_annot, return_counts=True)[1]], dtype="object")
    curve_indices = np.concatenate(curve_indices).ravel()
    df["curve_index"] = curve_indices
    

    在回调函数中,每个实例的数据帧中的正确索引可以使用

    来识别
     df_index = df[(df.label == curve) & (df.curve_index == num)].index[0]
    

    【讨论】:

    • 将颜色列从数字更改为字符串后遇到了同样的问题。这应该在某个地方的文档中!
    猜你喜欢
    • 2019-08-13
    • 2021-11-04
    • 2015-02-17
    • 2021-10-05
    • 2018-11-08
    • 2018-11-11
    • 1970-01-01
    • 1970-01-01
    • 2021-05-11
    相关资源
    最近更新 更多