From f824169ebf2efc639d0f712c806430c4f5ec4bf7 Mon Sep 17 00:00:00 2001 From: Emily Kellison-Linn <4672118+emilykl@users.noreply.github.com> Date: Mon, 2 Dec 2024 15:38:41 -0500 Subject: [PATCH 1/4] handle dtype conversion for empty arrays --- packages/python/plotly/_plotly_utils/utils.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/python/plotly/_plotly_utils/utils.py b/packages/python/plotly/_plotly_utils/utils.py index 88f1a4000db..8f8f60bc960 100644 --- a/packages/python/plotly/_plotly_utils/utils.py +++ b/packages/python/plotly/_plotly_utils/utils.py @@ -51,8 +51,8 @@ def to_typed_array_spec(v): # convert default Big Ints until we could support them in plotly.js if dtype == "int64": - max = v.max() - min = v.min() + max = v.max() if v else 0 + min = v.min() if v else 0 if max <= int8max and min >= int8min: v = v.astype("int8") elif max <= int16max and min >= int16min: @@ -63,8 +63,8 @@ def to_typed_array_spec(v): return v elif dtype == "uint64": - max = v.max() - min = v.min() + max = v.max() if v else 0 + min = v.min() if v else 0 if max <= uint8max and min >= 0: v = v.astype("uint8") elif max <= uint16max and min >= 0: From ac9ddcea87557d67f0f43e77ed4d79989143bf1c Mon Sep 17 00:00:00 2001 From: Emily Kellison-Linn <4672118+emilykl@users.noreply.github.com> Date: Mon, 2 Dec 2024 15:58:53 -0500 Subject: [PATCH 2/4] handle dtype conversion for empty arrays; check array.size --- packages/python/plotly/_plotly_utils/utils.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/python/plotly/_plotly_utils/utils.py b/packages/python/plotly/_plotly_utils/utils.py index 8f8f60bc960..582db0ddf04 100644 --- a/packages/python/plotly/_plotly_utils/utils.py +++ b/packages/python/plotly/_plotly_utils/utils.py @@ -51,8 +51,8 @@ def to_typed_array_spec(v): # convert default Big Ints until we could support them in plotly.js if dtype == "int64": - max = v.max() if v else 0 - min = v.min() if v else 0 + max = v.max() if v.size > 0 else 0 + min = v.min() if v.size > 0 else 0 if max <= int8max and min >= int8min: v = v.astype("int8") elif max <= int16max and min >= int16min: @@ -63,8 +63,8 @@ def to_typed_array_spec(v): return v elif dtype == "uint64": - max = v.max() if v else 0 - min = v.min() if v else 0 + max = v.max() if v.size > 0 else 0 + min = v.min() if v.size > 0 else 0 if max <= uint8max and min >= 0: v = v.astype("uint8") elif max <= uint16max and min >= 0: From ca90f21f03cdcf58bff48ec6e70eff8af77db650 Mon Sep 17 00:00:00 2001 From: Emily Kellison-Linn <4672118+emilykl@users.noreply.github.com> Date: Tue, 3 Dec 2024 09:39:02 -0500 Subject: [PATCH 3/4] skip b64 encoding if array is empty --- packages/python/plotly/_plotly_utils/utils.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/python/plotly/_plotly_utils/utils.py b/packages/python/plotly/_plotly_utils/utils.py index 582db0ddf04..bb33e44140b 100644 --- a/packages/python/plotly/_plotly_utils/utils.py +++ b/packages/python/plotly/_plotly_utils/utils.py @@ -43,16 +43,18 @@ def to_typed_array_spec(v): """ v = copy_to_readonly_numpy_array(v) + # Skip b64 encoding if numpy is not installed, + # or if v is not a numpy array, or if v is empty np = get_module("numpy", should_load=False) - if not np or not isinstance(v, np.ndarray): + if not np or not isinstance(v, np.ndarray) or v.size == 0: return v dtype = str(v.dtype) # convert default Big Ints until we could support them in plotly.js if dtype == "int64": - max = v.max() if v.size > 0 else 0 - min = v.min() if v.size > 0 else 0 + max = v.max() + min = v.min() if max <= int8max and min >= int8min: v = v.astype("int8") elif max <= int16max and min >= int16min: @@ -63,8 +65,8 @@ def to_typed_array_spec(v): return v elif dtype == "uint64": - max = v.max() if v.size > 0 else 0 - min = v.min() if v.size > 0 else 0 + max = v.max() + min = v.min() if max <= uint8max and min >= 0: v = v.astype("uint8") elif max <= uint16max and min >= 0: From f7675c38570b685f51bb828cb72d407798f02b96 Mon Sep 17 00:00:00 2001 From: Emily Kellison-Linn <4672118+emilykl@users.noreply.github.com> Date: Tue, 3 Dec 2024 10:31:17 -0500 Subject: [PATCH 4/4] add tests --- .../plotly/tests/test_io/test_to_from_json.py | 14 ++++++++++++++ .../plotly/tests/test_optional/test_px/test_px.py | 15 +++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/packages/python/plotly/plotly/tests/test_io/test_to_from_json.py b/packages/python/plotly/plotly/tests/test_io/test_to_from_json.py index a932282bd36..0376855dec1 100644 --- a/packages/python/plotly/plotly/tests/test_io/test_to_from_json.py +++ b/packages/python/plotly/plotly/tests/test_io/test_to_from_json.py @@ -2,6 +2,7 @@ import plotly.io as pio import pytest import plotly +import numpy as np import json import os import tempfile @@ -259,3 +260,16 @@ def test_write_json_from_file_string(fig1, pretty, remove_uids): # Check contents that were written expected = pio.to_json(fig1, pretty=pretty, remove_uids=remove_uids) assert result == expected + + +def test_to_dict_empty_np_array_int64(): + fig = go.Figure( + [ + go.Bar( + x=np.array([], dtype="str"), + y=np.array([], dtype="int64"), + ) + ] + ) + # to_dict() should not raise an exception + fig.to_dict() diff --git a/packages/python/plotly/plotly/tests/test_optional/test_px/test_px.py b/packages/python/plotly/plotly/tests/test_optional/test_px/test_px.py index 157cb1fd2a1..e7a090bde21 100644 --- a/packages/python/plotly/plotly/tests/test_optional/test_px/test_px.py +++ b/packages/python/plotly/plotly/tests/test_optional/test_px/test_px.py @@ -360,3 +360,18 @@ def test_render_mode(backend): ) assert fig.data[0].type == "histogram2dcontour" assert fig.data[1].type == "scatter" + + +def test_empty_df_int64(backend): + # Load px data, then filter it such that the dataframe is empty + df = px.data.tips(return_type=backend) + df = nw.from_native(px.data.tips(return_type=backend)) + df_empty = df.filter(nw.col("day") == "banana").to_native() + + fig = px.scatter( + df_empty, + x="total_bill", + y="size", # size is an int64 column + ) + # to_dict() should not raise an exception + fig.to_dict()