Skip to content

added option to download an image of the most recent plot #494

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 40 commits into from
Jun 15, 2016
Merged
Changes from 35 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
d2b9880
added option to download an image of the most recent plot
yankev Jun 2, 2016
89c53db
remove an alert, change name of function
yankev Jun 2, 2016
c769ad6
updated docstring
yankev Jun 2, 2016
555d89a
removed unused variable `selected`
yankev Jun 2, 2016
6ff77d6
more docstring updates
yankev Jun 2, 2016
78fc1d7
added the ability to download plots when calling iplot
yankev Jun 3, 2016
341e87f
fixed the inline download method
yankev Jun 3, 2016
17485bc
renamed variables so tests will pass
yankev Jun 3, 2016
8eae6bd
attempt at stopping image download on future notebook openings
yankev Jun 4, 2016
ad728a3
fixed the download on refresh
yankev Jun 4, 2016
b2f9db9
fixing code to fix tests
yankev Jun 4, 2016
bdb4b85
Revert "fixing code to fix tests"
yankev Jun 4, 2016
0effa54
removed redundant return from _plot_html
yankev Jun 4, 2016
3172843
removed unused download arguments
yankev Jun 4, 2016
151f23e
providing functionality to all offline plot calls
yankev Jun 5, 2016
cae796e
pep8 and edit message in confirmation to download image
yankev Jun 5, 2016
8b39241
fixed typo
yankev Jun 5, 2016
e20da3e
ensuring the use of the correct argument names, and proper assignment…
yankev Jun 5, 2016
6abf3f9
added new arguments to docstrings
yankev Jun 5, 2016
cac15c5
changed `download_image` parameter to `image`
yankev Jun 7, 2016
a49d903
changed default value for image_filename
yankev Jun 7, 2016
f7d972c
added warning messages indicating the option to use `py.image`
yankev Jun 7, 2016
4256891
changed default filename for `download_notebook_image`
yankev Jun 7, 2016
d447ae4
add download image examples, update more default values
yankev Jun 7, 2016
bd46038
more docstring fixes and amending examples
yankev Jun 7, 2016
1c7d517
removed `download_notebook_image()` function
yankev Jun 7, 2016
f5baa3e
removed `download_notebook_image` from module init
yankev Jun 7, 2016
dbbad22
merged image and format into one parameter: image
yankev Jun 8, 2016
5bf4dd5
added new logic to deal with the new image parameter (iplot, plot)
yankev Jun 10, 2016
1892ab6
rename some arguments, typos, and formatting
yankev Jun 10, 2016
94a55f9
added confirm message to iplot mode
yankev Jun 10, 2016
6ea4e6d
edit value error
yankev Jun 10, 2016
e60a5dd
put download scripts into a function
yankev Jun 10, 2016
f44ad45
remove old scripts replaced by function calls
yankev Jun 10, 2016
e943120
remove image server warnings
yankev Jun 10, 2016
7b4681a
address PR comments
yankev Jun 14, 2016
0582283
fixed function names, as well as added a better check for the caller …
yankev Jun 14, 2016
8689112
Revert "fixed function names, as well as added a better check for the…
yankev Jun 14, 2016
cf90fba
renamed calls to `get_image_download_script` and fixed docstring
yankev Jun 14, 2016
4235cd4
fix ValueError message
yankev Jun 14, 2016
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
140 changes: 130 additions & 10 deletions plotly/offline/offline.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@

__PLOTLY_OFFLINE_INITIALIZED = False

__IMAGE_FORMATS = ['jpeg', 'png', 'webp', 'svg']


def download_plotlyjs(download_url):
warnings.warn('''
Expand All @@ -46,6 +48,37 @@ def get_plotlyjs():
plotlyjs = resource_string('plotly', path).decode('utf-8')
return plotlyjs

def image_download_script(type):
Copy link
Contributor

Choose a reason for hiding this comment

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

🎎 can you add a docstring for this that explains the type parameter?

Copy link
Contributor

Choose a reason for hiding this comment

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

🐄 get_image_download_script?


if type == 'iplot':
check_start = 'if(document.readyState == \'complete\') {{'
check_end = '}}'
elif type == 'plot':
check_start = ''
check_end = ''
Copy link
Contributor

Choose a reason for hiding this comment

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

🐄

else:
    raise SomeException( .. )

?


return(
('<script>'
'function downloadimage(format, height, width,'
' filename) {{'
'var p = document.getElementById(\'{plot_id}\');'
'Plotly.downloadImage(p, {{format: format, height: height, '
'width: width, filename: filename}});'
'}};' +
check_start +
'if(confirm(\'Do you want to save this image as '
'{filename}.{format}?\\n\\n'
'For higher resolution images and more export options, '
'consider making requests to our image servers. Type: '
'help(py.image) for more details.'
'\')) {{'
'downloadimage(\'{format}\', {height}, {width}, '
'\'{filename}\');}}' +
check_end +
'</script>'
)
)


def init_notebook_mode(connected=False):
"""
Expand Down Expand Up @@ -114,8 +147,8 @@ def init_notebook_mode(connected=False):
__PLOTLY_OFFLINE_INITIALIZED = True


def _plot_html(figure_or_data, show_link, link_text,
validate, default_width, default_height, global_requirejs):
def _plot_html(figure_or_data, show_link, link_text, validate,
default_width, default_height, global_requirejs):

figure = tools.return_figure_from_figure_or_data(figure_or_data, validate)

Expand Down Expand Up @@ -185,9 +218,9 @@ def _plot_html(figure_or_data, show_link, link_text,

return plotly_html_div, plotdivid, width, height


def iplot(figure_or_data, show_link=True, link_text='Export to plot.ly',
validate=True):
validate=True, image=None, filename='plot_image', image_width=800,
image_height=600):
"""
Draw plotly graphs inside an IPython notebook without
connecting to an external server.
Expand All @@ -210,12 +243,23 @@ def iplot(figure_or_data, show_link=True, link_text='Export to plot.ly',
has become outdated with your version of
graph_reference.json or if you need to include
extra, unnecessary keys in your figure.
image (default=None |'png' |'jpeg' |'svg' |'webp') -- This parameter sets
the format of the image to be downloaded, if we choose to download an
image. This parameter has a default value of None indicating that no
image should be downloaded.
filename (default='plot') -- Sets the name of the file your image
will be saved to. The extension should not be included.
image_height (default=600) -- Specifies the height of the image in `px`.
image_width (default=800) -- Specifies the width of the image in `px`.

Example:
```
from plotly.offline import init_notebook_mode, iplot
init_notebook_mode()
iplot([{'x': [1, 2, 3], 'y': [5, 2, 7]}])
# We can also download an image of the plot by setting the image to the
format you want ie: `image='png'`
Copy link
Contributor

Choose a reason for hiding this comment

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

🐐 this is an example, not an explanation so ie: --> e.g., Also, i.e., not ie:. ;)

iplot([{'x': [1, 2, 3], 'y': [5, 2, 7]}], image='png')
```
"""
if not __PLOTLY_OFFLINE_INITIALIZED:
Expand All @@ -236,13 +280,32 @@ def iplot(figure_or_data, show_link=True, link_text='Export to plot.ly',

display(HTML(plot_html))

if image:
if image not in __IMAGE_FORMATS:
raise ValueError('The image parameter takes only the '
'following format types: `png`, `jpeg`, '
'`webp`, `svg`')
# if the check passes then download script injection will commence.
# Write script to download image of the plot
Copy link
Contributor

Choose a reason for hiding this comment

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

🎎 This comment could be cleaner. Also, you might not really need the second line here, it's clear from the code.

script = image_download_script('iplot').format(format=image,
width=image_width,
height=image_height,
filename=filename,
plot_id=plotdivid)
# allow time for the plot to draw
import time
Copy link
Contributor

Choose a reason for hiding this comment

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

🐄 This import should be at the top of the module. Let me know if you need a better explanation for why this is the case.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm, this could potentially get called a lot, so it might be a time saver to load it at the top. Let me know if that's why, or if you have additional reasons.

Copy link
Contributor

@theengineear theengineear Jun 14, 2016

Choose a reason for hiding this comment

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

Yah, exactly it's faster to put it at the top, it's also better Python style. Here's a quick note on it:

http://stackoverflow.com/questions/128478/should-python-import-statements-always-be-at-the-top-of-a-module

time.sleep(1)
Copy link
Contributor

@theengineear theengineear Jun 8, 2016

Choose a reason for hiding this comment

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

Will this work for plots that take > 1 second to download draw?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right so this is a bit of a concern. The most complicated plot I tried was one with 300 boxplots, I also dropped time.sleep to 0.1 and there was no issue. I'm not really sure of a way to guarantee this success though.

# inject code to download an image of the plot
display(HTML(script))


def plot(figure_or_data,
show_link=True, link_text='Export to plot.ly',
validate=True, output_type='file',
include_plotlyjs=True,
filename='temp-plot.html',
auto_open=True):
filename='temp-plot.html', auto_open=True,
Copy link
Contributor

Choose a reason for hiding this comment

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

This won't flake if you don't supply a filename twice, right? Will we end up with temp-plot.html (1) or something? Or, does the OS just handle it?

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, nvm, looks like this was here before your changes. 👍

image=None, image_filename='plot_image',
image_width=800, image_height=600):
""" Create a plotly graph locally as an HTML document or string.

Example:
Expand All @@ -251,6 +314,10 @@ def plot(figure_or_data,
import plotly.graph_objs as go

plot([go.Scatter(x=[1, 2, 3], y=[3, 2, 6])], filename='my-graph.html')
# We can also download an image of the plot by setting the image parameter
# to the image format we want
plot([go.Scatter(x=[1, 2, 3], y=[3, 2, 6])], filename='my-graph.html'
image='jpeg')
```
More examples below.

Expand Down Expand Up @@ -288,6 +355,14 @@ def plot(figure_or_data,
auto_open (default=True) -- If True, open the saved file in a
web browser after saving.
This argument only applies if `output_type` is 'file'.
image (default=None |'png' |'jpeg' |'svg' |'webp') -- This parameter sets
the format of the image to be downloaded, if we choose to download an
image. This parameter has a default value of None indicating that no
image should be downloaded.
image_filename (default='plot_image') -- Sets the name of the file your image
will be saved to. The extension should not be included.
image_height (default=600) -- Specifies the height of the image in `px`.
image_width (default=800) -- Specifies the width of the image in `px`.
"""
if output_type not in ['div', 'file']:
raise ValueError(
Expand Down Expand Up @@ -325,13 +400,30 @@ def plot(figure_or_data,
else:
plotly_js_script = ''

if image:
if image not in __IMAGE_FORMATS:
raise ValueError('The image parameter takes only the '
'following format types: `png`, `jpeg`, '
'`webp`, `svg`')
Copy link
Contributor

Choose a reason for hiding this comment

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

🐫! Use the actual values of __IMAGE_FORMATS here.

# if the check passes then download script is injected.
# write the download script:
Copy link
Contributor

Choose a reason for hiding this comment

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

script = image_download_script('plot')
script = script.format(format=image,
width=image_width,
height=image_height,
filename=image_filename,
plot_id=plotdivid)
else:
script = ''

f.write(''.join([
'<html>',
'<head><meta charset="utf-8" /></head>',
'<body>',
plotly_js_script,
plot_html,
resize_script,
script,
'</body>',
'</html>']))

Expand All @@ -358,7 +450,9 @@ def plot(figure_or_data,
def plot_mpl(mpl_fig, resize=False, strip_style=False,
verbose=False, show_link=True, link_text='Export to plot.ly',
validate=True, output_type='file', include_plotlyjs=True,
filename='temp-plot.html', auto_open=True):
filename='temp-plot.html', auto_open=True,
image=None, image_filename='plot_image',
image_height=600, image_width=800):
"""
Convert a matplotlib figure to a Plotly graph stored locally as HTML.

Expand Down Expand Up @@ -402,6 +496,14 @@ def plot_mpl(mpl_fig, resize=False, strip_style=False,
auto_open (default=True) -- If True, open the saved file in a
web browser after saving.
This argument only applies if `output_type` is 'file'.
image (default=None |'png' |'jpeg' |'svg' |'webp') -- This parameter sets
the format of the image to be downloaded, if we choose to download an
image. This parameter has a default value of None indicating that no
image should be downloaded.
image_filename (default='plot_image') -- Sets the name of the file your
image will be saved to. The extension should not be included.
image_height (default=600) -- Specifies the height of the image in `px`.
image_width (default=800) -- Specifies the width of the image in `px`.

Example:
```
Expand All @@ -416,16 +518,22 @@ def plot_mpl(mpl_fig, resize=False, strip_style=False,
plt.plot(x, y, "o")

plot_mpl(fig)
# If you want to to download an image of the figure as well
plot_mpl(fig, image='png')
```
"""
plotly_plot = tools.mpl_to_plotly(mpl_fig, resize, strip_style, verbose)
return plot(plotly_plot, show_link, link_text, validate, output_type,
include_plotlyjs, filename, auto_open)
include_plotlyjs, filename, auto_open,
image=image, image_filename=image_filename,
image_height=image_height, image_width=image_width)


def iplot_mpl(mpl_fig, resize=False, strip_style=False,
verbose=False, show_link=True,
link_text='Export to plot.ly', validate=True):
link_text='Export to plot.ly', validate=True,
image=None, image_filename='plot_image',
image_height=600, image_width=800):
"""
Convert a matplotlib figure to a plotly graph and plot inside an IPython
notebook without connecting to an external server.
Expand Down Expand Up @@ -454,6 +562,14 @@ def iplot_mpl(mpl_fig, resize=False, strip_style=False,
has become outdated with your version of
graph_reference.json or if you need to include
extra, unnecessary keys in your figure.
image (default=None |'png' |'jpeg' |'svg' |'webp') -- This parameter sets
the format of the image to be downloaded, if we choose to download an
image. This parameter has a default value of None indicating that no
image should be downloaded.
image_filename (default='plot_image') -- Sets the name of the file your
image will be saved to. The extension should not be included.
image_height (default=600) -- Specifies the height of the image in `px`.
image_width (default=800) -- Specifies the width of the image in `px`.

Example:
```
Expand All @@ -467,10 +583,14 @@ def iplot_mpl(mpl_fig, resize=False, strip_style=False,

init_notebook_mode()
iplot_mpl(fig)
# and if you want to download an image of the figure as well
iplot_mpl(fig, image='jpeg')
```
"""
plotly_plot = tools.mpl_to_plotly(mpl_fig, resize, strip_style, verbose)
return iplot(plotly_plot, show_link, link_text, validate)
return iplot(plotly_plot, show_link, link_text, validate,
image=image, filename=image_filename,
image_height=image_height, image_width=image_width)


def enable_mpl_offline(resize=False, strip_style=False,
Expand Down