Plotly Express图表转JSON遇序列化错误,求排查方案
问题:Plotly图表转JSON保存时序列化失败
我用plotly express创建各类图表,尝试将图表转换为JSON格式保存到文件中,但两种实现方式均报错:
- Way-1 报错:
Error-2 Object of type ndarray is not JSON serializable - Way-2 报错:
Error-2 Object of type Figure is not JSON serializable
最小可复现代码:
import json import dash_bootstrap_components as dbc from dash import dcc from dash_bootstrap_templates import load_figure_template import plotly.express as px import plotly.io as pio 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: # Way-1 # 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() # Way-2 figure = px.pie( data_frame=value_count_df, values=value, names=name, title=f"Pie chart of {field}", template=template, ) figure = pio.to_json(figure) # figure = pio.to_json(figure).encode() pie_chart = dcc.Graph(figure=pio.from_json(figure)).to_plotly_json() # pie_chart = dcc.Graph(figure=pio.from_json(figure.decode())).to_plotly_json() pie_charts.append(pie_chart) except Exception as e: print(f"Error-1 {e}") print(f"Length {len(pie_charts)}") return pie_charts def perform_exploratory_data_analysis(): rows = list() template = "darkly" load_figure_template(template) 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()
错误根源
- Way-1的问题:
px.pie()生成的Figure调用to_plotly_json()后,虽得到JSON格式字典,但dcc.Graph(figure=figure).to_plotly_json()的返回结构中,仍包含numpy ndarray类型数据(来自value_counts()生成的数值列),Python标准json.dump无法序列化这种非原生类型。 - Way-2的问题:
pio.to_json(figure)已将Figure转为JSON字符串,但后续用pio.from_json(figure)转回Figure对象,再传给dcc.Graph调用to_plotly_json(),等于绕圈回到包含不可序列化类型的结构,必然报错。 - 深层嵌套的
rows结构中,部分字段仍保留不可序列化的类型,最终导致json.dump失败。
正确解决方案
核心思路:用Plotly工具直接将Figure转为可序列化的JSON字典,同时把所有非Python原生类型(如ndarray)转换为原生类型(如list)。
修改后的代码:
import json import dash_bootstrap_components as dbc from dash import dcc from dash_bootstrap_templates import load_figure_template import plotly.express as px import pandas as pd from typing import Any 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() # 将ndarray类型的数值列转换为Python原生list value_count_df[value_count_df.columns[1]] = value_count_df[value_count_df.columns[1]].tolist() name: str = value_count_df.columns[0] value: str = value_count_df.columns[1] try: # 生成Figure后直接转为可序列化的JSON字典 figure = px.pie( data_frame=value_count_df, values=value, names=name, title=f"Pie chart of {field}", template=template, ).to_plotly_json() # 转换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}") print(f"Length {len(pie_charts)}") return pie_charts def perform_exploratory_data_analysis(): rows = list() template = "darkly" load_figure_template(template) 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} file = "eda.json" with open(file, "w") as json_file: json.dump(data, json_file) status = True msg = "EDA graphs created." except Exception as e: print(f"Error-2 {e}") status = False msg = "Error creating EDA graphs." return (status, msg) perform_exploratory_data_analysis()
关键修改点
- 将
value_count_df中的数值列从ndarray转为Python list,解决基础类型序列化问题。 - 直接使用
figure.to_plotly_json()获取可序列化字典,避免pio.to_json转字符串后再转回Figure的多余操作,减少类型转换风险。
内容的提问来源于stack exchange,提问作者winter
相关产品推荐
相关产品推荐

