Анимация песочной кучи: почему вызов этой функции через некоторое время l oop нарушает мою анимацию? Анимация анимации.FuncAnimation ведет себя как для l oop? - PullRequest
0 голосов
/ 14 января 2020

Я пытаюсь создать анимацию абелевой песочницы с использованием массивов 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...