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

Dash中Plotly Treemap仅子容器显示Hover信息的实现问题

解决Dash中Treemap父容器悬停异常的两种方案

针对你遇到的Treemap父容器悬停格式异常问题,以下两种方案可直接在Dash回调返回figure的场景下实现需求:

方案一:完全禁用父容器的悬停效果

方法1:通过Trace属性直接控制

在生成Treemap时,针对父节点单独设置hoverinfo='none',子节点保留正常悬停配置。需要根据你的数据结构判断父节点(示例中以parents数组为空字符串作为父节点标识):

import plotly.graph_objects as go

def update_treemap_figure():
    # 假设你的数据定义如下
    labels = ["A股总市值", "科技板块", "金融板块", "腾讯", "阿里", "工行", "招行"]
    parents = ["", "A股总市值", "A股总市值", "科技板块", "科技板块", "金融板块", "金融板块"]
    values = [500000, 200000, 300000, 120000, 80000, 180000, 120000]
    
    # 生成Treemap trace,为父节点设置hoverinfo为none
    fig = go.Figure(go.Treemap(
        labels=labels,
        parents=parents,
        values=values,
        # 动态设置每个节点的hoverinfo:父节点禁用,子节点正常显示
        hoverinfo=[
            'none' if p == "" else 'label+value+percent parent' 
            for p in parents
        ]
    ))
    return fig

方法2:通过PostScript前端控制

如果数据结构复杂,可在figure中添加PostScript代码,前端判断父节点并隐藏tooltip:

def update_treemap_figure():
    labels = ["A股总市值", "科技板块", "金融板块", "腾讯", "阿里", "工行", "招行"]
    parents = ["", "A股总市值", "A股总市值", "科技板块", "科技板块", "金融板块", "金融板块"]
    values = [500000, 200000, 300000, 120000, 80000, 180000, 120000]
    
    fig = go.Figure(go.Treemap(
        labels=labels,
        parents=parents,
        values=values,
        hoverinfo='label+value+percent parent'
    ))
    
    # 添加PostScript实现父节点悬停禁用
    fig.update_layout(
        post_script=f"""
        const treemap = document.querySelector('.treemap');
        if (treemap) {{
            treemap.addEventListener('mouseover', (e) => {{
                const node = e.target.closest('.trace .treemap-node');
                if (!node) return;
                const nodeIndex = parseInt(node.getAttribute('data-point-index'));
                const parents = {parents};
                // 判断是否为父节点(根据你的数据逻辑调整)
                if (parents[nodeIndex] === "") {{
                    const tooltip = document.querySelector('.plotly-tooltip');
                    if (tooltip) tooltip.style.display = 'none';
                }}
            }});
        }}
        """
    )
    return fig

方案二:自定义父容器的悬停内容

方法1:生成Trace时自定义Hovertext

提前为父节点设置格式化的悬停文本,子节点保留原有逻辑:

def update_treemap_figure():
    labels = ["A股总市值", "科技板块", "金融板块", "腾讯", "阿里", "工行", "招行"]
    parents = ["", "A股总市值", "A股总市值", "科技板块", "科技板块", "金融板块", "金融板块"]
    values = [500000, 200000, 300000, 120000, 80000, 180000, 120000]
    
    # 预计算父节点的汇总数据
    parent_totals = {}
    # 计算根节点总价值
    parent_totals[""] = sum(values)
    # 计算各子板块总价值
    for parent in set(parents) - {""}:
        parent_totals[parent] = sum(v for l, p, v in zip(labels, parents, values) if p == parent)
    
    # 生成自定义hovertext
    hovertext = []
    for l, p, v in zip(labels, parents, values):
        if p == "":
            # 根节点(父容器)的自定义悬停文本
            hovertext.append(f"板块:{l}<br>总市值:{v}亿元<br>占全市场比例:{round(v/parent_totals['']*100, 2)}%")
        else:
            # 子节点的正常悬停文本
            hovertext.append(f"股票:{l}<br>市值:{v}亿元<br>占板块比例:{round(v/parent_totals[p]*100, 2)}%")
    
    fig = go.Figure(go.Treemap(
        labels=labels,
        parents=parents,
        values=values,
        hovertext=hovertext,
        hoverinfo='text'  # 使用自定义的hovertext
    ))
    return fig

方法2:通过PostScript修改Tooltip内容

在前端动态修改父节点的tooltip显示内容:

def update_treemap_figure():
    labels = ["A股总市值", "科技板块", "金融板块", "腾讯", "阿里", "工行", "招行"]
    parents = ["", "A股总市值", "A股总市值", "科技板块", "科技板块", "金融板块", "金融板块"]
    values = [500000, 200000, 300000, 120000, 80000, 180000, 120000]
    
    parent_totals = {}
    parent_totals[""] = sum(values)
    for parent in set(parents) - {""}:
        parent_totals[parent] = sum(v for l, p, v in zip(labels, parents, values) if p == parent)
    
    fig = go.Figure(go.Treemap(
        labels=labels,
        parents=parents,
        values=values,
        hoverinfo='label+value+percent parent'
    ))
    
    fig.update_layout(
        post_script=f"""
        const treemap = document.querySelector('.treemap');
        if (treemap) {{
            treemap.addEventListener('mouseover', (e) => {{
                const node = e.target.closest('.trace .treemap-node');
                if (!node) return;
                const nodeIndex = parseInt(node.getAttribute('data-point-index'));
                const parents = {parents};
                const labels = {labels};
                const values = {values};
                const parentTotals = {parent_totals};
                
                if (parents[nodeIndex] === "") {{
                    const tooltip = document.querySelector('.plotly-tooltip');
                    if (tooltip) {{
                        tooltip.innerHTML = `
                            <div>板块:${labels[nodeIndex]}</div>
                            <div>总市值:${values[nodeIndex]}亿元</div>
                            <div>占全市场比例:${Math.round(values[nodeIndex]/parentTotals['']*100,2)}%</div>
                        `;
                    }}
                }}
            }});
        }}
        """
    )
    return fig

注意事项

  • 以上示例中判断父节点的逻辑(parents[nodeIndex] === "")需根据你的实际数据结构调整,比如部分场景下父节点的parent字段为null或其他标识。
  • PostScript方案需确保页面中Treemap的选择器(.treemap)正确,若存在多个图表可通过data-div-id定位特定图表。

内容的提问来源于stack exchange,提问作者Satyajit Giram

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 08:50:24