使用to_plotly_json保存Dash组件与Plotly饼图为JSON时遇模板错误
开发Dash应用时,使用Plotly Express绘制图表,尝试通过to_plotly_json()将Dash组件和图表保存为JSON文件,但处理饼图时出现以下错误:
Error-1 The first argument to the plotly.graph_objs.layout.Template constructor must be a dict or an instance of :class:
plotly.graph_objs.layout.Template
Error-1 The first argument to the plotly.graph_objs.layout.Template constructor must be a dict or
最小可复现示例(MWE):
import json import dash_bootstrap_components as dbc from dash import dcc import plotly.express as px import pandas as pd def generate_pie_charts(df, template) -> list[dict[str, Any]]: pie_charts = list() for field in df.columns.tolist(): value_count_df = df[field].value_counts().reset_index() cols = value_count_df.columns.tolist() name: str = cols[0] value: str = cols[1] try: figure = px.pie( data_frame=value_count_df, values=value, names=name, title=f"Pie chart of {field}", template=template, ).to_plotly_json() pie_chart = dcc.Graph(figure=figure).to_plotly_json() pie_charts.append(pie_chart) except Exception as e: print(f"Error-1 {e}") return pie_charts def perform_exploratory_data_analysis(): rows = list() template = "darkly" info = { "A": ["a", "a", "b", "b", "c", "a", "a", "b", "b", "c", "a", "a", "b", "b", "c"], "B": ["c", "c", "c", "c", "c", "a", "a", "b", "b", "c", "a", "a", "b", "b", "c"], } df = pd.DataFrame(info) try: row = dbc.Badge( "For Pie Charts", color="info", className="ms-1" ).to_plotly_json() rows.append(row) row = generate_pie_charts(df, template) rows.append(row) data = {"contents": rows} status = False msg = "Error creating EDA graphs." file = "eda.json" with open(file, "w") as json_file: json.dump(data, json_file) msg = "EDA graphs created." status = True except Exception as e: print(f"Error-2 {e}") result = (status, msg) return result perform_exploratory_data_analysis()
错误出在**先将Plotly figure转成JSON格式,再传给dcc.Graph**的步骤上:
- 调用
px.pie(...).to_plotly_json()后,figure字典中的template字段会被序列化为字符串(比如"darkly")。 - 当你把这个JSON化的figure传给
dcc.Graph(figure=figure)时,Dash会尝试将该字典还原为Plotly figure对象,此时会用字符串"darkly"去初始化Template类,但Template构造函数要求传入的是字典或Template实例,而非字符串,因此抛出错误。
调整顺序:先将原始的Plotly figure对象传给dcc.Graph,再对dcc.Graph组件调用to_plotly_json(),而非先序列化figure。
修改后的generate_pie_charts函数如下:
def generate_pie_charts(df, template) -> list[dict[str, Any]]: pie_charts = list() for field in df.columns.tolist(): value_count_df = df[field].value_counts().reset_index() cols = value_count_df.columns.tolist() name: str = cols[0] value: str = cols[1] try: # 保留原始figure对象,不先转JSON figure = px.pie( data_frame=value_count_df, values=value, names=name, title=f"Pie chart of {field}", template=template, ) # 先创建dcc.Graph,再对组件转JSON pie_chart = dcc.Graph(figure=figure).to_plotly_json() pie_charts.append(pie_chart) except Exception as e: print(f"Error-1 {e}") return pie_charts
to_plotly_json()方法的作用是将Dash组件或Plotly figure序列化为可JSON存储的字典,适合直接保存或传递。但如果先序列化figure再传给组件,会破坏figure内部对象的结构(比如将Template对象转为字符串),导致组件无法正确解析。正确的做法是让组件直接接收原生的figure对象,再整体序列化组件。
内容的提问来源于stack exchange,提问作者winter

