Cómo crear gráficos animados en Python

Cómo crear gráficos animados en Python

@programacion

Matplotlib y Seaborn son bibliotecas de Python bastante decentes para hacer grandes tramas. Pero tales gráficos resultan ser estáticos, y es extremadamente difícil elegir una hermosa presentación de datos para ellos o rastrear la dinámica de los cambios. ¿Te gustaría que en tu próxima presentación/video/publicación en redes sociales pudieras mostrar la dinámica del cambio en forma de un video corto? Y aún más: ¡esas tramas se pueden crear en Matplotlib, Seaborn o cualquier otra biblioteca!

No hace mucho, creé algunos gráficos dinámicos para un breve documental sobre la crisis de los opioides en EE. UU., por lo que los datos del artículo se tomarán de ahí. Esta información está disponible públicamente en los sitios web del Instituto Nacional para el Estudio del Abuso de Drogas y los Centros para el Control y la Prevención de Enfermedades. Puede descargarlo desde el enlace: https://www.drugabuse.gov/sites/default/files/overdose_data_1999-2015.xls .

Construiré diagramas en Matplotlib y Seaborn, y usaré Numpy y Pandas para el procesamiento de datos. Matplotlib ofrece varias funciones para la animación. Entonces, comencemos e importemos todas las dependencias.

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.animation as animation

Ahora, en preparación para crear la animación, necesitamos cargar los datos y agregarlos al Pandas DataFrame. Al crear varios gráficos sobre sobredosis de varios opiáceos, es mejor escribir una función separada que cargue los datos de la línea deseada.

overdoses = pd.read_excel('overdose_data_1999-2015.xls',sheetname='Online',skiprows =6)
def get_data(table,rownum,title):
    data = pd.DataFrame(table.loc[rownum][2:]).astype(float)
    data.columns = {title}
    return data

¡Pongámonos manos a la obra y pasemos a crear animación!

Primero, si usa Jupiter Notebook como yo, entonces inicie la celda con %matplotlib notebook- para que vea la animación inmediatamente, y no solo después de guardar.

Personalmente, extraje las estadísticas de sobredosis de heroína de una tabla usando la función get_datay luego transfirí los datos a un Pandas DataFrame en dos columnas. El primero es el año, el segundo es el número de sobredosis.

%matplotlib notebook
title = 'Heroin Overdoses'
d = get_data(overdoses,18,title)
x = np.array(d.index)
y = np.array(d['Heroin Overdoses'])
overdose = pd.DataFrame(y,x)
#XN,YN = augment(x,y,10)
#augmented = pd.DataFrame(YN,XN)
overdose.columns = {title}

A continuación, iniciamos writer, que usa ffmpeg y escribe 20 cuadros por segundo con una tasa de bits de 1800. Por supuesto, estos valores los puedes configurar tú mismo.

Writer = animation.writers['ffmpeg']
writer = Writer(fps=20, metadata=dict(artist='Me'), bitrate=1800)

Ahora vamos a crear un gráfico con símbolos. Asegúrese de establecer límites para los ejes x e y para que la animación no "rebote" en el rango de datos que se muestra.

fig = plt.figure(figsize=(10,6))
plt.xlim(1999, 2016)
plt.ylim(np.min(overdose)[0], np.max(overdose)[0])
plt.xlabel('Year',fontsize=20)
plt.ylabel(title,fontsize=20)
plt.title('Heroin Overdoses per Year',fontsize=20)

El componente principal del gráfico es la función de animación, que especifica lo que debe suceder en cada cuadro del video. Aquí i está el índice del cuadro de animación. Con este índice, selecciona el rango de datos que deben mostrarse en el marco. Luego, represente estos datos en un diagrama de línea marino. Las dos últimas líneas son necesarias para la belleza.

def animate(i):
    data = overdose.iloc[:int(i+1)] #select data range
    p = sns.lineplot(x=data.index, y=data[title], data=data, color="r")
    p.tick_params(labelsize=17)
    plt.setp(p.lines,linewidth=7)

El inicio de la animación se realiza a través matplotlib.animation.FuncAnimation : allí vincula la función de animación y establece el número total de cuadros. framesdetermina la frecuencia con la que se llamará animate(i).

ani = matplotlib.animation.FuncAnimation(fig, animate, frames=17, repeat=True)

Para guardar la animación en mp4, no dude en llamar al ani.save() . Si necesita una vista previa antes de guardar, entonces es mejor usar plt.show() .

ani.save('HeroinOverdosesJumpy.mp4', writer=writer)

Ahora la animación se ve así:

La función funcionó, pero las transiciones entre los datos son demasiado bruscas. Para suavizar los valores de salto, debe agregar algunos puntos adicionales entre los existentes. Para hacer esto, usamos otra función, a la que llamé augment .

def augment(xold,yold,numsteps):
    xnew = []
    ynew = []
    for i in range(len(xold)-1):
        difX = xold[i+1]-xold[i]
        stepsX = difX/numsteps
        difY = yold[i+1]-yold[i]
        stepsY = difY/numsteps
        for s in range(numsteps):
            xnew = np.append(xnew,xold[i]+s*stepsX)
            ynew = np.append(ynew,yold[i]+s*stepsY)
    return xnew,ynew

Ahora queda aplicar esta función a los datos y aumentar el número de fotogramas en matplotlib.animation.FuncAnimation. Aquí configuro el aumento con numsteps=10. Esto significa que aumento el conjunto de datos a 160 puntos y especifico frames=160 . El resultado es más suave, pero todavía hay algunos picos pronunciados en el gráfico.

Para eliminar esta "nitidez", puede agregar una función de suavizado desde aquí: https://www.swharden.com/wp/2008-11-17-linear-data-smoothing-in-python/

def smoothListGaussian(listin,strippedXs=False,degree=5):  
    window=degree*2-1  
    weight=np.array([1.0]*window)  
    weightGauss=[]  
    for i in range(window):  
        i=i-degree+1  
        frac=i/float(window)  
        gauss=1/(np.exp((4*(frac))**2))  
        weightGauss.append(gauss)
    weight=np.array(weightGauss)*weight  
    smoothed=[0.0]*(len(listin)-window)  
    for i in range(len(smoothed)):        smoothed[i]=sum(np.array(listin[i:i+window])*weight)/sum(weight)  
    return smoothed

También puede agregar opciones de color y estilo para que el gráfico sea más original.

sns.set(rc={'axes.facecolor':'lightgrey', 'figure.facecolor':'lightgrey','figure.edgecolor':'black','axes.grid':False})

Así es como obtenemos la versión final que se muestra arriba.

En este artículo, hemos analizado la función de animación en matplotlib usando un ejemplo. Por supuesto, se puede utilizar para animar cualquier tipo de gráfico. ¡Simplemente configure los parámetros y el tipo de gráfico en la función animate()y obtendrá infinitas posibilidades!

Traducción del artículo Viviane : Cómo crear gráficos animados en Python


Report Page