How Plotly Python Serializes Figures to JSON

Plotly relies on a clean separation between its Python interface and its client-side JavaScript rendering engine, Plotly.js. In Python, high-level figure declarations created with Plotly Express or plotly.graph_objects are translated into a standardized, JSON-serializable tree structure consisting of data, layout, and configuration parameters. This article explains how the Python library processes Python-native objects—such as NumPy arrays, Pandas DataFrames, and datetime values—into an optimized JSON payload that Plotly.js can parse and render in the browser.

The Anatomy of a Plotly Figure

In Python, a Plotly figure is an instance of the plotly.graph_objects.Figure class. Regardless of how complex the visualization is, every figure can be distilled into a tree structure containing three primary top-level keys:

Internally, each property in a Figure is validated and stored in structured dictionary-like objects called BasePlotlyType.

The Serialization Pipeline

To transfer a figure to the browser, Plotly must convert these internal graph objects into a valid JSON string. The primary function responsible for this is plotly.io.to_json(), also accessible directly via the fig.to_json() method.

The serialization pipeline involves the following stages:

  1. Dictionary Extraction: The Figure.to_plotly_json() method recursively traverses the figure tree, stripping away internal Python-specific validation wrappers and metadata to produce standard Python primitives (dict, list, str, int, float, bool).
  2. Type Coercion and Normalization: Real-world data structures often contain types not supported by standard JSON specifications, such as NumPy ndarray, Pandas Series, NaN/Infinity values, and datetime objects. Plotly transforms these non-standard types:
    • NumPy Arrays and Pandas Series: Converted into standard nested Python lists.
    • Missing and Non-Finite Values: NaN and None values are converted to JSON null, while Infinity and -Infinity are typically stringified or normalized so as not to break standard JSON parsers.
    • Dates and Times: Native Python datetime objects and Pandas Timestamp instances are serialized into ISO 8601 strings (e.g., YYYY-MM-DDTHH:MM:SS.sssZ), which Plotly.js natively recognizes and parses on the client side.

Serialization Engines

Plotly utilizes two main approaches to handle JSON conversion efficiently:

Client-Side Handoff to Plotly.js

Once serialized, the resulting JSON string represents the exact data schema expected by Plotly.js. When rendering a figure—whether in a Jupyter Notebook, a Dash web application, or an exported standalone HTML file—the serialization output is embedded into the document.

Plotly writes out a <script> tag that passes the serialized JSON directly to the client-side JavaScript entry point:

Plotly.newPlot('div-id', figureJson.data, figureJson.layout, figureJson.config);

On the client side, Plotly.js parses the JSON payload, instantiates its internal SVG or WebGL rendering contexts, and draws the visualization interactively in the DOM.