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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 05:50:26