Skip to content

Commit

Permalink
Adding auto start animation_opts argument to html export and html ren…
Browse files Browse the repository at this point in the history
…derers (#1503)
  • Loading branch information
TakodaS authored and jonmmease committed Apr 10, 2019
1 parent bb5c998 commit 82a62ff
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 20 deletions.
45 changes: 34 additions & 11 deletions plotly/io/_base_renderers.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,8 @@ def __init__(self,
global_init=False,
config=None,
auto_play=False,
post_script=None):
post_script=None,
animation_opts=None):

self.config = dict(config) if config else {}
self.auto_play = auto_play
Expand All @@ -238,6 +239,7 @@ def __init__(self,
self.requirejs = requirejs
self.full_html = full_html
self.post_script = post_script
self.animation_opts = animation_opts

def activate(self):
if self.global_init:
Expand Down Expand Up @@ -315,7 +317,8 @@ def to_mimebundle(self, fig_dict):
include_plotlyjs=include_plotlyjs,
include_mathjax=include_mathjax,
post_script=self.post_script,
full_html=self.full_html)
full_html=self.full_html,
animation_opts=self.animation_opts)

return {'text/html': html}

Expand All @@ -336,15 +339,17 @@ def __init__(self,
connected=False,
config=None,
auto_play=False,
post_script=None):
post_script=None,
animation_opts=None):
super(NotebookRenderer, self).__init__(
connected=connected,
full_html=False,
requirejs=True,
global_init=True,
config=config,
auto_play=auto_play,
post_script=post_script)
post_script=post_script,
animation_opts=animation_opts)


class KaggleRenderer(HtmlRenderer):
Expand All @@ -358,15 +363,21 @@ class KaggleRenderer(HtmlRenderer):
mime type: 'text/html'
"""
def __init__(self, config=None, auto_play=False, post_script=None):
def __init__(self,
config=None,
auto_play=False,
post_script=None,
animation_opts=None):

super(KaggleRenderer, self).__init__(
connected=True,
full_html=False,
requirejs=True,
global_init=True,
config=config,
auto_play=auto_play,
post_script=post_script)
post_script=post_script,
animation_opts=animation_opts)


class ColabRenderer(HtmlRenderer):
Expand All @@ -377,15 +388,21 @@ class ColabRenderer(HtmlRenderer):
mime type: 'text/html'
"""
def __init__(self, config=None, auto_play=False, post_script=None):
def __init__(self,
config=None,
auto_play=False,
post_script=None,
animation_opts=None):

super(ColabRenderer, self).__init__(
connected=True,
full_html=True,
requirejs=False,
global_init=False,
config=config,
auto_play=auto_play,
post_script=post_script)
post_script=post_script,
animation_opts=animation_opts)


class IFrameRenderer(MimetypeRenderer):
Expand Down Expand Up @@ -414,11 +431,13 @@ class IFrameRenderer(MimetypeRenderer):
def __init__(self,
config=None,
auto_play=False,
post_script=None):
post_script=None,
animation_opts=None):

self.config = config
self.auto_play = auto_play
self.post_script = post_script
self.animation_opts = animation_opts

def to_mimebundle(self, fig_dict):
from plotly.io import write_html
Expand Down Expand Up @@ -457,6 +476,7 @@ def to_mimebundle(self, fig_dict):
include_mathjax='cdn',
auto_open=False,
post_script=self.post_script,
animation_opts=self.animation_opts,
validate=False)

# Build IFrame
Expand Down Expand Up @@ -547,14 +567,16 @@ def __init__(self,
using=None,
new=0,
autoraise=True,
post_script=None):
post_script=None,
animation_opts=None):

self.config = config
self.auto_play = auto_play
self.using = using
self.new = new
self.autoraise = autoraise
self.post_script = post_script
self.animation_opts = animation_opts

def render(self, fig_dict):
renderer = HtmlRenderer(
Expand All @@ -564,7 +586,8 @@ def render(self, fig_dict):
global_init=False,
config=self.config,
auto_play=self.auto_play,
post_script=self.post_script)
post_script=self.post_script,
animation_opts=self.animation_opts)

bundle = renderer.to_mimebundle(fig_dict)
html = bundle['text/html']
Expand Down
26 changes: 23 additions & 3 deletions plotly/io/_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ def to_html(fig,
include_mathjax=False,
post_script=None,
full_html=True,
animation_opts=None,
validate=True):
"""
Convert a figure to an HTML string representation.
Expand Down Expand Up @@ -102,6 +103,12 @@ def to_html(fig,
If True, produce a string containing a complete HTML document
starting with an <html> tag. If False, produce a string containing
a single <div> element.
animation_opts: dict or None (default None)
dict of custom animation parameters to be passed to the function
Plotly.animate in Plotly.js. See
https://github.com/plotly/plotly.js/blob/master/src/plots/animation_attributes.js
for available options. Has no effect if the figure does not contain
frames, or auto_play is False.
validate: bool (default True)
True if the figure should be validated before being converted to
JSON, False otherwise.
Expand Down Expand Up @@ -164,9 +171,14 @@ def to_html(fig,
}})""".format(id=plotdivid, frames=jframes)

if auto_play:
if animation_opts:
animation_opts_arg = ', ' + json.dumps(animation_opts)
else:
animation_opts_arg = ''
then_animate = """.then(function(){{
Plotly.animate('{id}');
}})""".format(id=plotdivid)
Plotly.animate('{id}', null{animation_opts});
}})""".format(id=plotdivid,
animation_opts=animation_opts_arg)

script = """
if (document.getElementById("{id}")) {{
Expand Down Expand Up @@ -299,6 +311,7 @@ def write_html(fig,
include_mathjax=False,
post_script=None,
full_html=True,
animation_opts=None,
validate=True,
auto_open=False):
"""
Expand Down Expand Up @@ -390,6 +403,12 @@ def write_html(fig,
If True, produce a string containing a complete HTML document
starting with an <html> tag. If False, produce a string containing
a single <div> element.
animation_opts: dict or None (default None)
dict of custom animation parameters to be passed to the function
Plotly.animate in Plotly.js. See
https://github.com/plotly/plotly.js/blob/master/src/plots/animation_attributes.js
for available options. Has no effect if the figure does not contain
frames, or auto_play is False.
validate: bool (default True)
True if the figure should be validated before being converted to
JSON, False otherwise.
Expand All @@ -411,7 +430,8 @@ def write_html(fig,
include_mathjax=include_mathjax,
post_script=post_script,
full_html=full_html,
validate=validate)
validate=validate,
animation_opts=animation_opts)

# Check if file is a string
file_is_str = isinstance(file, six.string_types)
Expand Down
50 changes: 46 additions & 4 deletions plotly/offline/offline.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ def init_notebook_mode(connected=False):

def iplot(figure_or_data, show_link=False, link_text='Export to plot.ly',
validate=True, image=None, filename='plot_image', image_width=800,
image_height=600, config=None, auto_play=True):
image_height=600, config=None, auto_play=True, animation_opts=None):
"""
Draw plotly graphs inside an IPython or Jupyter notebook
Expand Down Expand Up @@ -329,6 +329,11 @@ def iplot(figure_or_data, show_link=False, link_text='Export to plot.ly',
auto_play (default=True) -- Whether to automatically start the animation
sequence if the figure contains frames. Has no effect if the figure
does not contain frames.
animation_opts (default=None) -- dict of custom animation parameters to be
passed to the function Plotly.animate in Plotly.js. See
https://github.com/plotly/plotly.js/blob/master/src/plots/animation_attributes.js
for available options. Has no effect if the figure
does not contain frames, or auto_play is False.
Example:
```
Expand All @@ -339,6 +344,20 @@ def iplot(figure_or_data, show_link=False, link_text='Export to plot.ly',
format you want. e.g. `image='png'`
iplot([{'x': [1, 2, 3], 'y': [5, 2, 7]}], image='png')
```
animation_opts Example:
```
from plotly.offline import iplot
figure = {'data': [{'x': [0, 1], 'y': [0, 1]}],
'layout': {'xaxis': {'range': [0, 5], 'autorange': False},
'yaxis': {'range': [0, 5], 'autorange': False},
'title': 'Start Title'},
'frames': [{'data': [{'x': [1, 2], 'y': [1, 2]}]},
{'data': [{'x': [1, 4], 'y': [1, 4]}]},
{'data': [{'x': [3, 4], 'y': [3, 4]}],
'layout': {'title': 'End Title'}}]}
iplot(figure,animation_opts="{frame: {duration: 1}}")
```
"""
import plotly.io as pio

Expand All @@ -361,14 +380,16 @@ def iplot(figure_or_data, show_link=False, link_text='Export to plot.ly',
validate=validate,
config=config,
auto_play=auto_play,
post_script=post_script)
post_script=post_script,
animation_opts=animation_opts)


def plot(figure_or_data, show_link=False, link_text='Export to plot.ly',
validate=True, output_type='file', include_plotlyjs=True,
filename='temp-plot.html', auto_open=True, image=None,
image_filename='plot_image', image_width=800, image_height=600,
config=None, include_mathjax=False, auto_play=True):
config=None, include_mathjax=False, auto_play=True,
animation_opts=None):
""" Create a plotly graph locally as an HTML document or string.
Example:
Expand Down Expand Up @@ -481,6 +502,25 @@ def plot(figure_or_data, show_link=False, link_text='Export to plot.ly',
auto_play (default=True) -- Whether to automatically start the animation
sequence on page load if the figure contains frames. Has no effect if
the figure does not contain frames.
animation_opts (default=None) -- dict of custom animation parameters to be
passed to the function Plotly.animate in Plotly.js. See
https://github.com/plotly/plotly.js/blob/master/src/plots/animation_attributes.js
for available options. Has no effect if the figure does not contain
frames, or auto_play is False.
Example:
```
from plotly.offline import plot
figure = {'data': [{'x': [0, 1], 'y': [0, 1]}],
'layout': {'xaxis': {'range': [0, 5], 'autorange': False},
'yaxis': {'range': [0, 5], 'autorange': False},
'title': 'Start Title'},
'frames': [{'data': [{'x': [1, 2], 'y': [1, 2]}]},
{'data': [{'x': [1, 4], 'y': [1, 4]}]},
{'data': [{'x': [3, 4], 'y': [3, 4]}],
'layout': {'title': 'End Title'}}]}
plot(figure,animation_opts="{frame: {duration: 1}}")
```
"""
import plotly.io as pio

Expand Down Expand Up @@ -522,6 +562,7 @@ def plot(figure_or_data, show_link=False, link_text='Export to plot.ly',
post_script=post_script,
full_html=True,
validate=validate,
animation_opts=animation_opts,
auto_open=auto_open)
return filename
else:
Expand All @@ -533,7 +574,8 @@ def plot(figure_or_data, show_link=False, link_text='Export to plot.ly',
include_mathjax=include_mathjax,
post_script=post_script,
full_html=False,
validate=validate)
validate=validate,
animation_opts=animation_opts)


def plot_mpl(mpl_fig, resize=False, strip_style=False,
Expand Down
23 changes: 21 additions & 2 deletions plotly/tests/test_core/test_offline/test_offline.py
Original file line number Diff line number Diff line change
Expand Up @@ -418,9 +418,28 @@ def test_auto_play(self):

def test_no_auto_play(self):
html = plotly.offline.plot(
fig_frames, output_type='div',auto_play=False)
fig_frames, output_type='div', auto_play=False)
self.assertIn(add_frames, html)
self.assertNotIn(do_auto_play, html)

def test_animation_opts(self):
animation_opts = {'frame': {'duration': 5000}}
expected_opts_str = json.dumps(animation_opts)

# When auto_play is False, animation options are skipped
html = plotly.offline.plot(
fig_frames, output_type='div', auto_play=False, animation_opts=animation_opts)
self.assertIn(add_frames, html)
self.assertNotIn(do_auto_play, html)
self.assertNotIn(expected_opts_str, html)

# When auto_play is True, animation options are included
html = plotly.offline.plot(
fig_frames, output_type='div', auto_play=True,
animation_opts=animation_opts)
self.assertIn(add_frames, html)
self.assertIn(do_auto_play, html)
self.assertIn(expected_opts_str, html)

def test_download_image(self):
# Not download image by default
Expand All @@ -431,4 +450,4 @@ def test_download_image(self):
# Request download image
html = plotly.offline.plot(
fig_frames, output_type='div', auto_play=False, image='png')
self.assertIn(download_image, html)
self.assertIn(download_image, html)

0 comments on commit 82a62ff

Please sign in to comment.