Skip to content

Commit d45f0fc

Browse files
committed
Merge branch 'master' into etienne-factories
Conflicts: plotly/graph_objs/graph_objs_tools.py
2 parents c86fd28 + 0836322 commit d45f0fc

File tree

6 files changed

+218
-22
lines changed

6 files changed

+218
-22
lines changed

Diff for: plotly/graph_objs/graph_objs.py

+66-16
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,7 @@ def to_string(self, level=0, indent=4, eol='\n', pretty=True, max_chars=80):
563563
obj_key = NAME_TO_KEY[self.__class__.__name__]
564564
for key in INFO[obj_key]: # this sets the order of the keys! nice.
565565
if key in self:
566+
index += 1
566567
string += "{eol}{indent}{key}=".format(
567568
eol=eol,
568569
indent=' ' * indent * (level+1),
@@ -574,16 +575,40 @@ def to_string(self, level=0, indent=4, eol='\n', pretty=True, max_chars=80):
574575
pretty=pretty,
575576
max_chars=max_chars)
576577
except AttributeError:
577-
val = repr(self[key])
578-
val_chars = max_chars - (indent*(level+1)) - (len(key)+1)
579-
if pretty and (len(val) > val_chars):
580-
string += val[:val_chars - 5] + '...' + val[-1]
581-
else:
582-
string += val
583-
if index < len(self) - 1:
578+
if pretty: # curtail representation if too many chars
579+
max_len = (max_chars -
580+
indent*(level + 1) -
581+
len(key + "=") -
582+
len(eol))
583+
if index < len(self):
584+
max_len -= len(',') # remember the comma!
585+
if isinstance(self[key], list):
586+
s = "[]"
587+
for iii, entry in enumerate(self[key], 1):
588+
if iii < len(self[key]):
589+
s_sub = graph_objs_tools.curtail_val_repr(
590+
entry,
591+
max_chars=max_len - len(s),
592+
add_delim=True
593+
)
594+
else:
595+
s_sub = graph_objs_tools.curtail_val_repr(
596+
entry,
597+
max_chars=max_len - len(s),
598+
add_delim=False
599+
)
600+
s = s[:-1] + s_sub + s[-1]
601+
if len(s) == max_len:
602+
break
603+
string += s
604+
else:
605+
string += graph_objs_tools.curtail_val_repr(
606+
self[key], max_len)
607+
else: # they want it all!
608+
string += repr(self[key])
609+
if index < len(self):
584610
string += ","
585-
index += 1
586-
if index == len(self):
611+
if index == len(self): # TODO: extraneous...
587612
break
588613
string += "{eol}{indent})".format(eol=eol, indent=' ' * indent * level)
589614
return string
@@ -906,16 +931,41 @@ def to_string(self, level=0, indent=4, eol='\n', pretty=True, max_chars=80):
906931
pretty=pretty,
907932
max_chars=max_chars)
908933
except AttributeError:
909-
val = repr(self[key])
910-
val_chars = max_chars - (indent*(level+1)) - (len(key)+1)
911-
if pretty and (len(val) > val_chars):
912-
string += val[:val_chars - 5] + '...' + val[-1]
913-
else:
914-
string += val
934+
if pretty: # curtail representation if too many chars
935+
max_len = (max_chars -
936+
indent*(level + 1) -
937+
len(key + "=") -
938+
len(eol))
939+
if index < len(self):
940+
max_len -= len(',') # remember the comma!
941+
if isinstance(self[key], list):
942+
s = "[]"
943+
for iii, entry in enumerate(self[key], 1):
944+
if iii < len(self[key]):
945+
s_sub = graph_objs_tools.curtail_val_repr(
946+
entry,
947+
max_chars=max_len - len(s),
948+
add_delim=True
949+
)
950+
else:
951+
s_sub = graph_objs_tools.curtail_val_repr(
952+
entry,
953+
max_chars=max_len - len(s),
954+
add_delim=False
955+
)
956+
s = s[:-1] + s_sub + s[-1]
957+
if len(s) == max_len:
958+
break
959+
string += s
960+
else:
961+
string += graph_objs_tools.curtail_val_repr(
962+
self[key], max_len)
963+
else: # they want it all!
964+
string += repr(self[key])
915965
if index < len(self) - 1:
916966
string += ","
917967
index += 1
918-
if index == len(self):
968+
if index == len(self): # TODO: extraneous...
919969
break
920970
left_over_keys = [key for key in self if key not in INFO[obj_key]]
921971
left_over_keys.sort()

Diff for: plotly/graph_objs/graph_objs_tools.py

+30
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
else:
99
from collections import OrderedDict
1010
import json
11+
import six
1112

1213

1314
from pkg_resources import resource_string
@@ -215,3 +216,32 @@ def make_dict_doc(name):
215216
doc += code
216217
doc += '\n'
217218
return doc.expandtabs(tab_size)
219+
220+
221+
def curtail_val_repr(val, max_chars, add_delim=False):
222+
delim = ", "
223+
end = ".."
224+
if isinstance(val, six.string_types):
225+
if max_chars <= len("'" + end + "'"):
226+
return ' ' * max_chars
227+
elif add_delim and max_chars <= len("'" + end + "'") + len(delim):
228+
return "'" + end + "'" + ' ' * (max_chars - len("'" + end + "'"))
229+
else:
230+
if max_chars <= len(end):
231+
return ' ' * max_chars
232+
elif add_delim and max_chars <= len(end) + len(delim):
233+
return end + ' ' * (max_chars - len(end))
234+
if add_delim:
235+
max_chars -= len(delim)
236+
r = repr(val)
237+
if len(r) > max_chars:
238+
if isinstance(val, six.string_types):
239+
# TODO: can we assume this ends in "'"
240+
r = r[:max_chars - len(end + "'")] + end + "'"
241+
elif isinstance(val, list) and max_chars >= len("[{end}]".format(end)):
242+
r = r[:max_chars - len(end + ']')] + end + ']'
243+
else:
244+
r = r[:max_chars - len(end)] + end
245+
if add_delim:
246+
r += delim
247+
return r

Diff for: plotly/tests/test_optional/test_ipython/__init__.py

Whitespace-only changes.
+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
from __future__ import absolute_import
2+
3+
import plotly.tools as tls
4+
import imghdr
5+
import threading
6+
import six
7+
import unittest
8+
version = six.sys.version_info[:2] # need this for conditional testing
9+
10+
# unittest `skipIf` not supported in 2.6 and IPython not supported in 2.6/3.2
11+
if version < (2, 7) or (2, 7) < version < (3, 3):
12+
pass
13+
else:
14+
15+
class TestPlotlyDisplay(unittest.TestCase):
16+
17+
def setUp(self):
18+
plot_info = {"un": "plotlyimagetest", "fid": "2"}
19+
url = "https://plot.ly/~{un}/{fid}".format(**plot_info)
20+
self.display_obj = tls.embed(url)
21+
self.results = {}
22+
self.images = {}
23+
self.threads = []
24+
self.format_to_func = {
25+
"jpeg": self.jpeg_worker,
26+
"png": self.png_worker,
27+
"svg": self.svg_worker,
28+
"pdf": self.pdf_worker}
29+
30+
def test_plotly_display(self):
31+
for f_format, func in self.format_to_func.items():
32+
self.threads += [threading.Thread(target=func)]
33+
self.threads[-1].setDaemon(True)
34+
self.threads[-1].start()
35+
for thread in self.threads:
36+
thread.join()
37+
for f_format in self.format_to_func:
38+
result = self.results.get(f_format, False)
39+
print("{f_format}: {result}".format(f_format=f_format,
40+
result=result))
41+
print("{image}\n".format(image=self.images[f_format][:72]))
42+
assert self.results.get(f_format)
43+
44+
def jpeg_worker(self):
45+
self.images['jpeg'] = self.display_obj._repr_jpeg_()
46+
if imghdr.what('', self.images['jpeg']) == "jpeg":
47+
self.results["jpeg"] = True
48+
49+
def png_worker(self):
50+
self.images['png'] = self.display_obj._repr_png_()
51+
if imghdr.what('', self.images['png']) == "png":
52+
self.results["png"] = True
53+
54+
def svg_worker(self):
55+
self.images['svg'] = self.display_obj._repr_svg_()
56+
if self.images['svg'][:4] == six.b('<svg'):
57+
self.results["svg"] = True
58+
59+
def pdf_worker(self):
60+
self.images['pdf'] = self.display_obj._repr_pdf_()
61+
if self.images['pdf'][:4] == six.b('%PDF'):
62+
self.results["pdf"] = True

Diff for: plotly/tools.py

+59-5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import os.path
1414
import warnings
1515
import six
16+
import requests
1617

1718
from plotly import utils
1819
from plotly import exceptions
@@ -30,6 +31,12 @@ def warning_on_one_line(message, category, filename, lineno, file=None, line=Non
3031
except ImportError:
3132
_matplotlylib_imported = False
3233

34+
try:
35+
import IPython
36+
_ipython_imported = True
37+
except ImportError:
38+
_ipython_imported = False
39+
3340
PLOTLY_DIR = os.path.join(os.path.expanduser("~"), ".plotly")
3441
CREDENTIALS_FILE = os.path.join(PLOTLY_DIR, ".credentials")
3542
CONFIG_FILE = os.path.join(PLOTLY_DIR, ".config")
@@ -283,11 +290,21 @@ def embed(file_owner_or_url, file_id=None, width="100%", height=525):
283290
return html(s, hide=False)
284291
except:
285292
pass
286-
try:
287-
from IPython.display import HTML, display
288-
display(HTML(s))
289-
except:
290-
pass
293+
if _ipython_imported:
294+
if file_id:
295+
url = "{plotly_domain}/~{un}/{fid}".format(
296+
plotly_domain=get_config_file()['plotly_domain'],
297+
un=file_owner_or_url,
298+
fid=file_id)
299+
else:
300+
url = file_owner_or_url
301+
return PlotlyDisplay(url)
302+
else:
303+
warnings.warn(
304+
"Looks like you're not using IPython or Sage to embed this plot. "
305+
"If you just want the *embed code*, try using `get_embed()` "
306+
"instead."
307+
"\nQuestions? [email protected]")
291308

292309

293310
### mpl-related tools ###
@@ -532,3 +549,40 @@ def _replace_newline(obj):
532549
return s
533550
else:
534551
return obj # we return the actual reference... but DON'T mutate.
552+
553+
554+
if _ipython_imported:
555+
class PlotlyDisplay(IPython.core.display.HTML):
556+
"""An IPython display object for use with plotly urls
557+
558+
PlotlyDisplay objects should be instantiated with a url for a plot.
559+
IPython will *choose* the proper display representation from any
560+
Python object, and using provided methods if they exist. By defining
561+
the following, if an HTML display is unusable, the PlotlyDisplay
562+
object can provide alternate representations.
563+
564+
"""
565+
def __init__(self, url):
566+
self.resource = url
567+
self.embed_code = get_embed(url)
568+
super(PlotlyDisplay, self).__init__(data=self.embed_code)
569+
570+
def _repr_svg_(self):
571+
url = self.resource + ".svg"
572+
res = requests.get(url)
573+
return res.content
574+
575+
def _repr_png_(self):
576+
url = self.resource + ".png"
577+
res = requests.get(url)
578+
return res.content
579+
580+
def _repr_pdf_(self):
581+
url = self.resource + ".pdf"
582+
res = requests.get(url)
583+
return res.content
584+
585+
def _repr_jpeg_(self):
586+
url = self.resource + ".jpeg"
587+
res = requests.get(url)
588+
return res.content

Diff for: plotly/version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '1.2.6'
1+
__version__ = '1.2.7'

0 commit comments

Comments
 (0)