¿Sabías que puedes crear animaciones desde matplotlib y que se pueden usar en documentos HTML y con controles para mover los frames hacia adelante, hacia atrás, botón de play, control de la velocidad, control para visualizarlo en bucle,...? Pues sí y, además, es relativamente sencillo.
Obviamente, mejor aprender haciendo así que veámoslo con un ejemplo.
Como siempre, empezamos importando lo que necesitamos:
import codecs
from random import choice
from typing import List, Any
import matplotlib.pyplot as plt
from matplotlib import animation
from matplotlib.colors import get_named_colors_mapping
Lo que voy a animar es un haiku y así quedará más 'artístico'. Un haiku es un tipo de poesía japonesa que consiste en un poema breve de diecisiete sílabas escrito en tres versos de cinco, siete y cinco sílabas, respectivamente.
El haiku lo he 'codificado' para dejar un poco de misterio hasta el final... El cifrado es prácticamente imposible de romper por lo que ni lo intentéis :-D
coded_haiku = 'Cvrafn ra ryyb\nGbqbf ybf qínf yyhrir\nZnenivyybfb '
haiku = codecs.encode(coded_haiku, 'rot13')
Además, para que quede más aparente, voy a usar colores que voy a obtener de la función get_named_colors_mapping dentro del módulo matplotlib.colors:
colors = list(get_named_colors_mapping().values())
Lo siguiente de lo que voy a hablar es de la parte del código que crea la animación. Para ello voy a necesitar tres partes:
- Una primera parte con la figura y la zona donde voy a pintar las cosas.
- La segunda cosa que necesito es la función que irá generando los fotogramas de la animación.
- Y, por último, necesito una clase que anime todo esto que obtengo del módulo
matplotlib.animation. La clase que voy a usar se llamaFuncAnimation.
El código por partes será como sigue. La primera parte es la siguiente:
fig, ax = plt.subplots(figsize=(12,6))
ax.axis('off')
El anterior código inicializa lo que necesito para hacer la animación. A la zona en la que voy a pintar le quito toda la información de los ejes puesto que no los necesito.
La segunda parte es la función que crea los fotogramas:
def update(
i: int,
haiku: str,
colors: List[Any]
):
step = (1 - 0.2) / max(map(len, haiku.split('\n')))
y = 0.75
x = 0.1
k = 0
for h in haiku[:i]:
if h == '\n':
y -= 0.25
x = 0.1
continue
x += step
color = choice(colors)
ax.text(x, y, h, fontsize=30, color=color)
return ax
La función update anterior lo único que hace es añadir texto en posiciones que se van calculando a cada paso y con colores que se van definiendo en la propia función.
La tercera parte es la instanciación de la clase FuncAnimation:
anim = animation.FuncAnimation(
fig,
update,
len(haiku),
fargs=(haiku, colors),
interval=50
)
A la función update le iré pasando una serie de cosas en cada fotograma: len(haiku), haiku y colors.
Con lo anterior ya tenemos la maquinaria necesaria para crear la animación.
La instancia anim posee un método muy interesante que voy a usar a continuación:
with open('haiku.html', 'w') as f:
f.write(anim.to_jshtml())
Ese método, to_jshtml, es el que realiza la magia. Lo que hace es codificar en base64 cada fotograma para poder meterlo directamente como código dentro del documento HTML. Además, la función mete el resto de cosas, css, javascript, HTML, que necesitamos para poder mostrar las imágenes como una animación con controles.
El código completo lo puedes ver a continuación:
import codecs
from random import choice
from typing import List, Any
import matplotlib.pyplot as plt
from matplotlib import animation
from matplotlib.colors import get_named_colors_mapping
coded_haiku = 'Cvrafn ra ryyb\nGbqbf ybf qínf yyhrir\nZnenivyybfb '
haiku = codecs.encode(coded_haiku, 'rot13')
colors = list(get_named_colors_mapping().values())
fig, ax = plt.subplots(figsize=(12,6))
ax.axis('off')
def update(
i: int,
haiku: str,
colors: List[Any]
):
step = (1 - 0.2) / max(map(len, haiku.split('\n')))
y = 0.75
x = 0.1
k = 0
for h in haiku[:i]:
if h == '\n':
y -= 0.25
x = 0.1
continue
x += step
color = choice(colors)
ax.text(x, y, h, fontsize=30, color=color)
return ax
anim = animation.FuncAnimation(
fig,
update,
len(haiku),
fargs=(haiku, colors),
interval=50
)
with open('haiku.html', 'w') as f:
f.write(anim.to_jshtml())
Y el resultado del código anterior lo incrusto a continuación:
.animation { display: inline-block; text-align: center; } input[type=range].anim-slider { width: 374px; margin-left: auto; margin-right: auto; } .anim-buttons { margin: 8px 0px; } .anim-buttons button { padding: 0; width: 36px; } .anim-state label { margin-right: 8px; } .anim-state input { margin: 0; vertical-align: middle; }
Once Loop Reflect
¡¡¡¡Ta chán!!!!
Espero que os haya gustado el haiku y el artículo.
Si os ha gustado podéis crear un haiku y dejarlo en los comentarios.
Otros artículos relacionados con animaciones:
- https://pybonacci.org/2012/12/16/creando-una-animacion-con-matplotlib-y-ffmpeg/
- https://pybonacci.org/2020/05/12/demanda-electrica-en-espana-durante-el-confinamiento-covid-19-visto-con-python/
- https://pybonacci.org/2020/04/08/analizando-el-calentamiento-global-con-python/
- https://pybonacci.org/2019/12/13/creacion-de-gif-animado-con-imageio-y-python/
- https://pybonacci.org/2018/11/27/creacion-de-videos-al-vuelo-en-el-notebook/
Pybonacci