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

Plotly Dash上传按钮无响应问题求助

Plotly Dash上传按钮无响应问题排查与解决

问题背景

数月前正常运行的Plotly Dash代码,当前点击Upload按钮无任何响应,无报错信息;复制官方Upload组件示例代码测试,问题依旧。

提交代码

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = Dash(__name__, external_stylesheets=external_stylesheets)

# if deploy onto a server
server = app.server


# create a background template for plots
templates = ['plotly', 'seaborn', 'simple_white', 'ggplot2',
             'plotly_white', 'plotly_dark', 'presentation', 'xgridoff',
             'ygridoff', 'gridon', 'none']


# create a blank figure to prevent plotly dash error when runnng the app, even though it still works without this.
def blankfigure():
    figure = go.Figure(go.Scatter(x=[],y=[]))
    figure.update_layout(template = None)
    figure.update_xaxes(showgrid = False, showticklabels = False, zeroline = False)
    figure.update_yaxes(showgrid = False, showticklabels = False, zeroline = False)

    return figure


app.layout = html.Div([
        
        # components for label and input content by user
        dbc.Row([dbc.Col(html.H1('Plotter App', style={'textAlign': 'center', "font-size":"60px"}))]), # title

        # components for upload file 
        dbc.Row([dbc.Col(html.Label('Upload file') ,style={'textAlign': 'left',"font-size":"30px"})]),
        dbc.Row([dcc.Upload(id='upload-data',children=html.Div(['Drag and Drop or ',html.A('Select Files')]),
                    style={
                        'width': '30%',
                        'height': '60px',
                        'lineHeight': '60px',
                        'borderWidth': '1px',
                        'borderStyle': 'dashed',
                        'borderRadius': '5px',
                        'textAlign': 'center',
                        'margin': '10px'
                            },
                        # Allow multiple files to be uploaded
                        multiple=False)
                ]),
        html.Div(id='output-data-upload', children = ''),    

        # component for radio button for show/hide table
        dbc.Row([dcc.RadioItems(id = 'show_hide_table_button', options = ['show_table', 'hide_table','show_plot'], value = 'hide')]),        
])

def parse_contents(contents, file_name): # 'contents/filename' property is needed for callbacks
    
    content_type, content_string = contents.split(',')
    #print(content_type)
    
    decoded = base64.b64decode(content_string)
    #print(decoded)
   
    if 'csv' in file_name:
        # Assume that the user uploaded a CSV file
        df = pd.read_csv(io.StringIO(decoded.decode('utf-8')))
    elif 'xls' in file_name:
        # Assume that the user uploaded an excel file
        df = pd.read_excel(io.BytesIO(decoded))
    elif 'txt' in file_name:
        # Assume that the user uploaded an text file
        # 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte -> USE utf-16
        df = pd.read_csv(io.StringIO(decoded.decode('utf-16')), delimiter = '\t') # \t separates columns separated by tabs

    return df

@app.callback(
    Output('output-data-upload', 'children'),
    [Input('upload-data', 'contents'), # refer to first arg in upload_data_file()
    Input('upload-data', 'filename'), # refer to 2nd arg in upload_data_file()
    Input(component_id = 'show_hide_table_button', component_property = 'value')] # refer to 3rd arg in upload_data_file()
    
    #State('upload-data', 'last_modified'),
    #prevent_initial_call=True
)
    
def upload_data_file(contents, file_name, display):
    show_table = html.Div()
    show_plot = html.Div()
    
    global uploaded_df
    if contents is not None:
        uploaded_df = parse_contents(contents, file_name) # dataframe object
        dropdown = uploaded_df.columns
        show_table = html.Div([
                    dbc.Row([dbc.Col([html.H5(file_name)])]),
                    
                    # show data table
                    dbc.Row([dbc.Col([dash_table.DataTable(data=uploaded_df.to_dict('rows'), columns=[{"name": i, "id": i} for i in uploaded_df.columns])])]),
                    ])

        show_plot = html.Div([
            
                    # component for show dropdown options
                    dbc.Row([dbc.Col(html.Label('Select x-axis from dropdown'), width=2), #width = between Cols
                            dbc.Col(dcc.Dropdown(id = 'xaxis_column', options = dropdown, value = None)),
                            dbc.Col(html.Label('Select x-axis from dropdown'), width=2), #width = between Cols
                            dbc.Col(dcc.Dropdown(id = 'xaxis_column1', options = dropdown, value = None)),
                            ]),

                    dbc.Row([dbc.Col(html.Label('Select y-axis from dropdown'), width=2),
                            dbc.Col(dcc.Dropdown(id = 'yaxis_column', options = dropdown, value = None, multi = True)),
                            dbc.Col(html.Label('Select y-axis from dropdown'), width=2),
                            dbc.Col(dcc.Dropdown(id = 'yaxis_column1', options = dropdown, value = None, multi = True)),
                            ]),
            
                    # component for output graph(s) when data is uploaded
                    dbc.Row([dbc.Col(dcc.RadioItems(id='template', options = [{'label': k, 'value': k} for k in templates], value = None, inline=True)),
                            dbc.Col(dcc.RadioItems(id='template1', options = [{'label': k, 'value': k} for k in templates], value = None, inline=True)), # grid style
                            ]), # grid style
                    
                    html.Br(),
        
                    # components for graph, graph options, and download data from plot (for two plots)
                    dbc.Row([dbc.Col(dcc.Graph(id="graph", figure=blankfigure())),
                            dbc.Col(dcc.Graph(id="graph1", figure=blankfigure()))
                            ]),
                    dbc.Row([dbc.Col(dcc.Dropdown(id = 'plot_type', options = ['scatter,','line','bar','box'], value = 'line', style={'font-size':20})),
                            dbc.Col(dcc.Dropdown(id = 'plot_type1', options = ['scatter','line','bar','box'], value = 'line', style={'font-size':20})),
                            ]),
                    ])
    
                    
    # connecting radio button options with output of upload button
    if display == 'show': 
        return show_table
    if display == 'hide_table':
        return None
    if display == 'show_plot':
        return show_plot

排查方向及解决方案

  1. 依赖版本冲突
    检查Dash及相关依赖(dash-core-components、dash-html-components、dash-bootstrap-components等)的版本,数月前的版本可能与当前环境不兼容。建议锁定之前可用的版本,或逐步升级排查。

  2. 浏览器缓存干扰
    清除浏览器缓存,或使用无痕模式测试,避免旧的静态资源导致的异常。

  3. 代码逻辑缺陷

    • RadioItems初始值设为'hide',但回调判断逻辑中无对应分支,导致上传后无输出反馈。需将初始值改为'hide_table',或补充display == 'hide'的处理分支。
    • parse_contents函数对txt文件的编码处理过于绝对,部分txt文件可能为utf-8编码,建议添加异常捕获:
      elif 'txt' in file_name:
          try:
              df = pd.read_csv(io.StringIO(decoded.decode('utf-8')), delimiter='\t')
          except UnicodeDecodeError:
              df = pd.read_csv(io.StringIO(decoded.decode('utf-16')), delimiter='\t')
      
    • 全局变量uploaded_df易引发状态混乱,建议改用dcc.Store组件存储上传数据。
  4. 文件权限/大小限制
    若部署在服务器上,检查服务器的文件上传大小限制;本地环境则检查临时文件目录的读写权限。

修正后的核心回调逻辑示例

# 修改RadioItems初始值
dbc.Row([dcc.RadioItems(id='show_hide_table_button', options=['show_table', 'hide_table','show_plot'], value='hide_table')]),

# 修正回调判断逻辑
def upload_data_file(contents, file_name, display):
    show_table = html.Div()
    show_plot = html.Div()
    
    # 替换全局变量为dcc.Store,此处先保留原有逻辑,后续建议重构
    global uploaded_df
    if contents is not None:
        uploaded_df = parse_contents(contents, file_name)
        dropdown = uploaded_df.columns
        # ... 原有show_table、show_plot构建逻辑 ...
    
    # 补充全部分支判断
    if display == 'show_table': 
        return show_table
    elif display == 'hide_table':
        return None
    elif display == 'show_plot':
        return show_plot
    # 处理未匹配的情况
    return None

内容的提问来源于stack exchange,提问作者Wayne Wu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 16:45:06