Skip to content

Commit fb036c7

Browse files
committed
Move conversion to to_dict function
1 parent 066564e commit fb036c7

File tree

3 files changed

+110
-110
lines changed

3 files changed

+110
-110
lines changed

packages/python/plotly/_plotly_utils/utils.py

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,116 @@
1+
import base64
12
import decimal
23
import json as _json
34
import sys
45
import re
56
from functools import reduce
67

78
from _plotly_utils.optional_imports import get_module
8-
from _plotly_utils.basevalidators import ImageUriValidator
9+
from _plotly_utils.basevalidators import (
10+
ImageUriValidator,
11+
copy_to_readonly_numpy_array,
12+
is_homogeneous_array,
13+
)
14+
15+
16+
int8min = -128
17+
int8max = 127
18+
int16min = -32768
19+
int16max = 32767
20+
int32min = -2147483648
21+
int32max = 2147483647
22+
23+
uint8max = 255
24+
uint16max = 65535
25+
uint32max = 4294967295
26+
27+
plotlyjsShortTypes = {
28+
"int8": "i1",
29+
"uint8": "u1",
30+
"int16": "i2",
31+
"uint16": "u2",
32+
"int32": "i4",
33+
"uint32": "u4",
34+
"float32": "f4",
35+
"float64": "f8",
36+
}
37+
38+
39+
def to_typed_array_spec(v):
40+
"""
41+
Convert numpy array to plotly.js typed array spec
42+
If not possible return the original value
43+
"""
44+
v = copy_to_readonly_numpy_array(v)
45+
46+
np = get_module("numpy", should_load=False)
47+
if not isinstance(v, np.ndarray):
48+
return v
49+
50+
dtype = str(v.dtype)
51+
52+
# convert default Big Ints until we could support them in plotly.js
53+
if dtype == "int64":
54+
max = v.max()
55+
min = v.min()
56+
if max <= int8max and min >= int8min:
57+
v = v.astype("int8")
58+
elif max <= int16max and min >= int16min:
59+
v = v.astype("int16")
60+
elif max <= int32max and min >= int32min:
61+
v = v.astype("int32")
62+
else:
63+
return v
64+
65+
elif dtype == "uint64":
66+
max = v.max()
67+
min = v.min()
68+
if max <= uint8max and min >= 0:
69+
v = v.astype("uint8")
70+
elif max <= uint16max and min >= 0:
71+
v = v.astype("uint16")
72+
elif max <= uint32max and min >= 0:
73+
v = v.astype("uint32")
74+
else:
75+
return v
76+
77+
dtype = str(v.dtype)
78+
79+
if dtype in plotlyjsShortTypes:
80+
arrObj = {
81+
"dtype": plotlyjsShortTypes[dtype],
82+
"bdata": base64.b64encode(v).decode("ascii"),
83+
}
84+
85+
if v.ndim > 1:
86+
arrObj["shape"] = str(v.shape)[1:-1]
87+
88+
return arrObj
89+
90+
return v
91+
92+
93+
def is_skipped_key(key):
94+
"""
95+
Return whether any keys in the parent hierarchy are in the list of keys that
96+
are skipped for conversion to the typed array spec
97+
"""
98+
skipped_keys = ["geojson", "layer", "range"]
99+
return any(skipped_key in key for skipped_key in skipped_keys)
100+
101+
102+
def convert_to_base64(obj):
103+
if isinstance(obj, dict):
104+
for key, value in obj.items():
105+
if is_skipped_key(key):
106+
continue
107+
elif is_homogeneous_array(value):
108+
obj[key] = to_typed_array_spec(value)
109+
else:
110+
convert_to_base64(value)
111+
elif isinstance(obj, list) or isinstance(obj, tuple):
112+
for i, value in enumerate(obj):
113+
convert_to_base64(value)
9114

10115

11116
def cumsum(x):

packages/python/plotly/plotly/basedatatypes.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
find_closest_string,
1818
)
1919
from _plotly_utils.exceptions import PlotlyKeyError
20+
from packages.python.plotly.plotly.io._utils import convert_to_base64
2021
from .optional_imports import get_module
2122

2223
from . import shapeannotation
@@ -3310,6 +3311,9 @@ def to_dict(self):
33103311
if frames:
33113312
res["frames"] = frames
33123313

3314+
# Add base64 conversion before sending to the front-end
3315+
convert_to_base64(res)
3316+
33133317
return res
33143318

33153319
def to_plotly_json(self):

packages/python/plotly/plotly/io/_utils.py

Lines changed: 0 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -1,113 +1,7 @@
1-
import base64
2-
from _plotly_utils.basevalidators import (
3-
copy_to_readonly_numpy_array,
4-
is_homogeneous_array,
5-
to_typed_array_spec,
6-
)
7-
from packages.python.plotly._plotly_utils.optional_imports import get_module
81
import plotly
92
import plotly.graph_objs as go
103
from plotly.offline import get_plotlyjs_version
114

12-
int8min = -128
13-
int8max = 127
14-
int16min = -32768
15-
int16max = 32767
16-
int32min = -2147483648
17-
int32max = 2147483647
18-
19-
uint8max = 255
20-
uint16max = 65535
21-
uint32max = 4294967295
22-
23-
plotlyjsShortTypes = {
24-
"int8": "i1",
25-
"uint8": "u1",
26-
"int16": "i2",
27-
"uint16": "u2",
28-
"int32": "i4",
29-
"uint32": "u4",
30-
"float32": "f4",
31-
"float64": "f8",
32-
}
33-
34-
35-
def to_typed_array_spec(v):
36-
"""
37-
Convert numpy array to plotly.js typed array spec
38-
If not possible return the original value
39-
"""
40-
v = copy_to_readonly_numpy_array(v)
41-
42-
np = get_module("numpy", should_load=False)
43-
if not isinstance(v, np.ndarray):
44-
return v
45-
46-
dtype = str(v.dtype)
47-
48-
# convert default Big Ints until we could support them in plotly.js
49-
if dtype == "int64":
50-
max = v.max()
51-
min = v.min()
52-
if max <= int8max and min >= int8min:
53-
v = v.astype("int8")
54-
elif max <= int16max and min >= int16min:
55-
v = v.astype("int16")
56-
elif max <= int32max and min >= int32min:
57-
v = v.astype("int32")
58-
else:
59-
return v
60-
61-
elif dtype == "uint64":
62-
max = v.max()
63-
min = v.min()
64-
if max <= uint8max and min >= 0:
65-
v = v.astype("uint8")
66-
elif max <= uint16max and min >= 0:
67-
v = v.astype("uint16")
68-
elif max <= uint32max and min >= 0:
69-
v = v.astype("uint32")
70-
else:
71-
return v
72-
73-
dtype = str(v.dtype)
74-
75-
if dtype in plotlyjsShortTypes:
76-
arrObj = {
77-
"dtype": plotlyjsShortTypes[dtype],
78-
"bdata": base64.b64encode(v).decode("ascii"),
79-
}
80-
81-
if v.ndim > 1:
82-
arrObj["shape"] = str(v.shape)[1:-1]
83-
84-
return arrObj
85-
86-
return v
87-
88-
89-
def is_skipped_key(key):
90-
"""
91-
Return whether any keys in the parent hierarchy are in the list of keys that
92-
are skipped for conversion to the typed array spec
93-
"""
94-
skipped_keys = ["geojson", "layer", "range"]
95-
return any(skipped_key in key for skipped_key in skipped_keys)
96-
97-
98-
def convert_to_base64(obj):
99-
if isinstance(obj, dict):
100-
for key, value in obj.items():
101-
if is_skipped_key(key):
102-
continue
103-
elif is_homogeneous_array(value):
104-
obj[key] = to_typed_array_spec(value)
105-
else:
106-
convert_to_base64(value)
107-
elif isinstance(obj, list) or isinstance(obj, tuple):
108-
for i, value in enumerate(obj):
109-
convert_to_base64(value)
110-
1115

1126
def validate_coerce_fig_to_dict(fig, validate):
1137
from plotly.basedatatypes import BaseFigure
@@ -131,9 +25,6 @@ def validate_coerce_fig_to_dict(fig, validate):
13125
)
13226
)
13327

134-
# Add base64 conversion before sending to the front-end
135-
convert_to_base64(fig_dict)
136-
13728
return fig_dict
13829

13930

0 commit comments

Comments
 (0)