Изучите основы анимации данных для создания динамических визуальных элементов.

Данные становятся все более востребованными в современном мире. Компании и частные лица используют его для прогнозирования цен на акции с помощью машинного обучения, для отслеживания состояния здоровья спортсмена, для изучения цен на жилье в конкретном городе… возможности безграничны. Хотя необработанные данные имеют фундаментальное значение, история, которую они могут рассказать, гораздо важнее. Рассказать эту историю — работа инженеров и специалистов по данным. Визуальные эффекты могут быть одним из лучших способов передать идею с использованием данных. Подумайте, вы бы предпочли смотреть на строки и строки данных или на пару графиков, которые обобщают их? Как и большинство, вы, вероятно, думали, что сюжеты звучат лучше. Хотя это и не всегда необходимо, добавление анимации к сюжету может придать дополнительный смысл вашему повествованию.

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

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

Импорт пакетов

Python имеет огромное количество библиотек для анализа данных, поэтому мы воспользуемся парой из них. Давайте запустим новый скрипт и импортируем необходимые пакеты для этого проекта:

# Importing Packages
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import animation
  • NumPy будет использоваться для создания числовых массивов и использования тригонометрических функций (определяемых как np для простоты вызова)
  • Pyplot из Matplotlib будет использоваться для построения графиков (определяется как plt для простоты вызова).
  • Axes3D будет использоваться для создания трехмерных осей для нашего графика.
  • анимацияиз Matplotlib будет использоваться для создания нашей анимации путем многократного вызова функции, которую мы определим позже.

Создание набора данных

Прежде чем мы сможем даже подумать о построении графика, нам нужно создать данные для построения графика. Для этой части я создал некоторые данные о положении, используя функцию синуса и массив времени, который проходит от 0 до 20 (в анимации я произвольно обозначил его как секунды).

# Time Array
t = np.linspace(0, 20, 100)

# Position Arrays
x = np.sin(np.pi/5 * t)
y = np.sin(np.pi/3 * t)
z = np.linspace(0, 100, 100)

# Setting up Data Set for Animation
dataSet = np.array([x, y, z])  # Combining our position coordinates
numDataPoints = len(t)

Я думаю, что этот раздел довольно понятен. Вы можете возиться с массивами времени и положения, чтобы создавать новые траектории. Переменные dataSet и numDataPoints будут использоваться в нашей функции анимации, которую мы определим далее.

Функция анимации

Для анимации нашей фигуры мы будем использовать функцию FuncAnimation из импортированного класса animation. Вы можете получить доступ к документации по этим двум здесь. FuncAnimation требует от нас создания собственной функции, которая обновляет линии, точки и т. д., которую мы определим как animate_func.

def animate_func(num):
    ax.clear()  # Clears the figure to update the line, point,   
                # title, and axes
    # Updating Trajectory Line (num+1 due to Python indexing)
    ax.plot3D(dataSet[0, :num+1], dataSet[1, :num+1], 
              dataSet[2, :num+1], c='blue')
    # Updating Point Location 
    ax.scatter(dataSet[0, num], dataSet[1, num], dataSet[2, num], 
               c='blue', marker='o')
    # Adding Constant Origin
    ax.plot3D(dataSet[0, 0], dataSet[1, 0], dataSet[2, 0],     
               c='black', marker='o')
    # Setting Axes Limits
    ax.set_xlim3d([-1, 1])
    ax.set_ylim3d([-1, 1])
    ax.set_zlim3d([0, 100])

    # Adding Figure Labels
    ax.set_title('Trajectory \nTime = ' + str(np.round(t[num],    
                 decimals=2)) + ' sec')
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_zlabel('z')

Начнем с того, что заметим, что переменная num передается в animate_func. Это индекс текущего шага анимации. Когда мы передаем animate_func в FuncAnimation, он повторяет нашу переменную num. Мы можем использовать эту переменную для перебора нашего dataSet, который мы создали ранее.

Функция начинается с очистки фигуры. При этом будут удалены линия, точка, начало координат, метки осей и заголовок. Затем он добавляет обновленную линию траектории (от 0 до num) и местоположение точки (на шаге num). Наше происхождение остается постоянным на этом рисунке, так что вы заметите, что num не отображается, так как мы не меняем происхождение. Затем функция определяет наши неизменные пределы осей. Вы можете удалить ограничения оси, если хотите, чтобы оси менялись по мере увеличения ваших чисел (чтобы оси были динамическими).

Наконец, функция определяет наш заголовок и метки осей. Метки просты, просто наши x, y и z для декартовых координат. В качестве небольшой дополнительной функциональности у нас есть динамический заголовок, который показывает массив времени траектории, t. Мы отображаем его (с округлением до второго десятичного знака) и обновляем при каждой итерации. Обратите внимание, что это не секунды реального времени.

Сюжет нашей анимации

Последний шаг — построение анимации с помощью FuncAnimation. Мы начинаем с создания нашего объекта фигуры с трехмерными осями. Затем мы используем FuncAnimation, который принимает в качестве входных данных фигуру, нашу функцию анимации, созданную ранее, значение интервала и значение кадров. Интервал — это задержка между кадрами в миллисекундах, а кадры — это просто количество кадров, которые вы хотите показать. Эти последние два аргумента являются необязательными, но мне нравится включать их, если я хочу настроить внешний вид анимации.

# Plotting the Animation
fig = plt.figure()
ax = plt.axes(projection='3d')
line_ani = animation.FuncAnimation(fig, animate_func, interval=100,   
                                   frames=numDataPoints)
plt.show()

Вы можете запустить код, и если все сделано правильно, ваш график должен выглядеть примерно так (скорость точки может быть другой):

Сохранение нашей анимации (необязательно)

Если вы хотите сохранить анимацию в виде файла .gif, вы можете использовать для этого следующий код.

# Saving the Animation
f = r"c://Users/(Insert User)/Desktop/animate_func.gif"
writergif = animation.PillowWriter(fps=numDataPoints/6)
line_ani.save(f, writer=writergif)

Вам нужно выбрать место для его сохранения и сохранить его как переменную f. Вы можете настроить количество кадров в секунду, fps, переменную в PillowWriter. Я разделил переменную numDataPoints, которая была определена как количество кадров в FuncAnimation, на 6, чтобы анимация была 6 длительность в секундах.

Это все для этой статьи. Спасибо за чтение! Если вы не хотите пропустить больше статей о Python и инженерных разработках, подпишитесь на меня и подпишитесь на мои электронные письма. Я написал несколько других статей, так что ознакомьтесь и с ними!