Plotly添加Trace至子图时触发ValueError问题排查
Plotly子图添加数据触发ValueError的解决方法
问题情况
用Plotly向子图添加数据时持续触发ValueError,单独绘制折线图可正常运行,尝试切换至plotly.graph_objects时遇到模块类错误,已尝试将数据转换为列表和元组,问题仍存在。
错误信息
ValueError: Invalid element(s) received for the 'data' property of Invalid elements include: [Figure({ 'data': [{'hovertemplate': 'year=%{x}<br>value_sum=%{y}<extra></extra>', 'legendgroup': '', 'line': {'color': '#636efa', 'dash': 'solid'}, 'marker': {'symbol': 'circle'}, 'mode': 'lines', 'name': '', 'orientation': 'v', 'showlegend': False, 'type': 'scatter', 'x': array(['2018', '2018', '2018', '2019', '2019', '2019', '2020', '2020', '2020', '2021', '2021', '2021'], dtype=object), 'xaxis': 'x', 'yaxis': 'y'}], 'layout': {'legend': {'tracegroupgap': 0}, 'margin': {'t': 60}, 'template': '...', 'xaxis': {'anchor': 'y', 'domain': [0.0, 1.0], 'title': {'text': 'year'}}, 'yaxis': {'anchor': 'x', 'domain': [0.0, 1.0], 'title': {'text': 'value_sum'}}} })] The 'data' property is a tuple of trace instances that may be specified as: - A list or tuple of trace instances (e.g. [Scatter(...), Bar(...)]) - A single trace instance (e.g. Scatter(...), Bar(...), etc.) - A list or tuple of dicts of string/value properties where: - The 'type' property specifies the trace type One of: ['bar', 'barpolar', 'box', 'candlestick', 'carpet', 'choropleth', 'choroplethmapbox', 'cone', 'contour', 'contourcarpet', 'densitymapbox', 'funnel', 'funnelarea', 'heatmap', 'heatmapgl', 'histogram', 'histogram2d', 'histogram2dcontour', 'icicle', 'image', 'indicator', 'isosurface', 'mesh3d', 'ohlc', 'parcats', 'parcoords', 'pie', 'pointcloud', 'sankey', 'scatter', 'scatter3d', 'scattercarpet', 'scattergeo', 'scattergl', 'scattermapbox', 'scatterpolar', 'scatterpolargl', 'scattersmith', 'scatterternary', 'splom', 'streamtube', 'sunburst', 'surface', 'table', 'treemap', 'violin', 'volume', 'waterfall'] - All remaining properties are passed to the constructor of the specified trace type (e.g. [{'type': 'scatter', ...}, {'type': 'bar, ...}])
原代码
from io import StringIO import pandas as pd import plotly.express as px data=''' Use-Cases 2018 2019 2020 2021 0 Consumer 50 251 2123 210 1 Education 541 52 32 23 2 Government 689 444 441 456 ''' df = pd.read_csv(StringIO(data), sep='\s+') # Go from a wide to long dataframe using melt df = pd.melt(df, id_vars=[ 'Use-Cases'], value_vars=['2018', '2019', '2020', '2021']) df = df.rename(columns={ 'variable': 'year'}) # get totals for each year so the percent calculation can be done aggregated_df = df[[ 'value', 'year']].groupby(['year']).agg(['sum']).reset_index() aggregated_df.columns = ['year', 'value_sum'] df = pd.merge(df, aggregated_df, on=['year'], how='left') # Caclulate percents and format the column df['percent'] = (df['value']/df['value_sum']*100).round(1).astype(str) + "%" df fig = make_subplots(rows=1, cols=2) fig.add_trace(px.line(df,df.year,df.value_sum))
问题原因
px.line()返回的是完整的Figure对象,但fig.add_trace()要求传入的是单个/多个Trace对象(比如Scatter、Bar),不是整个Figure,这是触发ValueError的核心原因。- 原代码未导入
make_subplots函数,会导致模块类错误。
修正方案
步骤1:导入缺失的模块
从plotly.subplots导入make_subplots。
步骤2:提取Plotly Express生成的Trace
先通过px.line()生成折线图的Figure,再提取其中的Trace对象(figure.data[0]),再添加到子图中。
步骤3:指定子图位置(可选)
添加Trace时通过row和col参数指定它在子图中的位置。
修正后的完整代码
from io import StringIO import pandas as pd import plotly.express as px from plotly.subplots import make_subplots # 导入缺失的模块 data=''' Use-Cases 2018 2019 2020 2021 0 Consumer 50 251 2123 210 1 Education 541 52 32 23 2 Government 689 444 441 456 ''' df = pd.read_csv(StringIO(data), sep='\s+') # 宽表转长表 df = pd.melt(df, id_vars=['Use-Cases'], value_vars=['2018', '2019', '2020', '2021']) df = df.rename(columns={'variable': 'year'}) # 计算年度总和 aggregated_df = df[['value', 'year']].groupby(['year']).agg(['sum']).reset_index() aggregated_df.columns = ['year', 'value_sum'] df = pd.merge(df, aggregated_df, on=['year'], how='left') # 计算百分比 df['percent'] = (df['value']/df['value_sum']*100).round(1).astype(str) + "%" # 创建子图 fig = make_subplots(rows=1, cols=2) # 生成折线图并提取trace line_fig = px.line(df, x='year', y='value_sum') fig.add_trace(line_fig.data[0], row=1, col=1) # 将trace添加到子图的第1行第1列 # 可以继续添加其他trace到第2列,比如柱状图 bar_fig = px.bar(df, x='year', y='value', color='Use-Cases') for trace in bar_fig.data: fig.add_trace(trace, row=1, col=2) # 设置布局 fig.update_layout(height=400, width=800, title_text="子图示例") fig.show()
内容的提问来源于stack exchange,提问作者dlnvss
相关产品推荐
相关产品推荐

