import matplotlib.pyplot as plt
import numpy as np
import math
import pathlib
from matplotlib.animation import FuncAnimation
= pathlib.Path(".").resolve()
DIR int = 128
SINE_FRAMES:
= np.arange(0, 2 * math.pi, step=2 * math.pi / SINE_FRAMES)
phis = np.sin(phis)
yys = np.empty_like(yys)
yys_shifted
def update(frame: int):
= SINE_FRAMES - frame
break_index
# NOTE: Yucky but efficient.
= yys[:break_index]
head = yys[break_index:]
tail
= tail
yys_shifted[:frame] = head
yys_shifted[frame:]
line.set_ydata(yys_shifted)return (line,)
= plt.subplots()
fig, ax = ax.plot(phis, yys)
line, = FuncAnimation(fig, update, frames=SINE_FRAMES, interval=1)
animation / "sine.gif", writer="pillow") # Save animation
animation.save(DIR
/ "thumb.png") # Save for thumbnail
plt.savefig(DIR plt.close()
Animations in Quarto Using Python
python, seaborn, numpy, diagram, matplotlib, animation, ffmpeg
This is an example of how to create animations with python
in quarto
notebooks using matplotlib
. Having not used animations very much in matplotlib
and not knowing much about quarto
I figured I should write some notes for anybody else who has to deal with this in the future as I did not find it to be completely obvious.
For this demonstration we will plot a sine wave with an increasing phase offset \(\phi\) over the interval \([0, \pi)\). More precisely, the graph animated is
\[\begin{equation} f_\psi: \phi \mapsto sin(\phi + \psi) \end{equation}\]
for one \(\psi \in [0, \pi)\) and all \([0, \pi]\) on each frame.
The following code is used to export a gif
of the sinusoid:
No figure is generated from this code, instead the figure is included from the saved gif
as follows:
![Exported gif](./sine.gif)
which is used to include the following figure:
This could also by done by using
from IPython.display import HTML
plt.close() HTML(animation.to_jshtml())
however I have found this to be quite slow when developing and has some relative downsides such as a slower render time, difficulty in conditional rendering, and a slower load time. More is said in the next section.
Advantages of Exporting
It is important to note that this figure could be directly embedded within the webpage. However this results in the webpage being quite large - this can be a problem when using a quarto
website as it
- Results in a longer load-time.
- Makes it difficult to open when inspecting
HTML
output directly. - Some websites will not craw if the page is too large.
In my case linkedin
would not create a preview card for my link, complaining that my document was too large. A version of my post about the logistic map reached a horrific size of about 11M. There are a number of ways the size can be determined - in my case I used wget localhost:3000/posts/logistic
and got the following output:
--2024-08-06 12:29:38-- http://localhost:3000/posts/logistic
Resolving localhost (localhost)... 127.0.0.1
Connecting to localhost (localhost)|127.0.0.1|:3000... connected.
HTTP request sent, awaiting response... 301 Moved Permanently
Location: /posts/logistic/ [following]
--2024-08-06 12:29:38-- http://localhost:3000/posts/logistic/
Connecting to localhost (localhost)|127.0.0.1|:3000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 12015385 (11M) [text/html] Saving to: ‘logistic’
Switching to gif
output, the size of the webpage is now drastically reduced:
--2024-08-06 13:13:44-- http://localhost:3000/posts/logistic
Resolving localhost (localhost)... 127.0.0.1
Connecting to localhost (localhost)|127.0.0.1|:3000... connected.
HTTP request sent, awaiting response... 301 Moved Permanently
Location: /posts/logistic/ [following]
--2024-08-06 13:13:44-- http://localhost:3000/posts/logistic/
Connecting to localhost (localhost)|127.0.0.1|:3000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 96239 (94K) [text/html] Saving to: ‘logistic.1’