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

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()

错误根源

  1. Way-1的问题:px.pie()生成的Figure调用to_plotly_json()后,虽得到JSON格式字典,但dcc.Graph(figure=figure).to_plotly_json()的返回结构中,仍包含numpy ndarray类型数据(来自value_counts()生成的数值列),Python标准json.dump无法序列化这种非原生类型。
  2. Way-2的问题:pio.to_json(figure)已将Figure转为JSON字符串,但后续用pio.from_json(figure)转回Figure对象,再传给dcc.Graph调用to_plotly_json(),等于绕圈回到包含不可序列化类型的结构,必然报错。
  3. 深层嵌套的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 04:13:24