Skip to content

Plotly Offline #236

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

Merged
merged 28 commits into from
Jul 3, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
57ad872
first pass at offline mode in plotlyjs
chriddyp Jun 25, 2015
3fca388
version 1.7.0 - offline mode
chriddyp Jun 25, 2015
421f3ff
make offline.py importable
chriddyp Jun 25, 2015
500c9ab
update python lib url
chriddyp Jun 25, 2015
096e36c
bundle it up!
chriddyp Jun 30, 2015
45bec11
remove variable directory
chriddyp Jun 30, 2015
3e64b9c
:lipstick:
chriddyp Jun 30, 2015
a47c761
rename the bundle
chriddyp Jun 30, 2015
c653188
export to enterprise; update link text the plotly.js way.
chriddyp Jun 30, 2015
962c881
prevent users from calling iplot before they initialize plotly.js.
chriddyp Jun 30, 2015
6723236
docstring :dog:
chriddyp Jun 30, 2015
96bb809
Merge branch 'master' into offline
chriddyp Jun 30, 2015
d69887d
basic usage tests
chriddyp Jun 30, 2015
9f15456
docstring :dog: - basic example
chriddyp Jun 30, 2015
93cb7b7
use PlotlyErrors instead of Exception
chriddyp Jun 30, 2015
5a9f445
test that you need to download files before initializing
chriddyp Jun 30, 2015
2793609
refactor tests to handle core vs optional deps (ipython)
chriddyp Jun 30, 2015
08a8660
Depreciate support for Python 2.6
chriddyp Jul 1, 2015
770f601
rm 2.6 reqs, too
chriddyp Jul 1, 2015
1552f8e
wb for python 3.3
chriddyp Jul 1, 2015
3d95463
TestCase for the :habit: hamster, this one's for you @theengineear
chriddyp Jul 2, 2015
ce5b42c
narrower exception handling
chriddyp Jul 2, 2015
767d01c
http://i.imgur.com/7y6JoyU.png
chriddyp Jul 2, 2015
b6ef5fd
renaming now that module is mostly private
chriddyp Jul 2, 2015
73114ff
update directory of bundle for tests since protected
chriddyp Jul 2, 2015
5ad5138
fix conflicts
chriddyp Jul 2, 2015
e94e66c
one more
chriddyp Jul 2, 2015
bb72482
fix tests
chriddyp Jul 3, 2015
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
3 changes: 1 addition & 2 deletions circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ machine:
environment:
PLOTLY_PACKAGE_ROOT: /home/ubuntu/python-api
PLOTLY_CONFIG_DIR: ${HOME}/.plotly
PLOTLY_PYTHON_VERSIONS: 2.6.8 2.7.8 3.3.3 3.4.1
PLOTLY_PYTHON_VERSIONS: 2.7.8 3.3.3 3.4.1
PLOTLY_CORE_REQUIREMENTS_FILE: ${PLOTLY_PACKAGE_ROOT}/requirements.txt
PLOTLY_OPTIONAL_REQUIREMENTS_FILE: ${PLOTLY_PACKAGE_ROOT}/optional-requirements.txt
PLOTLY_OPTIONAL_REQUIREMENTS_FILE_2_6: ${PLOTLY_PACKAGE_ROOT}/optional-requirements-2-6.txt
dependencies:
override:

Expand Down
13 changes: 2 additions & 11 deletions circle/setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,8 @@ for version in ${PLOTLY_PYTHON_VERSIONS[@]}; do
pip install -r ${PLOTLY_CORE_REQUIREMENTS_FILE} ||
error_exit "${LINENO}: can't install core reqs for Python ${version}"

# handle funkiness around python 2.6
if [ ${version:0:3} == '2.6' ]
then
pip install -e '.[PY2.6]' ||
error_exit "${LINENO}: can't install extras for Python ${version}"
pip install -r ${PLOTLY_OPTIONAL_REQUIREMENTS_FILE_2_6} ||
error_exit "${LINENO}: can't install optional for Python ${version}"
else
pip install -r ${PLOTLY_OPTIONAL_REQUIREMENTS_FILE} ||
error_exit "${LINENO}: can't install optional for Python ${version}"
fi
pip install -r ${PLOTLY_OPTIONAL_REQUIREMENTS_FILE} ||
error_exit "${LINENO}: can't install optional for Python ${version}"

# install some test tools
pip install nose coverage ||
Expand Down
18 changes: 0 additions & 18 deletions optional-requirements-2-6.txt

This file was deleted.

2 changes: 1 addition & 1 deletion plotly/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,5 @@

from __future__ import absolute_import

from plotly import plotly, graph_objs, grid_objs, tools, utils, session
from plotly import plotly, graph_objs, grid_objs, tools, utils, session, offline
from plotly.version import __version__
10 changes: 10 additions & 0 deletions plotly/offline/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"""
offline
======
This module provides offline functionality.
"""
from . offline import (
download_plotlyjs,
init_notebook_mode,
iplot
)
189 changes: 189 additions & 0 deletions plotly/offline/offline.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
""" Plotly Offline
A module to use Plotly's graphing library with Python
without connecting to a public or private plotly enterprise
server.
"""
from __future__ import absolute_import

import uuid
import json
import os
import requests

from plotly import utils
from plotly import tools
from plotly.exceptions import PlotlyError
from plotly import session

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


__PLOTLY_OFFLINE_INITIALIZED = False


def download_plotlyjs(download_url):
if not os.path.exists(PLOTLY_OFFLINE_DIRECTORY):
os.makedirs(PLOTLY_OFFLINE_DIRECTORY)

res = requests.get(download_url)
res.raise_for_status()

with open(PLOTLY_OFFLINE_BUNDLE, 'wb') as f:
f.write(res.content)

print('\n'.join([
'Success! Now start an IPython notebook and run the following ' +
'code to make your first offline graph:',
'',
'import plotly',
'plotly.offline.init_notebook_mode() '
'# run at the start of every ipython notebook',
'plotly.offline.iplot([{"x": [1, 2, 3], "y": [3, 1, 6]}])'
]))


def init_notebook_mode():
"""
Initialize Plotly Offline mode in an IPython Notebook.
Run this function at the start of an IPython notebook
to load the necessary javascript files for creating
Plotly graphs with plotly.offline.iplot.
"""
if not tools._ipython_imported:
raise ImportError('`iplot` can only run inside an IPython Notebook.')
from IPython.display import HTML, display

if not os.path.exists(PLOTLY_OFFLINE_BUNDLE):
raise PlotlyError('Plotly Offline source file at {source_path} '
'is not found.\n'
'If you have a Plotly Offline license, then try '
'running plotly.offline.download_plotlyjs(url) '
'with a licensed download url.\n'
"Don't have a Plotly Offline license? "
'Contact sales@plot.ly learn more about licensing.\n'
'Questions? support@plot.ly.'
.format(source_path=PLOTLY_OFFLINE_BUNDLE))

global __PLOTLY_OFFLINE_INITIALIZED
__PLOTLY_OFFLINE_INITIALIZED = True
display(HTML('<script type="text/javascript">' +
open(PLOTLY_OFFLINE_BUNDLE).read() + '</script>'))


def iplot(figure_or_data, show_link=True, link_text='Export to plot.ly'):
"""
Draw plotly graphs inside an IPython notebook without
connecting to an external server.
To save the chart to Plotly Cloud or Plotly Enterprise, use
`plotly.plotly.iplot`.
To embed an image of the chart, use `plotly.image.ishow`.

figure_or_data -- a plotly.graph_objs.Figure or plotly.graph_objs.Data or
dict or list that describes a Plotly graph.
See https://plot.ly/python/ for examples of
graph descriptions.

Keyword arguments:
show_link (default=True) -- display a link in the bottom-right corner of
of the chart that will export the chart to
Plotly Cloud or Plotly Enterprise
link_text (default='Export to plot.ly') -- the text of export link

Example:
```
from plotly.offline import init_notebook_mode, iplot
init_notebook_mode()

iplot([{'x': [1, 2, 3], 'y': [5, 2, 7]}])
```
"""
if not __PLOTLY_OFFLINE_INITIALIZED:
raise PlotlyError('\n'.join([
'Plotly Offline mode has not been initialized in this notebook. '
'Run: ',
'',
'import plotly',
'plotly.offline.init_notebook_mode() '
'# run at the start of every ipython notebook',
]))
if not tools._ipython_imported:
raise ImportError('`iplot` can only run inside an IPython Notebook.')

from IPython.display import HTML, display
if isinstance(figure_or_data, dict):
data = figure_or_data['data']
layout = figure_or_data.get('layout', {})
else:
data = figure_or_data
layout = {}

width = layout.get('width', '100%')
height = layout.get('height', 525)
try:
float(width)
except (ValueError, TypeError):
pass
else:
width = str(width) + 'px'

try:
float(width)
except (ValueError, TypeError):
pass
else:
width = str(width) + 'px'

plotdivid = uuid.uuid4()
jdata = json.dumps(data, cls=utils.PlotlyJSONEncoder)
jlayout = json.dumps(layout, cls=utils.PlotlyJSONEncoder)

if show_link is False:
link_text = ''

plotly_platform_url = session.get_session_config().get('plotly_domain',
'https://plot.ly')
if (plotly_platform_url != 'https://plot.ly' and
link_text == 'Export to plot.ly'):

link_domain = plotly_platform_url\
.replace('https://', '')\
.replace('http://', '')
link_text = link_text.replace('plot.ly', link_domain)

display(HTML(
'<script type="text/javascript">'
'window.PLOTLYENV={"BASE_URL": "' + plotly_platform_url + '"};'
'Plotly.LINKTEXT = "' + link_text + '";'
'</script>'
))

script = '\n'.join([
'Plotly.plot("{id}", {data}, {layout}).then(function() {{',
' $(".{id}.loading").remove();',
'}})'
]).format(id=plotdivid,
data=jdata,
layout=jlayout,
link_text=link_text)

display(HTML(''
'<div class="{id} loading" style="color: rgb(50,50,50);">'
'Drawing...</div>'
'<div id="{id}" style="height: {height}; width: {width};" '
'class="plotly-graph-div">'
'</div>'
'<script type="text/javascript">'
'{script}'
'</script>'
''.format(id=plotdivid, script=script,
height=height, width=width)))


def plot():
""" Configured to work with localhost Plotly graph viewer
"""
raise NotImplementedError

21 changes: 21 additions & 0 deletions plotly/tests/test_core/test_offline/test_offline.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"""
test__offline

"""
from __future__ import absolute_import

import os
from unittest import TestCase

import plotly


class PlotlyOfflineTestCase(TestCase):
def test_downloading_file_saves_it_to_the_disk(self):
dummy_js_url = ('https://gist.githubusercontent.com/chriddyp/'
'f40bd33d1eab6f0715dc/raw/'
'24cd2e4e62ceea79e6e790b3a2c94cda63510ede/test.js')

plotly.offline.download_plotlyjs(dummy_js_url)
assert (os.path.isfile(plotly.offline.offline.PLOTLY_OFFLINE_BUNDLE) is
True)
41 changes: 41 additions & 0 deletions plotly/tests/test_optional/test_offline/test_offline.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""
test__offline

"""
from __future__ import absolute_import
from nose.tools import raises
from unittest import TestCase
import os

from plotly.exceptions import PlotlyError
import plotly

dummy_js_url = ('https://gist.githubusercontent.com/chriddyp/'
'f40bd33d1eab6f0715dc/raw/'
'24cd2e4e62ceea79e6e790b3a2c94cda63510ede/'
'test.js')


class PlotlyOfflineTestCase(TestCase):
def _remove_plotlyjs(self):
try:
os.remove(plotly.offline.offline.PLOTLY_OFFLINE_BUNDLE)
except OSError:
pass

def test_no_errors_are_raised_when_initializing_offline_mode(self):
self._remove_plotlyjs()
plotly.offline.download_plotlyjs(dummy_js_url)
plotly.offline.init_notebook_mode()
plotly.offline.iplot([{'x': [1, 2, 3]}])

@raises(PlotlyError)
def test_calling_iplot_before_initializing_raises_an_error(self):
self._remove_plotlyjs()
plotly.offline.download_plotlyjs(dummy_js_url)
plotly.offline.iplot([{'x': [1, 2, 3]}])

@raises(PlotlyError)
def test_initializing_before_downloading_raises_an_error(self):
self._remove_plotlyjs()
plotly.offline.init_notebook_mode()
2 changes: 1 addition & 1 deletion plotly/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '1.6.19'
__version__ = '1.7.0'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😸

2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def readme():
author_email='chris@plot.ly',
maintainer='Chris P',
maintainer_email='chris@plot.ly',
url='https://plot.ly/api/python',
url='https://plot.ly/python/',
description="Python plotting library for collaborative, "
"interactive, publication-quality graphs.",
long_description=readme(),
Expand Down