Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 271a646

Browse files
committed
Merge pull request #4785 from dopplershift/anim-html5-video
Animation conversion to HTML5 video
2 parents 561ce23 + 83f4a45 commit 271a646

File tree

4 files changed

+80
-1
lines changed

4 files changed

+80
-1
lines changed

doc/users/whats_new.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,23 @@ Support for URL string arguments to ``imread``
8181
The ``imread`` function now accepts URL strings that point to remote PNG
8282
files. This circumvents the generation of a HTTPResponse object directly.
8383

84+
Display hook for animations in the IPython notebook
85+
---------------------------------------------------
86+
87+
`matplotlib.animation.Animation` instances gained a ``_repr_html_`` method
88+
to support inline display of animations in the notebook. The method used
89+
to display is controlled by the ``animation.html`` rc parameter, which
90+
currently supports values of ``none`` and ``html5``. ``none`` is the
91+
default, performing no display. ``html5`` converts the animation to an
92+
h264 encoded video, which is embedded directly in the notebook.
93+
94+
Users not wishing to use the ``_repr_html_`` display hook can also manually
95+
call the `to_html5_video` method to get the HTML and display using
96+
IPython's ``HTML`` display class::
97+
98+
from IPython.display import HTML
99+
HTML(anim.to_html5_video())
100+
84101

85102
.. _whats-new-1-4:
86103

lib/matplotlib/animation.py

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,13 @@
2323
from matplotlib.externals import six
2424
from matplotlib.externals.six.moves import xrange, zip
2525

26+
import os
2627
import platform
2728
import sys
2829
import itertools
30+
import base64
2931
import contextlib
32+
import tempfile
3033
from matplotlib.cbook import iterable, is_string_like
3134
from matplotlib.compat import subprocess
3235
from matplotlib import verbose
@@ -383,7 +386,6 @@ def cleanup(self):
383386

384387
# Delete temporary files
385388
if self.clear_temp:
386-
import os
387389
verbose.report(
388390
'MovieWriter: clearing temporary fnames=%s' %
389391
str(self._temp_names),
@@ -885,6 +887,59 @@ def _end_redraw(self, evt):
885887
self._resize_id = self._fig.canvas.mpl_connect('resize_event',
886888
self._handle_resize)
887889

890+
def to_html5_video(self):
891+
r'''Returns animation as an HTML5 video tag.
892+
893+
This saves the animation as an h264 video, encoded in base64
894+
directly into the HTML5 video tag. This respects the rc parameters
895+
for the writer as well as the bitrate. This also makes use of the
896+
``interval`` to control the speed, and uses the ``repeat``
897+
paramter to decide whether to loop.
898+
'''
899+
VIDEO_TAG = r'''<video {size} {options}>
900+
<source type="video/mp4" src="data:video/mp4;base64,{video}">
901+
Your browser does not support the video tag.
902+
</video>'''
903+
# Cache the the rendering of the video as HTML
904+
if not hasattr(self, '_base64_video'):
905+
# First write the video to a tempfile. Set delete to False
906+
# so we can re-open to read binary data.
907+
with tempfile.NamedTemporaryFile(suffix='.m4v',
908+
delete=False) as f:
909+
# We create a writer manually so that we can get the
910+
# appropriate size for the tag
911+
Writer = writers[rcParams['animation.writer']]
912+
writer = Writer(codec='h264',
913+
bitrate=rcParams['animation.bitrate'],
914+
fps=1000. / self._interval)
915+
self.save(f.name, writer=writer)
916+
917+
# Now open and base64 encode
918+
with open(f.name, 'rb') as video:
919+
vid64 = base64.encodebytes(video.read())
920+
self._base64_video = vid64.decode('ascii')
921+
self._video_size = 'width="{0}" height="{1}"'.format(
922+
*writer.frame_size)
923+
924+
# Now we can remove
925+
os.remove(f.name)
926+
927+
# Default HTML5 options are to autoplay and to display video controls
928+
options = ['controls', 'autoplay']
929+
930+
# If we're set to repeat, make it loop
931+
if self.repeat:
932+
options.append('loop')
933+
return VIDEO_TAG.format(video=self._base64_video,
934+
size=self._video_size,
935+
options=' '.join(options))
936+
937+
def _repr_html_(self):
938+
r'IPython display hook for rendering.'
939+
fmt = rcParams['animation.html']
940+
if fmt == 'html5':
941+
return self.to_html5_video()
942+
888943

889944
class TimedAnimation(Animation):
890945
'''

lib/matplotlib/rcsetup.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,9 @@ def validate_hinting(s):
499499

500500
validate_axis_locator = ValidateInStrings('major', ['minor', 'both', 'major'])
501501

502+
validate_movie_html_fmt = ValidateInStrings('animation.html',
503+
['html5', 'none'])
504+
502505
def validate_bbox(s):
503506
if isinstance(s, six.string_types):
504507
s = s.lower()
@@ -944,6 +947,7 @@ def __call__(self, s):
944947
'examples.directory': ['', six.text_type],
945948

946949
# Animation settings
950+
'animation.html': ['none', validate_movie_html_fmt],
947951
'animation.writer': ['ffmpeg', validate_movie_writer],
948952
'animation.codec': ['mpeg4', six.text_type],
949953
'animation.bitrate': [-1, validate_int],

matplotlibrc.template

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,9 @@ backend : %(backend)s
486486
#examples.directory : '' # directory to look in for custom installation
487487

488488
###ANIMATION settings
489+
#animation.html : 'none' # How to display the animation as HTML in
490+
# the IPython notebook. 'html5' uses
491+
# HTML5 video tag.
489492
#animation.writer : ffmpeg # MovieWriter 'backend' to use
490493
#animation.codec : mpeg4 # Codec to use for writing movie
491494
#animation.bitrate: -1 # Controls size/quality tradeoff for movie.

0 commit comments

Comments
 (0)