Skip to content

Commit c3c4425

Browse files
committed
instrumentation
1 parent b4d9afe commit c3c4425

File tree

3 files changed

+71
-23
lines changed

3 files changed

+71
-23
lines changed

packages/python/plotly/plotly/basedatatypes.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -917,10 +917,10 @@ def update(self, dict1=None, overwrite=False, **kwargs):
917917
else:
918918
self[k] = v
919919

920-
# instrumentation
921-
from plotly.io._json import to_json_plotly
922-
923-
to_json_plotly(self)
920+
# # instrumentation
921+
# from plotly.io._json import to_json_plotly
922+
#
923+
# to_json_plotly(self)
924924

925925
return self
926926

packages/python/plotly/plotly/express/_core.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2094,9 +2094,9 @@ def make_figure(args, constructor, trace_patch=None, layout_patch=None):
20942094
configure_animation_controls(args, constructor, fig)
20952095

20962096
# instrumentation
2097-
from plotly.io._json import to_json_plotly
2098-
2099-
to_json_plotly(fig)
2097+
# from plotly.io._json import to_json_plotly
2098+
#
2099+
# to_json_plotly(fig)
21002100

21012101
return fig
21022102

packages/python/plotly/plotly/io/_json.py

Lines changed: 64 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -57,17 +57,48 @@ def coerce_to_strict(const):
5757
return const
5858

5959

60+
def time_engine(engine, plotly_object):
61+
import time
62+
# time in seconds
63+
t_total = 0
64+
n_total = 0
65+
66+
# Call function for at least total of 2 seconds and at least 10 times
67+
n_min = 10
68+
t_min = 1
69+
70+
while t_total < t_min or n_total < n_min:
71+
t0 = time.perf_counter()
72+
_to_json_plotly(plotly_object, engine=engine)
73+
t1 = time.perf_counter()
74+
n_total += 1
75+
t_total += (t1 - t0)
76+
77+
# return time in ms
78+
return 1000 * t_total / n_total
79+
80+
6081
def to_json_plotly(plotly_object, pretty=False, engine=None):
82+
if engine is not None:
83+
return _to_json_plotly(plotly_object, pretty=pretty , engine=engine)
84+
6185
# instrucment _to_json_plotly by running it with all 3 engines and comparing results
62-
# before returning
86+
# before returnin
87+
88+
import timeit
89+
from IPython import get_ipython
90+
ipython = get_ipython()
6391
orjson = get_module("orjson", should_load=True)
6492
results = {}
93+
timing = {}
6594
result_str = None
66-
for engine in ["legacy", "json", "orjson"]:
95+
for engine in ["json", "orjson", "legacy"]:
6796
if orjson is None and engine == "orjson":
6897
continue
98+
6999
result_str = _to_json_plotly(plotly_object, pretty=pretty, engine=engine)
70100
results[engine] = from_json_plotly(result_str, engine=engine)
101+
timing[engine] = time_engine(engine, plotly_object)
71102

72103
# Check matches
73104
if results["legacy"] != results["json"]:
@@ -91,6 +122,19 @@ def to_json_plotly(plotly_object, pretty=False, engine=None):
91122
)
92123
)
93124

125+
# write timing
126+
import uuid
127+
import pickle
128+
import os
129+
uid = str(uuid.uuid4())
130+
with open("json_timing.csv".format(engine), "at") as f:
131+
f.write("{}, {}, {}, {}, {}\n".format(
132+
timing["legacy"], timing["json"], timing["orjson"], len(result_str), uid)
133+
)
134+
os.makedirs("json_object", exist_ok=True)
135+
with open("json_object/{uid}.pkl".format(uid=uid), "wb") as f:
136+
pickle.dump(plotly_object, f)
137+
94138
return result_str
95139

96140

@@ -495,6 +539,20 @@ def clean_to_json_compatible(obj, **kwargs):
495539
if isinstance(obj, (int, float, string_types)):
496540
return obj
497541

542+
# Plotly
543+
try:
544+
obj = obj.to_plotly_json()
545+
except AttributeError:
546+
pass
547+
548+
# And simple lists
549+
if isinstance(obj, (list, tuple)):
550+
# Must process list recursively even though it may be slow
551+
return [clean_to_json_compatible(v, **kwargs) for v in obj]
552+
# Recurse into lists and dictionaries
553+
if isinstance(obj, dict):
554+
return {k: clean_to_json_compatible(v, **kwargs) for k, v in obj.items()}
555+
498556
# unpack kwargs
499557
numpy_allowed = kwargs.get("numpy_allowed", False)
500558
datetime_allowed = kwargs.get("datetime_allowed", False)
@@ -505,12 +563,6 @@ def clean_to_json_compatible(obj, **kwargs):
505563
pd = modules["pd"]
506564
image = modules["image"]
507565

508-
# Plotly
509-
try:
510-
obj = obj.to_plotly_json()
511-
except AttributeError:
512-
pass
513-
514566
# Sage
515567
if sage_all is not None:
516568
if obj in sage_all.RR:
@@ -531,7 +583,7 @@ def clean_to_json_compatible(obj, **kwargs):
531583
elif obj.dtype.kind == "U":
532584
return obj.tolist()
533585
elif obj.dtype.kind == "O":
534-
# Treat object array as a lists, continue processing
586+
# Treat object array as plain list, allow recursive processing below
535587
obj = obj.tolist()
536588
elif isinstance(obj, np.datetime64):
537589
return str(obj)
@@ -588,12 +640,8 @@ def clean_to_json_compatible(obj, **kwargs):
588640
if image is not None and isinstance(obj, image.Image):
589641
return ImageUriValidator.pil_image_to_uri(obj)
590642

591-
# Recurse into lists and dictionaries
592-
if isinstance(obj, dict):
593-
return {k: clean_to_json_compatible(v, **kwargs) for k, v in obj.items()}
594-
elif isinstance(obj, (list, tuple)):
595-
if obj:
596-
# Must process list recursively even though it may be slow
597-
return [clean_to_json_compatible(v, **kwargs) for v in obj]
643+
if isinstance(obj, (list, tuple)) and obj:
644+
# Must process list recursively even though it may be slow
645+
return [clean_to_json_compatible(v, **kwargs) for v in obj]
598646

599647
return obj

0 commit comments

Comments
 (0)