Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
apply the same NaN/inf fallback in the FigureWidget serializer
_py_to_js sends 1-D float arrays to the frontend as binary buffers
that become typed arrays as well, so a FigureWidget hits the same
stacking reset. Send arrays with non-finite values as lists with null
instead, and turn bare non-finite floats into null too, which also
keeps jupyter_client from falling back to its non-compliant JSON path
for them.
  • Loading branch information
Belagum committed Sep 16, 2026
commit 88df69272f23b53a1a47a6ca83abddd6958f1f30
12 changes: 12 additions & 0 deletions plotly/serializers.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import math

from .basedatatypes import Undefined
from .optional_imports import get_module

Expand Down Expand Up @@ -38,6 +40,11 @@ def _py_to_js(v, widget_manager):
# Handle numpy array
# ------------------
elif np is not None and isinstance(v, np.ndarray):
# NaN/inf can't go out as JSON and plotly.js does not clean them out
# of typed arrays, so send them as null like the JSON encoders do
if v.dtype.kind == "f" and not np.isfinite(v).all():
return np.where(np.isfinite(v), v.astype(object), None).tolist()

# Convert 1D numpy arrays with numeric types to memoryviews with
# datatype and shape metadata.
if (
Expand All @@ -53,6 +60,11 @@ def _py_to_js(v, widget_manager):
# Convert all other numpy arrays to lists
return v.tolist()

# Handle non-finite floats
# ------------------------
elif isinstance(v, float) and not math.isfinite(v):
return None

# Handle Undefined
# ----------------
if v is Undefined:
Expand Down
21 changes: 21 additions & 0 deletions tests/test_optional/test_graph_objs/test_b64_non_finite.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import plotly.graph_objects as go
import plotly.io as pio
from _plotly_utils.utils import to_typed_array_spec
from plotly.serializers import _py_to_js

try:
import orjson # noqa: F401
Expand Down Expand Up @@ -73,3 +74,23 @@ def test_to_typed_array_spec_finite():
"dtype": "f8",
"bdata": "AAAAAAAA8D8AAAAAAAAAQA==",
}


def test_widget_serializer_non_finite():
assert _py_to_js(np.array([1.0, np.nan, np.inf]), None) == [1.0, None, None]
assert _py_to_js(np.array([[1.0, np.nan], [2.0, 3.0]]), None) == [
[1.0, None],
[2.0, 3.0],
]
assert _py_to_js({"y": [1.0, float("nan"), -float("inf")]}, None) == {
"y": [1.0, None, None]
}


def test_widget_serializer_finite_array_as_buffer():
v = np.array([1.0, 2.0])

result = _py_to_js(v, None)
assert result["dtype"] == "float64"
assert result["shape"] == (2,)
assert bytes(result["buffer"]) == v.tobytes()
Loading