Matplotlib

Используем библиотеку matplotlib для создания интересной анимации

Изображение имитации дождя выполнено с помощью библиотеки Matplotlib, известной как прародитель пакетов для визуализации данных на python. Matplotlib имитирует капли дождя на поверхности путем анимирования масштаба и непрозрачности 50 точек графика разброса. В этой статье мы рассмотрим анимации в Matplotlib и несколько способов их создания.

Обзор

Matplotlib — это одна из самых известных библиотек Python с двумерной (2D) графикой. Многие начинают путешествие в мир визуализации данных с Matplotlib. С ее помощью можно с легкостью создавать графики, гистограммы, энергетические спектры, столбчатые диаграммы, графики погрешностей, графики разброса и многое другое. Она также интегрируется с такими библиотеками, как Pandas и Seaborn для создания более сложных визуализаций.

Некоторые особенности matplotlib:

  • Она разработана подобно MATLAB, поэтому переключаться между ними довольно просто.
  • Содержит множество расширений для визуализации.
  • Воспроизводит практически все графики (если приложить усилия).
  • Существует более десяти лет, соответственно обладает большой базой пользователей.

Однако в некоторых областях Matplotlib отстает от своих мощных противников.

  • Matplotlib обладает достаточно многословным императивным API.
  • Иногда встречаются слабые по стилю стандартные параметры.
  • Слабая поддержка веб и интерактивных графов.
  • Часто тормозит при наличии большого объема сложных данных.

Освежить знания о базовых функциях поможет шпаргалка по Matplotlib из Datacamp.

Анимации

Базовый класс animation в Matplotlib отвечает за анимацию. Он предоставляет основу, вокруг которой создается функциональность анимации. Для этого есть два основных интерфейса:

FuncAnimation создает анимацию с помощью повторения вызова функции func.

ArtistAnimation: анимация с использованием фиксированного набора объектов Artist.

FuncAnimation является более удобным способом. В документации можно ознакомиться с обоими способами подробнее. В этой статье мы будем использовать только инструмент FuncAnimation.

Требования

  • Установите модули, включая numpy и matplotlib
  • Установите ffmpeg или imagemagick для сохранения анимации в формате mp4 или gif.

Теперь можно перейти к созданию базовой анимации в Jupyter Notebooks. Код доступен в репозитории Github.

Базовая анимация: Движущаяся синусоидальная волна

Создадим базовую анимацию синусоидальной волны, движущейся по экрану, с помощью FuncAnimation. Исходный код для этой анимации взят из Руководства по анимации в Matplotlib. Рассмотрим входные данные, а затем разберем отдельные фрагменты кода.

import numpy as np
from matplotlib import pyplot as plt
from matplotlib.animation import FuncAnimation
plt.style.use('seaborn-pastel')

fig = plt.figure()
ax = plt.axes(xlim=(0, 4), ylim=(-2, 2))
line, = ax.plot([], [], lw=3)

def init():
    line.set_data([], [])
    return line,
def animate(i):
    x = np.linspace(0, 4, 1000)
    y = np.sin(2 * np.pi * (x - 0.01 * i))
    line.set_data(x, y)
    return line,

anim = FuncAnimation(fig, animate, init_func=init,
                               frames=200, interval=20, blit=True)

anim.save('sine_wave.gif', writer='imagemagick')
  • В строках 7–9 создаем фигуру window с одной осью. Затем создаем пустой объект line, единственный из объектов, который будет изменяться в анимации. Объект line будет заполнен данными позже.
  • В строках 11–13 создаем функцию init, осуществляющую анимацию. Функция init инициализирует данные и устанавливает пределы оси.
  • В строках 14–18 определяем функцию, которая принимает количество кадров (i) в качестве параметра и создает синусоидальную волну (или любую другую анимацию), выполняющую движения в зависимости от значения i. Эта функция возвращает кортеж измененных объектов графика, который сообщает фреймворку анимации, какие части графика нужно анимировать.
  • В строке 20 создаем объект animation. Параметр blit гарантирует, что будут перерисованы только измененные части графика.

Это базовый подход к созданию анимации в Matplotlib. При внесении небольших изменений в код можно создать более интересные визуализации. Рассмотрим некоторые из них.

Растущая спираль

Создадим движущуюся спираль, которая будет медленно разматываться, с помощью класса animation в matplotlib. Код схож с кодом графика синусоидальной волны, однако содержит несколько изменений.

import matplotlib.pyplot as plt 
import matplotlib.animation as animation 
import numpy as np 
plt.style.use('dark_background')

fig = plt.figure() 
ax = plt.axes(xlim=(-50, 50), ylim=(-50, 50)) 
line, = ax.plot([], [], lw=2) 

# initialization function 
def init(): 
 # creating an empty plot/frame 
 line.set_data([], []) 
 return line, 

# lists to store x and y axis points 
xdata, ydata = [], [] 

# animation function 
def animate(i): 
 # t is a parameter 
 t = 0.1*i 
 
 # x, y values to be plotted 
 x = t*np.sin(t) 
 y = t*np.cos(t) 
 
 # appending new points to x, y axes points list 
 xdata.append(x) 
 ydata.append(y) 
 line.set_data(xdata, ydata) 
 return line, 
 
# setting a title for the plot 
plt.title('Creating a growing coil with matplotlib!') 
# hiding the axis details 
plt.axis('off') 

# call the animator  
anim = animation.FuncAnimation(fig, animate, init_func=init, 
 frames=500, interval=20, blit=True) 

# save the animation as mp4 video file 
anim.save('coil.gif',writer='imagemagick')

График обновления в режиме реального времени

Графики обновления в режиме реального времени пригодятся при построении динамических величин, таких как данные о запасах, данные сенсоров и друге зависящие от времени данные. Создаем базовый граф, который обновляется автоматически при появлении новых данных в системе. Создадим график цен на акции компании за месяц.

#importing libraries
import matplotlib.pyplot as plt
import matplotlib.animation as animation


fig = plt.figure()
#creating a subplot 
ax1 = fig.add_subplot(1,1,1)

def animate(i):
    data = open('stock.txt','r').read()
    lines = data.split('\n')
    xs = []
    ys = []
   
    for line in lines:
        x, y = line.split(',') # Delimiter is comma    
        xs.append(float(x))
        ys.append(float(y))
   
    
    ax1.clear()
    ax1.plot(xs, ys)

    plt.xlabel('Date')
    plt.ylabel('Price')
    plt.title('Live graph with matplotlib') 
 
    
ani = animation.FuncAnimation(fig, animate, interval=1000) 
plt.show()

Откройте терминал и запустите файл python. Получаем изображенный ниже график, который автоматически обновляется следующим образом:

Интервал составляет 1000 миллисекунд или одну секунду.

Анимация на 3D-графике

Создание 3D-графиков достаточно распространено, однако, что если анимировать угол обзора в этих графиках? Идея заключается в изменении обзора камеры и использовании каждого результирующего изображения для создания анимации. В Python Graph Gallery можно найти раздел, посвященный этой теме.

Создайте папку volcano в одном каталоге с notebook. Все изображения, которые будут использовать в анимации, сохранятся в этой папке.

# library
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns

# Get the data (csv file is hosted on the web)
url = 'https://python-graph-gallery.com/wp-content/uploads/volcano.csv'
data = pd.read_csv(url)

# Transform it to a long format
df=data.unstack().reset_index()
df.columns=["X","Y","Z"]

# And transform the old column name in something numeric
df['X']=pd.Categorical(df['X'])
df['X']=df['X'].cat.codes

# We are going to do 20 plots, for 20 different angles
for angle in range(70,210,2):

# Make the plot
    fig = plt.figure()
    ax = fig.gca(projection='3d')
    ax.plot_trisurf(df['Y'], df['X'], df['Z'], cmap=plt.cm.viridis, linewidth=0.2)

    ax.view_init(30,angle)

    filename='Volcano/Volcano_step'+str(angle)+'.png'
    plt.savefig(filename, dpi=96)
    plt.gca()

Этот фрагмент кода создаст несколько файлов PNG в папке Volcano. Теперь используем ImageMagick для создания анимации из этих изображений. Откройте терминал, перейдите к папке Volcano и введите следующую команду:

convert -delay 10 Volcano*.png animated_volcano.gif

Анимации с использованием модуля Celluloid

Celluloid — это модуль в Python, упрощающий процесс создания анимации в matplotlib. Эта библиотека создает фигуру matplotlib и Camera из нее. Затем она использует фигуру и делает снимок с камеры после создания каждого фрейма. Наконец создается анимация из всех захваченных фреймов.

Установка

pip install celluloid

Несколько примеров использования модуля Celluloid.

Minimal

from matplotlib import pyplot as plt
from celluloid import Camera

fig = plt.figure()
camera = Camera(fig)
for i in range(10):
    plt.plot([i] * 10)
    camera.snap()
animation = camera.animate()
animation.save('celluloid_minimal.gif', writer = 'imagemagick')

Subplots

import numpy as np
from matplotlib import pyplot as plt
from celluloid import Camera

fig, axes = plt.subplots(2)
camera = Camera(fig)
t = np.linspace(0, 2 * np.pi, 128, endpoint=False)
for i in t:
    axes[0].plot(t, np.sin(t + i), color='blue')
    axes[1].plot(t, np.sin(t - i), color='blue')
    camera.snap()
    
animation = camera.animate()  
animation.save('celluloid_subplots.gif', writer = 'imagemagick')

Legends

import matplotlib
from matplotlib import pyplot as plt
from celluloid import Camera

fig = plt.figure()
camera = Camera(fig)
for i in range(20):
    t = plt.plot(range(i, i + 5))
    plt.legend(t, [f'line {i}'])
    camera.snap()
animation = camera.animate()
animation.save('celluloid_legends.gif', writer = 'imagemagick')

Вывод

С помощью анимации можно подчеркнуть особенности визуализации, которые трудно передать с помощью статических диаграмм. Однако не стоит злоупотреблять использованием визуализаций. Каждую функцию в визуализации данных следует использовать разумно для создания лучшего эффекта.

Читайте также:


Перевод статьи Parul Pandey: Animations with Matplotlib