使用Dash上传组件时如何用Plotly Express渲染图表?
解决Dash Upload组件未上传文件时的UnboundLocalError问题
解决这个错误的核心是确保df变量在所有代码分支中都有定义,或者在未上传文件时直接返回合法的图表对象,以下是两种实用方案:
方案一:提前初始化空DataFrame
在回调函数开头就定义一个空的DataFrame,后续只有在上传文件时才覆盖它。这样即使没有上传文件,px.line也能拿到合法的DataFrame对象(空的),不会触发变量未定义错误。
import pandas as pd import base64 import io from dash import Dash, dcc, html, Input, Output import plotly.express as px app = Dash(__name__) app.layout = html.Div([ dcc.Upload( id='upload-data', children=html.Div(['拖拽文件到这里,或 ', html.A('选择文件')]), style={ 'width': '100%', 'height': '60px', 'lineHeight': '60px', 'borderWidth': '1px', 'borderStyle': 'dashed', 'borderRadius': '5px', 'textAlign': 'center', 'margin': '10px' }, ), dcc.Graph(id='line-plot') ]) @app.callback( Output('line-plot', 'figure'), Input('upload-data', 'contents'), State('upload-data', 'filename') ) def update_lineplot(contents, filename): # 提前初始化空DataFrame,确保变量始终存在 df = pd.DataFrame() if contents: # 解析上传的文件内容 content_type, content_string = contents.split(',') decoded = base64.b64decode(content_string) try: if 'csv' in filename: df = pd.read_csv(io.StringIO(decoded.decode('utf-8'))) elif 'xls' in filename: df = pd.read_excel(io.BytesIO(decoded)) except Exception as e: print(e) return px.line(title="文件解析失败,请检查文件格式") # 使用df生成折线图,空DataFrame会显示空图表 fig = px.line(df, x='日期', y='数值', title='数据趋势图') return fig if __name__ == '__main__': app.run_server(debug=True)
方案二:未上传时直接返回提示图表
在回调开头判断如果没有上传内容,直接返回一个带提示信息的空图表,跳过后续需要df的代码逻辑,从根源避免变量未定义的问题。
import pandas as pd import base64 import io from dash import Dash, dcc, html, Input, Output import plotly.express as px app = Dash(__name__) app.layout = html.Div([ dcc.Upload( id='upload-data', children=html.Div(['拖拽文件到这里,或 ', html.A('选择文件')]), style={ 'width': '100%', 'height': '60px', 'lineHeight': '60px', 'borderWidth': '1px', 'borderStyle': 'dashed', 'borderRadius': '5px', 'textAlign': 'center', 'margin': '10px' }, ), dcc.Graph(id='line-plot') ]) @app.callback( Output('line-plot', 'figure'), Input('upload-data', 'contents'), State('upload-data', 'filename') ) def update_lineplot(contents, filename): # 未上传文件时直接返回提示图表 if not contents: return px.line(title="请上传CSV或Excel格式的数据文件") # 解析上传的文件内容 content_type, content_string = contents.split(',') decoded = base64.b64decode(content_string) try: if 'csv' in filename: df = pd.read_csv(io.StringIO(decoded.decode('utf-8'))) elif 'xls' in filename: df = pd.read_excel(io.BytesIO(decoded)) except Exception as e: print(e) return px.line(title="文件解析失败,请检查文件格式") fig = px.line(df, x='日期', y='数值', title='数据趋势图') return fig if __name__ == '__main__': app.run_server(debug=True)
两种方案都能解决问题,你可以根据需求选择:方案一逻辑更统一,方案二的提示更直观,用户能清楚知道需要上传文件。
内容的提问来源于stack exchange,提问作者dspractician
相关产品推荐
相关产品推荐

