Dash Python中图表未与Callback交互问题排查
问题诊断与解决方案
核心问题分析
你的Dash图表无数据显示,但调用show()能在新标签页打开,主要有以下几个关键问题:
- 布局中缺少目标Graph组件:回调指定输出到
id='fatPrevLinhas'的figure属性,但代码里未展示布局中是否添加了dcc.Graph(id='fatPrevLinhas'),这是图表无法渲染的最直接原因。 - 多选项Dropdown初始值格式错误:当
Dropdown设置multi=True时,value必须是列表类型(比如["Todos"]),而你用了字符串"Todos",会导致初始回调逻辑异常。 - 数据生成依赖未定义:代码中
random.choices(departamentos, ...)里的departamentos、categorias、produtos三个列表未定义,运行时会抛出NameError,导致DataFrame生成失败。
分步修复方案
1. 补充布局中的Graph组件
在Dash应用布局里,必须添加对应id的dcc.Graph组件,示例如下:
app.layout = dbc.Container([ dbc.Row([filter1]), # 放入你的筛选器 dbc.Row([ dbc.Col([ dcc.Graph(id='fatPrevLinhas') # 必须添加这个组件,回调才能输出图表 ]) ]) ])
2. 修正Dropdown的初始值
将Dropdown的value改为列表格式:
dcc.Dropdown( id="filtroDepartamento", className="filtro", options=[{'label':'Todos', 'value': 'Todos'}, {'label':'Acessórios', 'value': 'Acessórios'}, {'label':'Colchões', 'value': 'Colchões'}, {'label':'Enxoval', 'value': 'Enxoval'}, {'label':'Móveis', 'value': 'Móveis'}, {'label':'Puericultura Leve', 'value': 'Puericultura Leve'}, {'label':'Puericultura Pesada', 'value': 'Puericultura Pesada'}], value=["Todos"], # 改为列表,适配multi=True multi=True )
3. 定义数据生成依赖的列表
在DataFrame生成前,添加departamentos、categorias、produtos的定义:
# 定义缺失的列表变量 departamentos = ['Acessórios', 'Colchões', 'Enxoval', 'Móveis', 'Puericultura Leve', 'Puericultura Pesada'] categorias = ['Categoria1', 'Categoria2', 'Categoria3'] # 可根据需求修改 produtos = ['ProdutoA', 'ProdutoB', 'ProdutoC'] # 可根据需求修改
完整修正后的代码
import datetime import pandas as pd import random import numpy as np import dash import dash_core_components as dcc import dash_html_components as html import dash_bootstrap_components as dbc import plotly.graph_objects as go from dash.dependencies import Input, Output # 初始化Dash应用 app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP]) # 定义缺失的列表变量 departamentos = ['Acessórios', 'Colchões', 'Enxoval', 'Móveis', 'Puericultura Leve', 'Puericultura Pesada'] categorias = ['Categoria1', 'Categoria2', 'Categoria3'] produtos = ['ProdutoA', 'ProdutoB', 'ProdutoC'] # Create a dataframe start_date_str = '2023-04-01' end_date_str = datetime.date.today().strftime('%Y-%m-%d') datas = pd.date_range(start=start_date_str, end=end_date_str, freq='D').to_list() fatData = pd.DataFrame(index=datas) fatData['Departamento'] = random.choices(departamentos, k=len(fatData)) fatData['Categoria'] = random.choices(categorias, k=len(fatData)) fatData['Produto'] = random.choices(produtos, k=len(fatData)) fatData['Faturamento'] = np.random.randint(500000, 900000, size=len(datas)) fatData['Previsão'] = np.random.randint(600000, 800000, size=len(datas)) fatData = fatData.reset_index() fatData = fatData.rename(columns={'index': 'Data'}) #Create a filter filter1 = dbc.Col([ html.Label('Departamento', className='title_filter'), dcc.Dropdown( id="filtroDepartamento", className="filtro", options=[{'label':'Todos', 'value': 'Todos'}, {'label':'Acessórios', 'value': 'Acessórios'}, {'label':'Colchões', 'value': 'Colchões'}, {'label':'Enxoval', 'value': 'Enxoval'}, {'label':'Móveis', 'value': 'Móveis'}, {'label':'Puericultura Leve', 'value': 'Puericultura Leve'}, {'label':'Puericultura Pesada', 'value': 'Puericultura Pesada'}], value=["Todos"], # 修正为列表格式 multi=True ) ], className='filter text-center') # 定义应用布局 app.layout = dbc.Container([ dbc.Row([filter1], className="my-3"), dbc.Row([ dbc.Col([ dcc.Graph(id='fatPrevLinhas') # 添加目标Graph组件 ]) ]) ], fluid=True) #Callback @app.callback( Output('fatPrevLinhas', 'figure'), Input('filtroDepartamento', 'value') ) def update_my_graph(departamento): if len(departamento) > 0: if 'Todos' in departamento: dff = fatData else: dff = fatData[fatData["Departamento"].isin(departamento)] fatPrevLinhas = go.Figure() fatPrevLinhas.add_trace(go.Scatter(x=dff['Data'], y=dff['Previsão'], mode='lines', name='Previsão', line=dict(color='gray', width=2, dash='dash'))) fatPrevLinhas.add_trace(go.Scatter(x=dff['Data'], y=dff['Faturamento'], mode='lines', name='Faturamento', line=dict(color='blue', width=2))) fatPrevLinhas.update_layout( title_text='Faturamento vs Previsão', xaxis_title='Data', yaxis_title='Faturamento (R$)' ) return fatPrevLinhas elif len(departamento) == 0: raise dash.exceptions.PreventUpdate # 运行应用 if __name__ == '__main__': app.run_server(debug=True)
内容的提问来源于stack exchange,提问作者Adriel Moreira
相关产品推荐
相关产品推荐

