Skip to content

Commit e4af3e0

Browse files
committed
Merge pull request #1 from plotly/offline-plot
🎆 offline `plot` command
2 parents 77f86cc + a077134 commit e4af3e0

File tree

2 files changed

+175
-65
lines changed

2 files changed

+175
-65
lines changed

plotly/offline/__init__.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@
66
from . offline import (
77
download_plotlyjs,
88
init_notebook_mode,
9-
iplot
9+
iplot,
10+
plot
1011
)

plotly/offline/offline.py

+173-64
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import uuid
1111
import warnings
1212
from pkg_resources import resource_string
13+
import webbrowser
1314

1415
import plotly
1516
from plotly import tools, utils
@@ -57,6 +58,72 @@ def init_notebook_mode():
5758
'</script>'))
5859

5960

61+
def _plot_html(figure_or_data, show_link, link_text,
62+
validate, default_width, default_height):
63+
64+
figure = tools.return_figure_from_figure_or_data(figure_or_data, validate)
65+
66+
width = figure.get('layout', {}).get('width', default_width)
67+
height = figure.get('layout', {}).get('height', default_height)
68+
69+
try:
70+
float(width)
71+
except (ValueError, TypeError):
72+
pass
73+
else:
74+
width = str(width) + 'px'
75+
76+
try:
77+
float(width)
78+
except (ValueError, TypeError):
79+
pass
80+
else:
81+
width = str(width) + 'px'
82+
83+
plotdivid = uuid.uuid4()
84+
jdata = json.dumps(figure.get('data', []), cls=utils.PlotlyJSONEncoder)
85+
jlayout = json.dumps(figure.get('layout', {}), cls=utils.PlotlyJSONEncoder)
86+
87+
config = {}
88+
config['showLink'] = show_link
89+
config['linkText'] = link_text
90+
jconfig = json.dumps(config)
91+
92+
# TODO: The get_config 'source of truth' should
93+
# really be somewhere other than plotly.plotly
94+
plotly_platform_url = plotly.plotly.get_config().get('plotly_domain',
95+
'https://plot.ly')
96+
if (plotly_platform_url != 'https://plot.ly' and
97+
link_text == 'Export to plot.ly'):
98+
99+
link_domain = plotly_platform_url\
100+
.replace('https://', '')\
101+
.replace('http://', '')
102+
link_text = link_text.replace('plot.ly', link_domain)
103+
104+
script = 'Plotly.plot("{id}", {data}, {layout}, {config})'.format(
105+
id=plotdivid,
106+
data=jdata,
107+
layout=jlayout,
108+
config=jconfig)
109+
110+
plotly_html_div = (
111+
''
112+
'<div id="{id}" style="height: {height}; width: {width};" '
113+
'class="plotly-graph-div">'
114+
'</div>'
115+
'<script type="text/javascript">'
116+
'window.PLOTLYENV=window.PLOTLYENV || {{}};'
117+
'window.PLOTLYENV.BASE_URL="' + plotly_platform_url + '";'
118+
'{script}'
119+
'</script>'
120+
'').format(
121+
id=plotdivid, script=script,
122+
height=height, width=width)
123+
124+
return plotly_html_div, plotdivid, width, height
125+
126+
60127
def iplot(figure_or_data, show_link=True, link_text='Export to plot.ly',
61128
validate=True):
62129
"""
@@ -103,76 +170,118 @@ def iplot(figure_or_data, show_link=True, link_text='Export to plot.ly',
103170
raise ImportError('`iplot` can only run inside an IPython Notebook.')
104171

105172
from IPython.display import HTML, display
106-
figure = tools.return_figure_from_figure_or_data(figure_or_data, validate)
107173

108-
width = figure.get('layout', {}).get('width', '100%')
109-
height = figure.get('layout', {}).get('height', 525)
110-
try:
111-
float(width)
112-
except (ValueError, TypeError):
113-
pass
114-
else:
115-
width = str(width) + 'px'
174+
display(HTML(_plot_html(
175+
figure_or_data, show_link, link_text, validate,
176+
'100%', 525)))
116177

117-
try:
118-
float(width)
119-
except (ValueError, TypeError):
120-
pass
121-
else:
122-
width = str(width) + 'px'
123178

124-
plotdivid = uuid.uuid4()
125-
jdata = json.dumps(figure.get('data', []), cls=utils.PlotlyJSONEncoder)
126-
jlayout = json.dumps(figure.get('layout', {}), cls=utils.PlotlyJSONEncoder)
179+
def plot(figure_or_data,
180+
show_link=True, link_text='Export to plot.ly',
181+
validate=True, output_type='file',
182+
include_plotlyjs=True,
183+
filename='temp-plot.html',
184+
auto_open=True):
185+
""" Create a plotly graph locally as an HTML document or string.
127186
128-
config = {}
129-
config['showLink'] = show_link
130-
config['linkText'] = link_text
131-
jconfig = json.dumps(config)
187+
Example:
188+
```
189+
from plotly.offline import plot
190+
import plotly.graph_objs as go
132191
133-
# TODO: The get_config 'source of truth' should
134-
# really be somewhere other than plotly.plotly
135-
plotly_platform_url = plotly.plotly.get_config().get('plotly_domain',
136-
'https://plot.ly')
137-
if (plotly_platform_url != 'https://plot.ly' and
138-
link_text == 'Export to plot.ly'):
192+
plot([
193+
go.Scatter(x=[1, 2, 3], y=[3, 2 6])
194+
], filename='my-graph.html')
195+
```
196+
More examples below.
139197
140-
link_domain = plotly_platform_url\
141-
.replace('https://', '')\
142-
.replace('http://', '')
143-
link_text = link_text.replace('plot.ly', link_domain)
198+
figure_or_data -- a plotly.graph_objs.Figure or plotly.graph_objs.Data or
199+
dict or list that describes a Plotly graph.
200+
See https://plot.ly/python/ for examples of
201+
graph descriptions.
144202
145-
display(HTML(
146-
'<script type="text/javascript">'
147-
'window.PLOTLYENV=window.PLOTLYENV || {};'
148-
'window.PLOTLYENV.BASE_URL="' + plotly_platform_url + '";'
149-
'</script>'
150-
))
151-
152-
script = '\n'.join([
153-
'Plotly.plot("{id}", {data}, {layout}, {config}).then(function() {{',
154-
' $(".{id}.loading").remove();',
155-
'}})'
156-
]).format(id=plotdivid,
157-
data=jdata,
158-
layout=jlayout,
159-
config=jconfig)
160-
161-
display(HTML(''
162-
'<div class="{id} loading" style="color: rgb(50,50,50);">'
163-
'Drawing...</div>'
164-
'<div id="{id}" style="height: {height}; width: {width};" '
165-
'class="plotly-graph-div">'
166-
'</div>'
167-
'<script type="text/javascript">'
168-
'{script}'
169-
'</script>'
170-
''.format(id=plotdivid, script=script,
171-
height=height, width=width)))
172-
173-
174-
def plot():
175-
""" Configured to work with localhost Plotly graph viewer
203+
Keyword arguments:
204+
show_link (default=True) -- display a link in the bottom-right corner of
205+
of the chart that will export the chart to Plotly Cloud or
206+
Plotly Enterprise
207+
link_text (default='Export to plot.ly') -- the text of export link
208+
validate (default=True) -- validate that all of the keys in the figure
209+
are valid? omit if your version of plotly.js has become outdated
210+
with your version of graph_reference.json or if you need to include
211+
extra, unnecessary keys in your figure.
212+
output_type ('file' | 'div' - default 'file') -- if 'file', then
213+
the graph is saved as a standalone HTML file and `plot`
214+
returns None.
215+
If 'div', then `plot` returns a string that just contains the
216+
HTML <div> that contains the graph and the script to generate the
217+
graph.
218+
Use 'file' if you want to save and view a single graph at a time
219+
in a standalone HTML file.
220+
Use 'div' if you are embedding these graphs in an HTML file with
221+
other graphs or HTML markup, like a HTML report or an website.
222+
include_plotlyjs (default=True) -- If True, include the plotly.js
223+
source code in the output file or string.
224+
Set as False if your HTML file already contains a copy of the plotly.js
225+
library.
226+
filename (default='temp-plot.html') -- The local filename to save the
227+
outputted chart to. If the filename already exists, it will be
228+
overwritten. This argument only applies if `output_type` is 'file'.
229+
auto_open (default=True) -- If True, open the saved file in a
230+
web browser after saving.
231+
This argument only applies if `output_type` is 'file'.
176232
"""
177-
raise NotImplementedError
233+
plot_html, plotdivid, width, height = _plot_html(
234+
figure_or_data, show_link, link_text, validate,
235+
'100%', '100%')
236+
237+
figure = tools.return_figure_from_figure_or_data(figure_or_data, validate)
238+
239+
resize_script = ''
240+
if width == '100%' or height == '100%':
241+
resize_script = (
242+
''
243+
'<script type="text/javascript">'
244+
'window.removeEventListener("resize");'
245+
'window.addEventListener("resize", function(){{'
246+
'console.log("resize");'
247+
'Plotly.Plots.resize(document.getElementById("{id}"));}});'
248+
'</script>'
249+
).format(id=plotdivid)
250+
251+
if output_type == 'file':
252+
filename = 'plotly-temp.html'
253+
with open(filename, 'w') as f:
254+
if include_plotlyjs:
255+
plotly_js_script = ''.join([
256+
'<script type="text/javascript">',
257+
get_plotlyjs(),
258+
'</script>',
259+
])
260+
else:
261+
plotly_js_script = ''
262+
263+
f.write(''.join([
264+
'<html>',
265+
'<head><meta charset="utf-8" /></head>',
266+
'<body>',
267+
plotly_js_script,
268+
plot_html,
269+
resize_script,
270+
'</body>',
271+
'</html>']))
272+
273+
if auto_open:
274+
webbrowser.open('file://' + os.path.abspath(filename))
178275

276+
elif output_type == 'div':
277+
if include_plotlyjs:
278+
return ''.join([
279+
'<div>',
280+
'<script type="text/javascript">',
281+
get_plotlyjs(),
282+
'</script>',
283+
plot_html,
284+
'</div>'
285+
])
286+
else:
287+
return plot_html

0 commit comments

Comments
 (0)