Plotly Dash报figure.data参数非法传入错误排查
问题描述
- 基于Plotly Dash搭建交互式数据看板,预期支持xy、xyy、xyyy等结构的数据集上传,自动生成对应折线图
- 上传数据后触发固定报错:
Invalid argumentfigure.datapassed into Graph - 相关参考材料:
- 参考教程:使用Plotly Dash搭建交互式数据应用
- 报错截图:

- 测试用样例数据预览:

原始问题代码
import base64 import datetime import io import plotly.graph_objs as go import cufflinks as cf import dash from dash.dependencies import Input, Output, State import dash_core_components as dcc import dash_html_components as html import dash_table import pandas as pd external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css'] app = dash.Dash(__name__, external_stylesheets=external_stylesheets) server = app.server colors = { "graphBackground": "#F5F5F5", "background": "#ffffff", "text": "#000000" } app.layout = html.Div([ dcc.Upload( id='upload-data', children=html.Div([ 'Drag and Drop or ', html.A('Select Files') ]), style={ 'width': '100%', 'height': '60px', 'lineHeight': '60px', 'borderWidth': '1px', 'borderStyle': 'dashed', 'borderRadius': '5px', 'textAlign': 'center', 'margin': '10px' }, multiple=True ), dcc.Graph(id='Mygraph'), html.Div(id='output-data-upload') ]) def parse_data(contents, filename): 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)) elif 'txt' or 'tsv' in filename: df = pd.read_csv( io.StringIO(decoded.decode('utf-8')), delimiter = r'\s+') except Exception as e: print(e) return html.Div([ 'There was an error processing this file.' ]) return df @app.callback(Output('Mygraph', 'figure'), [ Input('upload-data', 'contents'), Input('upload-data', 'filename') ]) def update_graph(contents, filename): fig = { 'layout': go.Layout( plot_bgcolor=colors["graphBackground"], paper_bgcolor=colors["graphBackground"]) } if contents: contents = contents[0] filename = filename[0] df = parse_data(contents, filename) df = df.set_index(df.columns[0]) fig['data'] = df.iplot(asFigure=True, kind='scatter', mode='lines+markers', size=1) return fig @app.callback(Output('output-data-upload', 'children'), [ Input('upload-data', 'contents'), Input('upload-data', 'filename') ]) def update_table(contents, filename): table = html.Div() if contents: contents = contents[0] filename = filename[0] df = parse_data(contents, filename) table = html.Div([ html.H5(filename), dash_table.DataTable( data=df.to_dict('rows'), columns=[{'name': i, 'id': i} for i in df.columns] ), html.Hr(), html.Div('Raw Content'), html.Pre(contents[0:200] + '...', style={ 'whiteSpace': 'pre-wrap', 'wordBreak': 'break-all' }) ]) return table if __name__ == '__main__': app.run_server(debug=True)
问题根因
代码存在4个核心问题,直接触发参数非法报错:
- Figure对象赋值错误:cufflinks的
iplot(asFigure=True)方法返回的是完整的Plotly Figure对象,本身已经包含data(轨迹列表)和layout(布局配置)两个顶级属性。原代码把整个Figure对象直接赋值给fig['data']字段,相当于给要求传入轨迹列表的data参数塞了个完整图结构,直接触发参数类型校验失败。 - 文件解析逻辑bug:
elif 'txt' or 'tsv' in filename是Python常见逻辑写法错误,非空字符串'txt'的布尔值恒为True,该分支会被所有文件触发,导致csv、excel文件也会按空白符分隔的txt规则解析,极易出现数据解析异常。 - 回调返回值缺失:
update_graph回调在没有上传文件的初始加载状态下,没有显式返回默认的fig对象,会返回None,也会触发组件参数报错。 - 未初始化cufflinks离线模式,部分环境下iplot生成的图结构会缺少必要配置。
修复方案
按以下步骤修改代码即可解决问题:
- 导入cufflinks后添加离线模式初始化配置
cf.go_offline() - 修正文件解析分支的判断逻辑,把txt/tsv的判断改为
elif 'txt' in filename or 'tsv' in filename,解析异常时返回空DataFrame而非html组件,避免后续图形渲染逻辑拿到非表格对象报错 - 调整图形生成逻辑:直接使用cufflinks生成的完整Figure对象,再更新自定义的背景色布局配置,不要把整个Figure赋值给data字段
- 补全回调的默认返回值,确保无上传内容时也返回合法的空图结构
修复后的核心代码片段:
# 导入cufflinks后添加离线初始化 cf.go_offline() # 修正parse_data逻辑 def parse_data(contents, filename): 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)) elif 'txt' in filename or 'tsv' in filename: df = pd.read_csv(io.StringIO(decoded.decode('utf-8')), delimiter=r'\s+') except Exception as e: print(e) return pd.DataFrame() return df # 修正图形回调逻辑 @app.callback(Output('Mygraph', 'figure'), [Input('upload-data', 'contents'),Input('upload-data', 'filename')]) def update_graph(contents, filename): # 初始化默认空图 fig = go.Figure() fig.update_layout( plot_bgcolor=colors["graphBackground"], paper_bgcolor=colors["graphBackground"] ) if contents: contents = contents[0] filename = filename[0] df = parse_data(contents, filename) if not df.empty: df = df.set_index(df.columns[0]) # 生成完整图对象 fig = df.iplot(asFigure=True, kind='scatter', mode='lines+markers', size=1) # 合并自定义背景配置 fig.update_layout( plot_bgcolor=colors["graphBackground"], paper_bgcolor=colors["graphBackground"] ) # 所有分支均返回合法fig对象 return fig
修复后即可正常上传xy、xyy、xyyy结构的表格文件,自动生成多系列折线图,不会再出现figure.data参数非法的报错。
内容的提问来源于stack exchange,提问作者Ritesh Kankonkar
相关产品推荐
相关产品推荐

