Description
Problem
Let's take the example from https://matplotlib.org/stable/gallery/animation/animate_decay.html
import itertools
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
def data_gen():
for cnt in itertools.count():
t = cnt / 10
yield t, np.sin(2*np.pi*t) * np.exp(-t/10.)
def init():
ax.set_ylim(-1.1, 1.1)
ax.set_xlim(0, 10)
del xdata[:]
del ydata[:]
line.set_data(xdata, ydata)
return line,
fig, ax = plt.subplots()
line, = ax.plot([], [], lw=2)
ax.grid()
xdata, ydata = [], []
def run(data):
# update the data
t, y = data
xdata.append(t)
ydata.append(y)
xmin, xmax = ax.get_xlim()
if t >= xmax:
ax.set_xlim(xmin, 2*xmax)
ax.figure.canvas.draw()
line.set_data(xdata, ydata)
return line,
ani = animation.FuncAnimation(fig, run, data_gen, interval=10, init_func=init)
plt.show()
It works great and I can easily save the animation to html using code such as:
from matplotlib.animation import HTMLWriter
fname = "path/to/myfile.html"
writer = HTMLWriter(fps=5)
writer.frame_format = "svg" # Ensure svg format
ani.save(fname, writer=writer)
I can open the html animation from a browser or display it in a jupyter notebook:
from IPython.display import HTML
# Display the animation
HTML(fname_html.read_text())
The problem is that within the html file, the path to the frames is hardcoded rather than being relative to the
html file. So if you change the location of the html file, it does not work anymore.
<script language="javascript">
/* Instantiate the Animation class. */
/* The IDs given should match those used in the
7EC6
template above. */
(function() {
var img_id = "_anim_imga5cbaf4d0c4c4ffda374436a276eff4b";
var slider_id = "_anim_slidera5cbaf4d0c4c4ffda374436a276eff4b";
var loop_select_id = "_anim_loop_selecta5cbaf4d0c4c4ffda374436a276eff4b";
var frames = new Array(100);
for (var i=0; i<100; i++){
frames[i] = "path/to/myfile_frames/frame" + ("0000000" + i).slice(-7) +
".svg";
}
/* set a timeout to make sure all the above elements are created before
the object is initialized. */
setTimeout(function() {
anima5cbaf4d0c4c4ffda374436a276eff4b = new Animation(frames, img_id, slider_id, 200,
loop_select_id);
}, 0);
})()
</script>
You can feed ani.save(fname, writer=writer)
with a relative fname
but in that case, it works in jupyter only if the html file is in the same folder than the notebook.
Proposed solution
The best would be to modify the javascript so it can get the path of the html file on the fly. I tried:
<script language="javascript">
/* Instantiate the Animation class. */
/* The IDs given should match those used in the template above. */
(function() {
var img_id = "_anim_imga5cbaf4d0c4c4ffda374436a276eff4b";
var slider_id = "_anim_slidera5cbaf4d0c4c4ffda374436a276eff4b";
var loop_select_id = "_anim_loop_selecta5cbaf4d0c4c4ffda374436a276eff4b";
var frames = new Array(100);
var scripts = document.getElementsByTagName("script"), src = scripts[scripts.length-1].src;
for (var i=0; i<100; i++){
frames[i] = src + "myfile_frames/frame" + ("0000000" + i).slice(-7) +
".svg";
}
/* set a timeout to make sure all the above elements are created before
the object is initialized. */
setTimeout(function() {
anima5cbaf4d0c4c4ffda374436a276eff4b = new Animation(frames, img_id, slider_id, 200,
loop_select_id);
}, 0);
})()
</script>
And it works at least in Firefox and Chrome. However, it does not work for:
from IPython.display import HTML
# Display the animation
HTML(fname_html.read_text())