Plotly Dash散点图悬停时多节点pointNumber重复问题求助
问题原因
这不是Plotly的BUG,属于正常设计逻辑:
- 当
px.scatter的color参数传入离散型分类值时,Plotly Express会自动为每个分类生成独立的trace(数据序列) - 每个trace内部的
pointNumber、pointIndex都是独立从0开始计数的,仅代表该点在所属trace内的位置,和全局DataFrame的索引没有对应关系 - 传入数值型
label时所有数据都在同一个trace里,所以pointNumber和全局索引对应,但是会触发连续色阶图例,不符合分类筛选需求
解决方案
最稳妥的实现方式是通过customdata参数把全局索引绑定到每个散点上,无需依赖pointNumber和curveNumber做关联映射,修改代码的核心位置如下:
- 生成散点图时新增
custom_data参数,传入DataFrame的全局索引 - 回调函数中直接从
hoverData中取出绑定的全局索引,再查询原DataFrame
完整可运行修改后代码
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 # Setup plotly scatter plot,新增custom_data绑定全局索引 fig = px.scatter(df, x="feat1", y="feat2", color="color", custom_data=[df.index]) 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 hover_data = hoverData["points"][0] bbox = hover_data["bbox"] # 从customdata中取绑定的全局索引 global_idx = hover_data["customdata"][0] children = [html.Div([html.Img(style={"height": "50px", "width": "50px", "display": "block", "margin": "0 auto"}), html.P("Feat1: {}".format(str(df.loc[global_idx]["feat1"]))), html.P("Feat2: {}".format(str(df.loc[global_idx]["feat2"])))])] return True, bbox, children if __name__ == "__main__": app.run_server(mode="inline", debug=True)
验证效果
修改后悬停索引31的setosa类样本和索引131的virginica类样本时,会分别取出对应的全局索引查询数据,返回正确的信息,同时保留离散分类图例的筛选功能。
内容的提问来源于stack exchange,提问作者C.S.
相关产品推荐
相关产品推荐

