13.2 Animación de una onda sinusoidal
Onda viajera (una línea)
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
x = np.linspace(0, 2 * np.pi, 600)
fig, ax = plt.subplots(figsize=(7, 4), layout="constrained")
(line,) = ax.plot(x, np.sin(x))
ax.set_xlim(x.min(), x.max())
ax.set_ylim(-1.2, 1.2)
ax.set_title("Onda sinusoidal animada")
ax.set_xlabel("x")
ax.set_ylabel("y = sin(x - fase)")
def init():
line.set_ydata(np.sin(x))
return (line,)
def update(frame):
fase = 0.05 * frame
line.set_ydata(np.sin(x - fase))
return (line,)
ani = FuncAnimation(
fig,
update,
frames=200,
init_func=init,
interval=20,
blit=True,
repeat=True
)
plt.show()
Dos líneas y anotación
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
x = np.linspace(0, 2 * np.pi, 600)
fig, ax = plt.subplots(figsize=(7, 4), layout="constrained")
line1, = ax.plot(x, np.sin(x))
line2, = ax.plot(x, np.cos(x))
txt = ax.text(0.02, 0.90, "", transform=ax.transAxes)
ax.set_ylim(-1.2, 1.2)
ax.set_title("sin/cos animados")
def init():
line1.set_ydata(np.sin(x))
line2.set_ydata(np.cos(x))
txt.set_text("")
return (line1, line2, txt)
def update(i):
fase = 0.04 * i
line1.set_ydata(np.sin(x - fase))
line2.set_ydata(np.cos(x - fase))
txt.set_text(f"frame: {i}")
return (line1, line2, txt)
ani = FuncAnimation(
fig,
update,
frames=250,
init_func=init,
interval=20,
blit=True
)
plt.show()
13.3 Guardar animaciones en GIF o MP4
Para guardar, necesitás un writer disponible en tu entorno. Comprobálo con matplotlib.animation.writers.list()
.
Guardar como GIF
from matplotlib.animation import PillowWriter
# ani = FuncAnimation(...)
writer = PillowWriter(fps=30)
ani.save("onda.gif", writer=writer, dpi=100)
Guardar como MP4
from matplotlib.animation import FFMpegWriter
# ani = FuncAnimation(...)
writer = FFMpegWriter(fps=30, bitrate=1800)
ani.save("onda.mp4", writer=writer, dpi=120)
💡 Asegurate de tener FFmpeg instalado (PATH en Windows o gestor de paquetes en Linux/macOS).
13.5 Patrón reusable
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation, FFMpegWriter
def build_animation(fps=30, frames=300, save=None):
x = np.linspace(0, 2 * np.pi, 800)
fig, ax = plt.subplots(figsize=(7, 4), layout="constrained")
(line,) = ax.plot(x, np.sin(x))
ax.set_ylim(-1.2, 1.2)
ax.set_title("Patrón reusable")
def init():
line.set_ydata(np.sin(x))
return (line,)
def update(i):
phase = 2 * np.pi * (i / frames)
line.set_ydata(np.sin(x - phase))
return (line,)
ani = FuncAnimation(
fig,
update,
init_func=init,
frames=frames,
interval=1000 // fps,
blit=True
)
if save:
if save.endswith(".mp4"):
ani.save(save, writer=FFMpegWriter(fps=fps, bitrate=2000), dpi=120)
elif save.endswith(".gif"):
from matplotlib.animation import PillowWriter
ani.save(save, writer=PillowWriter(fps=fps), dpi=100)
return ani
💡 Ajustá fps
, frames
, dpi
y bitrate
según el medio de destino (web, video, presentaciones).