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

如何在Dash应用中绘制Sankey桑基图并解决回调返回值报错问题

报错修复方法

你遇到的dash.exceptions.InvalidCallbackReturnValue报错由两个问题引发:

  1. 布局中id="output_container"的组件被你注释删除了,但回调中仍然保留了该输出项,Dash找不到对应接收值的组件
  2. 回调返回值顺序和声明的输出顺序不匹配:你声明的输出顺序是[container内容, 图表figure],但函数返回的是(fig, container),值完全错位

业务逻辑修复

原有桑基图生成逻辑不符合需求,还需要做以下调整:

  • 修复数据筛选逻辑:保留选中标签关联的数据,同时增加value>=用户选择阈值的过滤条件
  • 桑基图的source、target必须为节点列表的索引值,不能直接传入字符串标签
  • 增加年份分层节点,实现不同年份的标签流向展示

完整可运行代码

import pandas as pd
import plotly.graph_objects as go
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import numpy as np 
from dash import Dash

app = Dash(__name__)

# 直接嵌入数据集,无需读外部csv
data = [
    ["cs.AI",1.00,1990],["cs.AI",0.20,1990],["cs.AI",0.85,1990],["cs.AI",0.99,1990],["cs.AI",0.19,1990],["cs.AI",0.87,1990],
    ["cs.CC",0.19,1990],["cs.CC",1.00,1990],["cs.CC",0.34,1990],["cs.CC",0.50,1990],["cs.CC",0.09,1990],["cs.CC",0.67,1990],
    ["cs.CE",0.94,1990],["cs.CE",0.63,1990],["cs.CE",1.00,1990],["cs.CE",0.61,1990],["cs.CE",0.82,1990],["cs.CE",0.17,1990],
    ["cs.CG",0.74,1990],["cs.CG",0.95,1990],["cs.CG",0.53,1990],["cs.CG",1.00,1990],["cs.CG",0.43,1990],["cs.CG",0.10,1990],
    ["cs.CL",0.31,1990],["cs.CL",0.27,1990],["cs.CL",0.91,1990],["cs.CL",0.21,1990],["cs.CL",1.00,1990],["cs.CL",0.12,1990],
    ["cs.CR",0.31,1990],["cs.CR",0.18,1990],["cs.CR",0.76,1990],["cs.CR",0.35,1990],["cs.CR",0.67,1990],["cs.CR",1.00,1990],
    ["cs.AI",1.00,1991],["cs.AI",0.55,1991],["cs.AI",0.82,1991],["cs.AI",0.05,1991],["cs.AI",0.17,1991],["cs.AI",0.83,1991],
    ["cs.CC",0.52,1991],["cs.CC",1.00,1991],["cs.CC",0.64,1991],["cs.CC",1.00,1991],["cs.CC",0.80,1991],["cs.CC",0.21,1991],
    ["cs.CE",0.10,1991],["cs.CE",0.58,1991],["cs.CE",1.00,1991],["cs.CE",0.01,1991],["cs.CE",0.77,1991],["cs.CE",0.19,1991],
    ["cs.CG",0.08,1991],["cs.CG",0.21,1991],["cs.CG",0.63,1991],["cs.CG",1.00,1991],["cs.CG",0.34,1991],["cs.CG",0.60,1991],
    ["cs.CL",0.91,1991],["cs.CL",0.33,1991],["cs.CL",0.60,1991],["cs.CL",0.57,1991],["cs.CL",1.00,1991],["cs.CL",0.37,1991],
    ["cs.CR",1.00,1991],["cs.CR",0.28,1991],["cs.CR",0.92,1991],["cs.CR",0.47,1991],["cs.CR",0.53,1991],["cs.CR",1.00,1991],
    ["cs.AI",1.00,1992],["cs.AI",0.79,1992],["cs.AI",0.86,1992],["cs.AI",0.30,1992],["cs.AI",0.27,1992],["cs.AI",0.91,1992],
    ["cs.CC",0.06,1992],["cs.CC",1.00,1992],["cs.CC",0.72,1992],["cs.CC",0.44,1992],["cs.CC",0.31,1992],["cs.CC",0.75,1992],
    ["cs.CE",0.40,1992],["cs.CE",0.07,1992],["cs.CE",1.00,1992],["cs.CE",0.88,1992],["cs.CE",0.79,1992],["cs.CE",0.03,1992],
    ["cs.CG",0.74,1992],["cs.CG",0.91,1992],["cs.CG",1.00,1992],["cs.CG",1.00,1992],["cs.CG",0.68,1992],["cs.CG",0.22,1992],
    ["cs.CL",0.42,1992],["cs.CL",0.03,1992],["cs.CL",0.95,1992],["cs.CL",0.17,1992],["cs.CL",1.00,1992],["cs.CL",0.28,1992],
    ["cs.CR",0.04,1992],["cs.CR",0.30,1992],["cs.CR",0.26,1992],["cs.CR",0.80,1992],["cs.CR",0.90,1992],["cs.CR",1.00,1992]
]
df = pd.DataFrame(data, columns=["Label1", "value", "year"])

app.layout = html.Div([
    html.H1("标签年份流向桑基图", style={'text-align': 'center'}),
    dcc.Dropdown(id="slct_label",
                  options=[{'label': x, 'value': x} for x in sorted(df["Label1"].unique())],
                 multi=False,
                 value="cs.AI",
                 style={'width': "30%"}
                 ),
    html.Br(),
    dcc.Dropdown(id="slct_value",
                  options=[{'label': x, 'value': x} for x in sorted(df[df["value"] >= 0.75]["value"].unique())],
                 multi=False,
                 value=0.75,
                 style={'width': "40%"},
                 placeholder="Select threshold"
                 ),
    html.Div(id='output_container', children=[]),
    html.Br(),
    dcc.Graph(id='my_bee_map', figure={})
])

@app.callback(
    [Output(component_id='output_container', component_property='children'),
     Output(component_id='my_bee_map', component_property='figure')],
    [Input(component_id='slct_label', component_property='value'),
    Input(component_id='slct_value', component_property='value')]
)
def update_graph(slct_label, slct_value):
    container = "当前选中标签:{},阈值:{}".format(slct_label, slct_value)
    # 筛选符合条件的数据
    dff = df[(df['Label1'] == slct_label) & (df['value'] >= slct_value)].copy()
    if dff.empty:
        return container, go.Figure()
    
    # 构建节点:格式为 年份_标签
    nodes = []
    for year in sorted(dff['year'].unique()):
        for label in [slct_label]:
            node_name = f"{year}_{label}"
            if node_name not in nodes:
                nodes.append(node_name)
    # 增加关联标签节点
    for idx, row in dff.iterrows():
        node_name = f"{row['year']}_关联标签"
        if node_name not in nodes:
            nodes.append(node_name)
    
    # 构建边
    source = []
    target = []
    value = []
    color = []
    year_list = sorted(dff['year'].unique())
    color_pool = ['#a6cee3','#fdbf6f','#fb9a99','#e3a6ce','#a6e3da']
    
    for i in range(len(year_list)-1):
        y1 = year_list[i]
        y2 = year_list[i+1]
        # 同标签跨年流向
        s_idx = nodes.index(f"{y1}_{slct_label}")
        t_idx = nodes.index(f"{y2}_{slct_label}")
        source.append(s_idx)
        target.append(t_idx)
        value.append(dff[dff['year'] == y1]['value'].sum())
        color.append(color_pool[i%len(color_pool)])
        # 当年关联标签流向
        s_idx = nodes.index(f"{y1}_{slct_label}")
        t_idx = nodes.index(f"{y1}_关联标签")
        source.append(s_idx)
        target.append(t_idx)
        value.append(dff[dff['year'] == y1]['value'].sum() * 0.3)
        color.append(color_pool[i%len(color_pool)])
    
    # 最后一年的关联标签
    last_y = year_list[-1]
    s_idx = nodes.index(f"{last_y}_{slct_label}")
    t_idx = nodes.index(f"{last_y}_关联标签")
    source.append(s_idx)
    target.append(t_idx)
    value.append(dff[dff['year'] == last_y]['value'].sum() * 0.3)
    color.append(color_pool[-1])
    
    # 生成桑基图
    link = dict(source=source, target=target, value=value, color=color)
    node = dict(label=[n.split('_')[1] if '关联' not in n else n.split('_')[1] for n in nodes], pad=35, thickness=15)
    data = go.Sankey(link=link, node=node)
    
    fig = go.Figure(data)
    fig.update_layout(
        hovermode= 'x',
        title = f'{slct_label} 标签年份流向',
        font=dict(size=10,color='white'),
        paper_bgcolor='#51504f'
    )
    # 注意返回顺序要和输出声明顺序一致
    return container, fig

if __name__ == '__main__':
    app.run_server(debug=True)

内容的提问来源于stack exchange,提问作者chuky pedro

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 19:36:04