8000 JSON encoding engine instrumentation by jonmmease · Pull Request #3012 · plotly/plotly.py · GitHub
[go: up one dir, main page]

Skip to content

JSON encoding engine instrumentation #3012

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 18 commits into from
Closed
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
Next Next commit
instrumentation
  • Loading branch information
jonmmease committed Jan 21, 2021
commit c3c44252e3cfd545a265c8b0ea3e891d916b52cd
8 changes: 4 additions & 4 deletions packages/python/plotly/plotly/basedatatypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -917,10 +917,10 @@ def update(self, dict1=None, overwrite=False, **kwargs):
else:
self[k] = v

# instrumentation
from plotly.io._json import to_json_plotly

to_json_plotly(self)
# # instrumentation
# from plotly.io._json import to_json_plotly
#
# to_json_plotly(self)

return self

Expand Down
6 changes: 3 additions & 3 deletions packages/python/plotly/plotly/express/_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -2094,9 +2094,9 @@ def make_figure(args, constructor, trace_patch=None, layout_patch=None):
configure_animation_controls(args, constructor, fig)

# instrumentation
from plotly.io._json import to_json_plotly

to_json_plotly(fig)
# from plotly.io._json import to_json_plotly
#
# to_json_plotly(fig)

return fig

Expand Down
80 changes: 64 additions & 16 deletions packages/python/plotly/plotly/io/_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,17 +57,48 @@ def coerce_to_strict(const):
return const


def time_engine(engine, plotly_object):
import time
# time in seconds
t_total = 0
n_total = 0

# Call function for at least total of 2 seconds and at least 10 times
n_min = 10
t_min = 1

while t_total < t_min or n_total < n_min:
t0 = time.perf_counter()
_to_json_plotly(plotly_object, engine=engine)
t1 = time.perf_counter()
n_total += 1
t_total += (t1 - t0)

# return time in ms
return 1000 * t_total / n_total


def to_json_plotly(plotly_object, pretty=False, engine=None):
if engine is not None:
return _to_json_plotly(plotly_object, pretty=pretty , engine=engine)

# instrucment _to_json_plotly by running it with all 3 engines and comparing results
# before returning
# before returnin

import timeit
from IPython import get_ipython
ipython = get_ipython()
orjson = get_module("orjson", should_load=True)
results = {}
timing = {}
result_str = None
for engine in ["legacy", "json", "orjson"]:
for engine in ["json", "orjson", "legacy"]:
if orjson is None and engine == "orjson":
continue

result_str = _to_json_plotly(plotly_object, pretty=pretty, engine=engine)
results[engine] = from_json_plotly(result_str, engine=engine)
timing[engine] = time_engine(engine, plotly_object)

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

# write timing
import uuid
import pickle
import os
uid = str(uuid.uuid4())
with open("json_timing.csv".format(engine), "at") as f:
f.write("{}, {}, {}, {}, {}\n".format(
timing["legacy"], timing["json"], timing["orjson"], len(result_str), uid)
)
os.makedirs("json_object", exist_ok=True)
with open("json_object/{uid}.pkl".format(uid=uid), "wb") as f:
pickle.dump(plotly_object, f)

return result_str


Expand Down Expand Up @@ -495,6 +539,20 @@ def clean_to_json_compatible(obj, **kwargs):
if isinstance(obj, (int, float, string_types)):
return obj

# Plotly
try:
obj = obj.to_plotly_json()
except AttributeError:
pass

# And simple lists
if isinstance(obj, (list, tuple)):
# Must process list recursively even though it may be slow
return [clean_to_json_compatible(v, **kwargs) for v in obj]
# Recurse into lists and dictionaries
if isinstance(obj, dict):
return {k: clean_to_json_compatible(v, **kwargs) for k, v in obj.items()}

# unpack kwargs
numpy_allowed = kwargs.get("numpy_allowed", False)
datetime_allowed = kwargs.get("datetime_allowed", False)
Expand All @@ -505,12 +563,6 @@ def clean_to_json_compatible(obj, **kwargs):
pd = modules["pd"]
image = modules["image"]

# Plotly
try:
obj = obj.to_plotly_json()
except AttributeError:
pass

# Sage
if sage_all is not None:
if obj in sage_all.RR:
Expand All @@ -531,7 +583,7 @@ def clean_to_json_compatible(obj, **kwargs):
elif obj.dtype.kind == "U":
return obj.tolist()
elif obj.dtype.kind == "O":
# Treat object array as a lists, continue processing
# Treat object array as plain list, allow recursive processing below
obj = obj.tolist()
elif isinstance(obj, np.datetime64):
return str(obj)
Expand Down Expand Up @@ -588,12 +640,8 @@ def clean_to_json_compatible(obj, **kwargs):
if image is not None and isinstance(obj, image.Image):
return ImageUriValidator.pil_image_to_uri(obj)

# Recurse into lists and dictionaries
if isinstance(obj, dict):
return {k: clean_to_json_compatible(v, **kwargs) for k, v in obj.items()}
elif isinstance(obj, (list, tuple)):
if obj:
# Must process list recursively even though it may be slow
return [clean_to_json_compatible(v, **kwargs) for v in obj]
if isinstance(obj, (list, tuple)) and obj:
# Must process list recursively even though it may be slow
return [clean_to_json_compatible(v, **kwargs) for v in obj]

return obj
0