From 82a62ff086c2fbd39a8c58b6c3ec7dbb1bec7e31 Mon Sep 17 00:00:00 2001
From: TakodaS <49280242+TakodaS@users.noreply.github.com>
Date: Wed, 10 Apr 2019 22:36:32 +0100
Subject: [PATCH] Adding auto start animation_opts argument to html export and
html renderers (#1503)
---
plotly/io/_base_renderers.py | 45 +++++++++++++----
plotly/io/_html.py | 26 ++++++++--
plotly/offline/offline.py | 50 +++++++++++++++++--
.../test_core/test_offline/test_offline.py | 23 ++++++++-
4 files changed, 124 insertions(+), 20 deletions(-)
diff --git a/plotly/io/_base_renderers.py b/plotly/io/_base_renderers.py
index 5f82d098f4..b8a684feb0 100644
--- a/plotly/io/_base_renderers.py
+++ b/plotly/io/_base_renderers.py
@@ -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
@@ -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:
@@ -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}
@@ -336,7 +339,8 @@ 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,
@@ -344,7 +348,8 @@ def __init__(self,
global_init=True,
config=config,
auto_play=auto_play,
- post_script=post_script)
+ post_script=post_script,
+ animation_opts=animation_opts)
class KaggleRenderer(HtmlRenderer):
@@ -358,7 +363,12 @@ 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,
@@ -366,7 +376,8 @@ def __init__(self, config=None, auto_play=False, post_script=None):
global_init=True,
config=config,
auto_play=auto_play,
- post_script=post_script)
+ post_script=post_script,
+ animation_opts=animation_opts)
class ColabRenderer(HtmlRenderer):
@@ -377,7 +388,12 @@ 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,
@@ -385,7 +401,8 @@ def __init__(self, config=None, auto_play=False, post_script=None):
global_init=False,
config=config,
auto_play=auto_play,
- post_script=post_script)
+ post_script=post_script,
+ animation_opts=animation_opts)
class IFrameRenderer(MimetypeRenderer):
@@ -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
@@ -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
@@ -547,7 +567,8 @@ 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
@@ -555,6 +576,7 @@ def __init__(self,
self.new = new
self.autoraise = autoraise
self.post_script = post_script
+ self.animation_opts = animation_opts
def render(self, fig_dict):
renderer = HtmlRenderer(
@@ -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']
diff --git a/plotly/io/_html.py b/plotly/io/_html.py
index f70d269f7f..62596ae98f 100644
--- a/plotly/io/_html.py
+++ b/plotly/io/_html.py
@@ -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.
@@ -102,6 +103,12 @@ def to_html(fig,
If True, produce a string containing a complete HTML document
starting with an tag. If False, produce a string containing
a single
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.
@@ -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}")) {{
@@ -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):
"""
@@ -390,6 +403,12 @@ def write_html(fig,
If True, produce a string containing a complete HTML document
starting with an tag. If False, produce a string containing
a single
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.
@@ -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)
diff --git a/plotly/offline/offline.py b/plotly/offline/offline.py
index 5cad091f01..94a7fd07a2 100644
--- a/plotly/offline/offline.py
+++ b/plotly/offline/offline.py
@@ -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
@@ -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:
```
@@ -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
@@ -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:
@@ -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
@@ -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:
@@ -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,
diff --git a/plotly/tests/test_core/test_offline/test_offline.py b/plotly/tests/test_core/test_offline/test_offline.py
index da1a93e21a..b7d543a6b3 100644
--- a/plotly/tests/test_core/test_offline/test_offline.py
+++ b/plotly/tests/test_core/test_offline/test_offline.py
@@ -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
@@ -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)
\ No newline at end of file
+ self.assertIn(download_image, html)