Skip to content

Commit 237c799

Browse files
committed
Merge pull request #164 from plotly/jsonify-masked-numbers
Masked numbers, datetime.date json encoding
2 parents d309589 + 54dbb4e commit 237c799

File tree

3 files changed

+74
-13
lines changed

3 files changed

+74
-13
lines changed

plotly/tests/test_optional/test_utils/test_utils.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,26 @@
33
from nose.plugins.attrib import attr
44

55
from datetime import datetime as dt
6+
import datetime
67
import numpy as np
78
import json
89
import pandas as pd
910
from pandas.util.testing import assert_series_equal
11+
import matplotlib.pyplot as plt
1012

1113
from plotly import utils
1214
from plotly.grid_objs import Column
1315
from plotly.graph_objs import Scatter, Scatter3d, Figure, Data
16+
from plotly.matplotlylib import Exporter, PlotlyRenderer
17+
from plotly.plotly import plot
1418

1519
## JSON encoding
1620
numeric_list = [1, 2, 3]
1721
np_list = np.array([1, 2, 3, np.NaN, np.NAN, np.Inf, dt(2014, 1, 5)])
1822
mixed_list = [1, 'A', dt(2014, 1, 5), dt(2014, 1, 5, 1, 1, 1),
1923
dt(2014, 1, 5, 1, 1, 1, 1)]
24+
dt_list = [dt(2014, 1, 5), dt(2014, 1, 5, 1, 1, 1),
25+
dt(2014, 1, 5, 1, 1, 1, 1)]
2026

2127
df = pd.DataFrame(columns=['col 1'],
2228
data=[1, 2, 3, dt(2014, 1, 5), pd.NaT, np.NaN, np.Inf])
@@ -72,6 +78,17 @@ def test_figure_json_encoding():
7278
dt(2014, 1, 5, 1, 1, 1, 1)]))
7379

7480

81+
def test_datetime_json_encoding():
82+
j1 = json.dumps(dt_list, cls=utils._plotlyJSONEncoder)
83+
assert(j1 == '["2014-01-05", '
84+
'"2014-01-05 01:01:01", '
85+
'"2014-01-05 01:01:01.000001"]')
86+
j2 = json.dumps({"x": dt_list}, cls=utils._plotlyJSONEncoder)
87+
assert(j2 == '{"x": ["2014-01-05", '
88+
'"2014-01-05 01:01:01", '
89+
'"2014-01-05 01:01:01.000001"]}')
90+
91+
7592
def test_pandas_json_encoding():
7693
j1 = json.dumps(df['col 1'], cls=utils._plotlyJSONEncoder)
7794
assert(j1 == '[1, 2, 3, "2014-01-05", null, NaN, Infinity]')
@@ -98,3 +115,50 @@ def test_pandas_json_encoding():
98115

99116
j6 = json.dumps(ts.index, cls=utils._plotlyJSONEncoder)
100117
assert(j6 == '["2011-01-01", "2011-01-01 01:00:00"]')
118+
119+
120+
def test_numpy_masked_json_encoding():
121+
l = [1, 2, np.ma.core.masked]
122+
j1 = json.dumps(l, cls=utils._plotlyJSONEncoder)
123+
assert(j1 == '[1, 2, NaN]')
124+
assert(set(l) == set([1, 2, np.ma.core.masked]))
125+
126+
127+
def test_masked_constants_example():
128+
# example from: https://gist.github.com/tschaume/d123d56bf586276adb98
129+
data = {
130+
'esN': [0, 1, 2, 3],
131+
'ewe_is0': [-398.11901997, -398.11902774,
132+
-398.11897111, -398.11882215],
133+
'ewe_is1': [-398.11793027, -398.11792966, -398.11786308, None],
134+
'ewe_is2': [-398.11397008, -398.11396421, None, None]
135+
}
136+
df = pd.DataFrame.from_dict(data)
137+
138+
plotopts = {'x': 'esN', 'marker': 'o'}
139+
fig, ax = plt.subplots(1, 1)
140+
df.plot(ax=ax, **plotopts)
141+
142+
renderer = PlotlyRenderer()
143+
Exporter(renderer).run(fig)
144+
145+
json.dumps(renderer.plotly_fig, cls=utils._plotlyJSONEncoder)
146+
147+
jy = json.dumps(renderer.plotly_fig['data'][1]['y'],
148+
cls=utils._plotlyJSONEncoder)
149+
assert(jy == '[-398.11793026999999, -398.11792966000002, '
150+
'-398.11786308000001, NaN]')
151+
152+
153+
def test_numpy_dates():
154+
a = np.arange(np.datetime64('2011-07-11'), np.datetime64('2011-07-18'))
155+
j1 = json.dumps(a, cls=utils._plotlyJSONEncoder)
156+
assert(j1 == '["2011-07-11", "2011-07-12", "2011-07-13", '
157+
'"2011-07-14", "2011-07-15", "2011-07-16", '
158+
'"2011-07-17"]')
159+
160+
161+
def test_datetime_dot_date():
162+
a = [datetime.date(2014, 1, 1), datetime.date(2014, 1, 2)]
163+
j1 = json.dumps(a, cls=utils._plotlyJSONEncoder)
164+
assert(j1 == '["2014-01-01", "2014-01-02"]')

plotly/utils.py

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,12 @@ def numpyJSONEncoder(self, obj):
101101
if not _numpy_imported:
102102
raise NotEncodable
103103

104+
if obj is numpy.ma.core.masked:
105+
return float('nan')
106+
104107
if type(obj).__module__.split('.')[0] == numpy.__name__:
105-
l = obj.tolist()
106-
try:
107-
return self.datetimeJSONEncoder(l)
108-
except NotEncodable:
109-
return l
108+
return obj.tolist()
109+
110110
else:
111111
raise NotEncodable
112112

@@ -123,19 +123,16 @@ def datetimeJSONEncoder(self, obj):
123123
if _pandas_imported and obj is pandas.NaT:
124124
return None
125125

126-
if isinstance(obj, (datetime.datetime, datetime.date)):
126+
127+
if isinstance(obj, datetime.datetime):
127128
if obj.microsecond:
128129
return obj.strftime('%Y-%m-%d %H:%M:%S.%f')
129130
elif any((obj.second, obj.minute, obj.hour)):
130131
return obj.strftime('%Y-%m-%d %H:%M:%S')
131132
else:
132133
return obj.strftime('%Y-%m-%d')
133-
elif isinstance(obj[0], (datetime.datetime, datetime.date)):
134-
return [o.strftime(
135-
'%Y-%m-%d %H:%M:%S.%f') if o.microsecond else
136-
o.strftime('%Y-%m-%d %H:%M:%S') if any((o.second, o.minute, o.hour)) else
137-
o.strftime('%Y-%m-%d')
138-
for o in obj]
134+
elif isinstance(obj, datetime.date):
135+
return obj.strftime('%Y-%m-%d')
139136
else:
140137
raise NotEncodable
141138

plotly/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '1.4.10'
1+
__version__ = '1.4.11'

0 commit comments

Comments
 (0)