You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Plotly graph_objects 3D散点子图hovertemplate不识别customdata

问题背景

参考Plotly官方子图教程构建包含两个3D散点图的可视化,基础绘图搭建完成后hovertemplate功能始终无法正常生效。
基础绘图效果

原本沿用单Scatter3D图(直接构建、不通过graph_objects创建)中验证可用的配置逻辑:传入与待渲染点数量一致的customdata数组,预期实现customdata与体素1:1对应,悬停时展示对应字段值;但实际悬停时仅显示hovertemplate参数设置的字面字符串,不会替换占位符内容。

问题复现代码如下:

import plotly.graph_objects as go
from plotly.subplots import make_subplots
import json 
import pandas as pd
import numpy as np

json_data = {}
with open("voxels_with_calculated.json", "r") as in_file:
    json_data = json.load(in_file)
json_df = pd.DataFrame(json_data)

# 单条数据格式示例
#{
#   "x": 1,
#   "y": -31,
#   "z": -63,
#   "M": -1,
#   "E": -1,
#   "F": -1,
#   "CE": -1,
#   "MA": -1,
#   "R": -1
#}

x,y,z = json_df.x, json_df.y, json_df.z

fig = make_subplots(
    rows=1, 
    cols=2, 
    specs=[[{"type": "scatter3d"}, {"type": "scatter3d"}]],
    subplot_titles=["Original Voxels", "Voxels to World"]
)

fig.add_trace(
    go.Scatter3d(
    x=x,
    y=y,
    z=z,
    customdata=[json_df.M, json_df.E, json_df.F, json_df.CE, json_df.MA, json_df.R],
    hovertemplate="<b> dfdfd %{customdata[0]}</b> ",
    mode='markers'
),
    row=1, col=1
)

fig.add_trace(
    go.Scatter3d(
    x=x,
    y=y,
    z=z,
    customdata=[json_df.M, json_df.E, json_df.F, json_df.CE, json_df.MA, json_df.R],
    hovertemplate="<b> HAHA %{customdata}</b>",
    mode='markers'
),
    row=1, col=2
)

"""
# 单图(不通过graph_objects创建)场景下可用的配置
fig.update_traces(
    hovertemplate="<br>".join([
        "M: %{customdata[0]}",
        "E: %{customdata[1]}",
        "F: %{customdata[2]}",
        "CE: %{customdata[3]}",
        "MA: %{customdata[4]}",
        "R: %{customdata[5]}",
        "U: %{customdata[6]}"
    ])
)
"""

fig.show()

无论如何调整配置,鼠标悬停时都仅显示字面的%{customdata}字符串,单图场景下可用的update_traces配置hovertemplate的写法在子图场景下也无法生效。
异常悬停效果1
异常悬停效果2

故障原因

核心问题是customdata参数传入的数组形状不符合Plotly的要求:

  • 代码中传入的[json_df.M, json_df.E, json_df.F, json_df.CE, json_df.MA, json_df.R]是按列拼接的6个Series,整体形状为(自定义字段数, 点数量)
  • Plotly要求customdata的形状必须为(点数量, 自定义字段数),即每一行对应一个渲染点的所有自定义字段,每一列对应一个自定义字段的所有点值

单图场景下Plotly会自动对形状不符的customdata做转置容错,但子图场景下该自动容错逻辑不触发,直接导致hovertemplate中的占位符无法被解析,原样输出字符串。

修复方案

调整customdata的传入格式,保证数组形状匹配即可,不需要修改其他子图配置:

  • 直接从DataFrame中选取需要的字段列,转为numpy数组传入,会自动生成符合形状要求的(点数量, 字段数)结构
  • 可在hovertemplate末尾添加<extra></extra>,隐藏悬停框侧边默认显示的trace名称,优化展示效果

修复后的trace添加代码示例:

fig.add_trace(
    go.Scatter3d(
        x=x,
        y=y,
        z=z,
        # 修正customdata形状,直接取对应列的数组即可
        customdata=json_df[["M", "E", "F", "CE", "MA", "R"]].values,
        hovertemplate="<br>".join([
            "<b>Original Voxels</b>",
            "M: %{customdata[0]}",
            "E: %{customdata[1]}",
            "F: %{customdata[2]}",
            "CE: %{customdata[3]}",
            "MA: %{customdata[4]}",
            "R: %{customdata[5]}",
            "<extra></extra>"
        ]),
        mode='markers'
    ),
    row=1, col=1
)

# 第二个子图的trace做相同修改即可
fig.add_trace(
    go.Scatter3d(
        x=x,
        y=y,
        z=z,
        customdata=json_df[["M", "E", "F", "CE", "MA", "R"]].values,
        hovertemplate="<br>".join([
            "<b>Voxels to World</b>",
            "M: %{customdata[0]}",
            "E: %{customdata[1]}",
            "F: %{customdata[2]}",
            "CE: %{customdata[3]}",
            "MA: %{customdata[4]}",
            "R: %{customdata[5]}",
            "<extra></extra>"
        ]),
        mode='markers'
    ),
    row=1, col=2
)

修改后悬停时即可正常替换占位符,展示对应点的自定义字段值。

内容的提问来源于stack exchange,提问作者J. Maria

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 00:33:22