Skip to content

Commit b76c26b

Browse files
committed
Merge pull request plotly#348 from plotly/updated-offline-mode
Updated offline mode
2 parents 244f4e5 + 3594b3d commit b76c26b

File tree

9 files changed

+362
-221
lines changed

9 files changed

+362
-221
lines changed

CHANGELOG.md

+14
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,20 @@ This project adheres to [Semantic Versioning](http://semver.org/).
44

55
## [Unreleased]
66

7+
## [1.9.0] - 2015-11-15
8+
- Previously, using plotly offline required a paid license.
9+
No more: `plotly.js` is now shipped inside this package to allow
10+
unlimited free use of plotly inside the ipython notebook environment.
11+
The `plotly.js` library that is included in this package is free,
12+
open source, and maintained independently on GitHub at
13+
[https://github.com/plotly/plotly.js](https://github.com/plotly/plotly.js).
14+
- The `plotly.js` bundle that is required for offline use is no longer downloaded
15+
and installed independently from this package: `plotly.offline.download_plotlyjs`
16+
is **deprecated**.
17+
- New versions of `plotly.js` will be tested and incorporated
18+
into this package as new versioned pip releases;
19+
`plotly.js` is not automatically kept in sync with this package.
20+
721
## [1.8.12] - 2015-11-02
822
- *Big data* warning mentions `plotly.graph_objs.Scattergl` as possible solution.
923

plotly/graph_reference/default-schema.json

+210-115
Large diffs are not rendered by default.

plotly/offline/offline.py

+37-51
Original file line numberDiff line numberDiff line change
@@ -8,40 +8,29 @@
88
import json
99
import os
1010
import uuid
11-
12-
import requests
11+
import warnings
12+
from pkg_resources import resource_string
1313

1414
from plotly import session, tools, utils
1515
from plotly.exceptions import PlotlyError
1616

17-
PLOTLY_OFFLINE_DIRECTORY = plotlyjs_path = os.path.expanduser(
18-
os.path.join(*'~/.plotly/plotlyjs'.split('/')))
19-
PLOTLY_OFFLINE_BUNDLE = os.path.join(PLOTLY_OFFLINE_DIRECTORY,
20-
'plotly-ipython-offline-bundle.js')
21-
2217

2318
__PLOTLY_OFFLINE_INITIALIZED = False
2419

2520

2621
def download_plotlyjs(download_url):
27-
if not os.path.exists(PLOTLY_OFFLINE_DIRECTORY):
28-
os.makedirs(PLOTLY_OFFLINE_DIRECTORY)
29-
30-
res = requests.get(download_url)
31-
res.raise_for_status()
22+
warnings.warn('''
23+
`download_plotlyjs` is deprecated and will be removed in the
24+
next release. plotly.js is shipped with this module, it is no
25+
longer necessary to download this bundle separately.
26+
''', DeprecationWarning)
27+
pass
3228

33-
with open(PLOTLY_OFFLINE_BUNDLE, 'wb') as f:
34-
f.write(res.content)
3529

36-
print('\n'.join([
37-
'Success! Now start an IPython notebook and run the following ' +
38-
'code to make your first offline graph:',
39-
'',
40-
'import plotly',
41-
'plotly.offline.init_notebook_mode() '
42-
'# run at the start of every ipython notebook',
43-
'plotly.offline.iplot([{"x": [1, 2, 3], "y": [3, 1, 6]}])'
44-
]))
30+
def get_plotlyjs():
31+
path = os.path.join('offline', 'plotly.min.js')
32+
plotlyjs = resource_string('plotly', path).decode('utf-8')
33+
return plotlyjs
4534

4635

4736
def init_notebook_mode():
@@ -55,24 +44,20 @@ def init_notebook_mode():
5544
raise ImportError('`iplot` can only run inside an IPython Notebook.')
5645
from IPython.display import HTML, display
5746

58-
if not os.path.exists(PLOTLY_OFFLINE_BUNDLE):
59-
raise PlotlyError('Plotly Offline source file at {source_path} '
60-
'is not found.\n'
61-
'If you have a Plotly Offline license, then try '
62-
'running plotly.offline.download_plotlyjs(url) '
63-
'with a licensed download url.\n'
64-
"Don't have a Plotly Offline license? "
65-
'Contact [email protected] learn more about licensing.\n'
66-
'Questions? [email protected].'
67-
.format(source_path=PLOTLY_OFFLINE_BUNDLE))
68-
6947
global __PLOTLY_OFFLINE_INITIALIZED
7048
__PLOTLY_OFFLINE_INITIALIZED = True
7149
display(HTML('<script type="text/javascript">' +
72-
open(PLOTLY_OFFLINE_BUNDLE).read() + '</script>'))
50+
# ipython's includes `require` as a global, which
51+
# conflicts with plotly.js. so, unrequire it.
52+
'require=requirejs=define=undefined;' +
53+
'</script>' +
54+
'<script type="text/javascript">' +
55+
get_plotlyjs() +
56+
'</script>'))
7357

7458

75-
def iplot(figure_or_data, show_link=True, link_text='Export to plot.ly'):
59+
def iplot(figure_or_data, show_link=True, link_text='Export to plot.ly',
60+
validate=True):
7661
"""
7762
Draw plotly graphs inside an IPython notebook without
7863
connecting to an external server.
@@ -90,6 +75,11 @@ def iplot(figure_or_data, show_link=True, link_text='Export to plot.ly'):
9075
of the chart that will export the chart to
9176
Plotly Cloud or Plotly Enterprise
9277
link_text (default='Export to plot.ly') -- the text of export link
78+
validate (default=True) -- validate that all of the keys in the figure
79+
are valid? omit if your version of plotly.js
80+
has become outdated with your version of
81+
graph_reference.json or if you need to include
82+
extra, unnecessary keys in your figure.
9383
9484
Example:
9585
```
@@ -112,15 +102,10 @@ def iplot(figure_or_data, show_link=True, link_text='Export to plot.ly'):
112102
raise ImportError('`iplot` can only run inside an IPython Notebook.')
113103

114104
from IPython.display import HTML, display
115-
if isinstance(figure_or_data, dict):
116-
data = figure_or_data['data']
117-
layout = figure_or_data.get('layout', {})
118-
else:
119-
data = figure_or_data
120-
layout = {}
105+
figure = tools.return_figure_from_figure_or_data(figure_or_data, validate)
121106

122-
width = layout.get('width', '100%')
123-
height = layout.get('height', 525)
107+
width = figure.get('layout', {}).get('width', '100%')
108+
height = figure.get('layout', {}).get('height', 525)
124109
try:
125110
float(width)
126111
except (ValueError, TypeError):
@@ -136,11 +121,13 @@ def iplot(figure_or_data, show_link=True, link_text='Export to plot.ly'):
136121
width = str(width) + 'px'
137122

138123
plotdivid = uuid.uuid4()
139-
jdata = json.dumps(data, cls=utils.PlotlyJSONEncoder)
140-
jlayout = json.dumps(layout, cls=utils.PlotlyJSONEncoder)
124+
jdata = json.dumps(figure.get('data', []), cls=utils.PlotlyJSONEncoder)
125+
jlayout = json.dumps(figure.get('layout', {}), cls=utils.PlotlyJSONEncoder)
141126

142-
if show_link is False:
143-
link_text = ''
127+
config = {}
128+
config['showLink'] = show_link
129+
config['linkText'] = link_text
130+
jconfig = json.dumps(config)
144131

145132
plotly_platform_url = session.get_session_config().get('plotly_domain',
146133
'https://plot.ly')
@@ -156,18 +143,17 @@ def iplot(figure_or_data, show_link=True, link_text='Export to plot.ly'):
156143
'<script type="text/javascript">'
157144
'window.PLOTLYENV=window.PLOTLYENV || {};'
158145
'window.PLOTLYENV.BASE_URL="' + plotly_platform_url + '";'
159-
'Plotly.LINKTEXT = "' + link_text + '";'
160146
'</script>'
161147
))
162148

163149
script = '\n'.join([
164-
'Plotly.plot("{id}", {data}, {layout}).then(function() {{',
150+
'Plotly.plot("{id}", {data}, {layout}, {config}).then(function() {{',
165151
' $(".{id}.loading").remove();',
166152
'}})'
167153
]).format(id=plotdivid,
168154
data=jdata,
169155
layout=jlayout,
170-
link_text=link_text)
156+
config=jconfig)
171157

172158
display(HTML(''
173159
'<div class="{id} loading" style="color: rgb(50,50,50);">'

plotly/offline/plotly.min.js

+91
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

plotly/tests/test_core/test_offline/__init__.py

Whitespace-only changes.

plotly/tests/test_core/test_offline/test_offline.py

-25
This file was deleted.

plotly/tests/test_optional/test_offline/test_offline.py

+8-28
Original file line numberDiff line numberDiff line change
@@ -4,41 +4,21 @@
44
"""
55
from __future__ import absolute_import
66

7-
import os
8-
from nose.plugins.attrib import attr
97
from nose.tools import raises
108
from unittest import TestCase
119

1210
import plotly
13-
from plotly.exceptions import PlotlyError
14-
15-
dummy_js_url = ('https://gist.githubusercontent.com/chriddyp/'
16-
'f40bd33d1eab6f0715dc/raw/'
17-
'24cd2e4e62ceea79e6e790b3a2c94cda63510ede/'
18-
'test.js')
1911

2012

2113
class PlotlyOfflineTestCase(TestCase):
22-
def _remove_plotlyjs(self):
23-
try:
24-
os.remove(plotly.offline.offline.PLOTLY_OFFLINE_BUNDLE)
25-
except OSError:
26-
pass
27-
28-
def test_no_errors_are_raised_when_initializing_offline_mode(self):
29-
self._remove_plotlyjs()
30-
plotly.offline.download_plotlyjs(dummy_js_url)
31-
plotly.offline.init_notebook_mode()
32-
plotly.offline.iplot([{'x': [1, 2, 3]}])
14+
def setUp(self):
15+
plotly.offline.offline.__PLOTLY_OFFLINE_INITIALIZED = False
3316

34-
@attr('slow')
35-
@raises(PlotlyError)
36-
def test_calling_iplot_before_initializing_raises_an_error(self):
37-
self._remove_plotlyjs()
38-
plotly.offline.download_plotlyjs(dummy_js_url)
39-
plotly.offline.iplot([{'x': [1, 2, 3]}])
17+
@raises(plotly.exceptions.PlotlyError)
18+
def test_iplot_doesnt_work_before_you_call_init_notebook_mode(self):
19+
plotly.offline.iplot([{}])
4020

41-
@raises(PlotlyError)
42-
def test_initializing_before_downloading_raises_an_error(self):
43-
self._remove_plotlyjs()
21+
def test_iplot_works_after_you_call_init_notebook_mode(self):
22+
plotly.tools._ipython_imported = True
4423
plotly.offline.init_notebook_mode()
24+
plotly.offline.iplot([{}])

plotly/version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '1.8.12'
1+
__version__ = '1.9.0'

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,6 @@ def readme():
4040
'plotly/matplotlylib',
4141
'plotly/matplotlylib/mplexporter',
4242
'plotly/matplotlylib/mplexporter/renderers'],
43-
package_data={'plotly': ['graph_reference/*.json', 'widgets/*.js']},
43+
package_data={'plotly': ['graph_reference/*.json', 'widgets/*.js', 'offline/*.js']},
4444
install_requires=['requests', 'six', 'pytz'],
4545
zip_safe=False)

0 commit comments

Comments
 (0)