pythonpandasplotly-dashplotly-express

Convert plotly express graph into json


I am using plotly express to create different graphs. I am trying to convert graphs into json format to save in json file. While doing so I am getting error using different ways as below:

Way-1 code gives error as below
Error-2 Object of type ndarray is not JSON serializable

Way-2 code gives error as below
Error-2 Object of type Figure is not JSON serializable

Below is MWE:

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

What I am missing?


Solution

  • You were close with way-2, you need to :

    1. Convert the figure (go.Figure) to a JSON string using pio.to_json(), so that ndarray and other python types used in the figure's data are properly converted into their javascript equivalent.

    2. Deserialize the JSON string using json.loads() in order to get the figure as a standard JSON dict and prevent double encoding with future call to json.dump() (nb. pio.from_json() would return a go.Figure which json.dump() doesn't know how to serialize).

    The relevant part of the code :

    # ...
    
    figure = px.pie(
        data_frame=value_count_df,
        values=value,
        names=name,
        title=f"Pie chart of {field}",
        template=template,
    )
    
    # serializable figure dict
    fig_dict = json.loads(figure.to_json())
    
    pie_chart = dcc.Graph(figure=fig_dict).to_plotly_json()
    
    # ...