Я пытаюсь создать анимацию абелевой песочницы с использованием массивов seaborn и numpy в Python3.
Сначала я импортирую все необходимые библиотеки
%matplotlib notebook #for running this program in a jupyter notebook
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
import seaborn as sns
import random
Затем я устанавливаю размерность массива, количество итераций и максимальное значение для любой ячейки в массиве и инициализирую массив нулей numpy:
dimension = 3
iterations = 100
Z_critical = 4
Z = np.zeros((dimension, dimension))
После этого я определяю функция для имитации "лавин" в песочнице. Для тех, кто знаком с абелевыми песочными кучами, просто рассмотрим это произвольное преобразование массива Z, которое при применении снова и снова приводит к матрице, ячейки которой содержат целочисленные значения, меньшие, чем Z_critical:
def avalanch(Z, Z_critical):
Z_new = np.copy(Z)
repeat = False
for x in range(dimension):
for y in range(dimension):
if x < dimension-1 and Z[x+1, y] >= Z_critical:
Z_new[x, y] = Z_new[x, y] + 1
Z_new[x+1, y] = 0
repeat = True
if y < dimension-1 and Z[x, y+1] >= Z_critical:
Z_new[x, y] = Z_new[x, y] + 1
Z_new[x, y+1] = 0
repeat = True
if x > 0 and Z[x-1, y] >= Z_critical:
Z_new[x, y] = Z_new[x, y] + 1
Z_new[x-1, y] = 0
repeat = True
if y > 0 and Z[x, y-1] >= Z_critical:
Z_new[x, y] = Z_new[x, y] + 1
Z_new[x, y-1] = 0
repeat = True
return(Z_new, repeat)
В качестве идентификатора Мне любопытно, что есть способ «векторизовать» этот бит кода, чтобы он работал быстрее.
Теперь я хотел бы увеличить центр массива на 1, а затем вызвать avalanch. функционировать, пока все значения в массиве не станут меньше Z_critical. Программа прекрасно работает, когда все, что я делаю, это выводит тепловую карту для каждой итерации:
for i in range(iterations):
x=1
y=1
Z[x, y] = Z[x, y] + 1
repeat = True
while repeat == True:
Z, repeat = avalanch(Z, Z_critical)
fig = plt.figure(figsize=(10,10))
ax = fig.add_subplot(1, 1, 1)
ax = sns.heatmap(Z, square = True, cbar = False, vmin=0, vmax=4)
plt.show(ax)
Но вот бит бит. Когда я пытаюсь анимировать его, я получаю только 4 кадра, пока анимация не остановится (хотя мое ядро еще немного занято, предполагая, что базовые преобразования матрицы все еще выполняются?).
fig = plt.figure()
def animate(i, Z, Z_critical):
plt.clf()
enter code here
x=1
y=1
Z[x, y] = Z[x, y] + 1
Z, repeat = avalanch(Z, Z_critical)
while repeat == True:
Z, repeat = avalanch(Z, Z_critical)
ax = sns.heatmap(Z, square = True, cbar = False, vmin=0, vmax=4)
anim = animation.FuncAnimation(fig, animate, fargs=(Z, Z_critical), frames=iterations, repeat = False)
Я планировал анимацию. Funcanimation () работает как l для 1042 *, но это должно быть неправильно. Как мне изменить мой код так, чтобы из моего рабочего кода я получал анимацию, кадры которой выглядят как графики тепловых карт?
Во время отладки я подтвердил, что могу получить работающую анимацию с большим длиннее четырех кадров, используя другую анимационную функцию, которая просто меняет значение средней ячейки между 0 и 3, используя:
def animate(i, Z, Z_critical):
plt.clf()
x=1
y=1
Z[x, y] = np.mod(Z[x, y] + 1, Z_critical)
ax = sns.heatmap(Z, square = True, cbar = False, vmin=0, vmax=4)
Так что, кажется, что это вызов функция лавины, которая как-то нарушена. Функция avalanch работает в течение l oop, но не повторяется в анимации.
Для удобства, вот весь код, с которым я сейчас играю в одном фрагменте:
%matplotlib notebook
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
import seaborn as sns
import random
dimension = 3
iterations = 100
Z_critical = 4
Z = np.zeros((dimension, dimension))
def avalanch(Z, Z_critical):
Z_new = np.copy(Z)
repeat = False
for x in range(dimension):
for y in range(dimension):
if x < dimension-1 and Z[x+1, y] >= Z_critical:
Z_new[x, y] = Z_new[x, y] + 1
Z_new[x+1, y] = 0
repeat = True
if y < dimension-1 and Z[x, y+1] >= Z_critical:
Z_new[x, y] = Z_new[x, y] + 1
Z_new[x, y+1] = 0
repeat = True
if x > 0 and Z[x-1, y] >= Z_critical:
Z_new[x, y] = Z_new[x, y] + 1
Z_new[x-1, y] = 0
repeat = True
if y > 0 and Z[x, y-1] >= Z_critical:
Z_new[x, y] = Z_new[x, y] + 1
Z_new[x, y-1] = 0
repeat = True
return(Z_new, repeat)
fig = plt.figure()
def animate(i, Z, Z_critical):
plt.clf()
#x = random.randrange(0, dimension)
#y = random.randrange(0, dimension)
x=1
y=1
Z[x, y] = Z[x, y] + 1
Z, repeat = avalanch(Z, Z_critical)
while repeat == True:
Z, repeat = avalanch(Z, Z_critical)
ax = sns.heatmap(Z, square = True, cbar = False, vmin=0, vmax=4)
anim = animation.FuncAnimation(fig, animate, fargs=(Z, Z_critical), frames=iterations, repeat = False)