Як оживити розкиданий сюжет?


83

Я намагаюся зробити анімацію розсіяного сюжету, де кольори та розмір точок змінюються на різному етапі анімації. Для даних у мене є два numpy ndarray зі значенням x і значенням y:

data.shape = (ntime, npoint)
x.shape = (npoint)
y.shape = (npoint)

Тепер я хочу побудувати графік розкиду типу

pylab.scatter(x,y,c=data[i,:])

і створити анімацію над індексом i. Як це зробити?


2
Є приклад у документації matplotlib: Симуляція дощу .
ImportanceOfBeingErnest

Відповіді:


142

Припустимо, у вас є графік розсіювання scat = ax.scatter(...), тоді ви можете

  • змінити позиції

          scat.set_offsets(array)
    

де array- N x 2фігурний масив координат x та y.

  • змінити розміри

          scat.set_sizes(array)
    

де array- 1D масив розмірів у точках.

  • змінити колір

          scat.set_array(array)
    

де array- одновимірний масив значень, які будуть кольоровими.

Ось короткий приклад використання модуля анімації .
Це дещо складніше, ніж повинно бути, але це має дати вам основу для того, щоб робити більш химерні справи.

(Код відредаговано у квітні 2019 року, щоб бути сумісним із поточними версіями. Для попереднього коду див. Історію редагувань )

import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np

class AnimatedScatter(object):
    """An animated scatter plot using matplotlib.animations.FuncAnimation."""
    def __init__(self, numpoints=50):
        self.numpoints = numpoints
        self.stream = self.data_stream()

        # Setup the figure and axes...
        self.fig, self.ax = plt.subplots()
        # Then setup FuncAnimation.
        self.ani = animation.FuncAnimation(self.fig, self.update, interval=5, 
                                          init_func=self.setup_plot, blit=True)

    def setup_plot(self):
        """Initial drawing of the scatter plot."""
        x, y, s, c = next(self.stream).T
        self.scat = self.ax.scatter(x, y, c=c, s=s, vmin=0, vmax=1,
                                    cmap="jet", edgecolor="k")
        self.ax.axis([-10, 10, -10, 10])
        # For FuncAnimation's sake, we need to return the artist we'll be using
        # Note that it expects a sequence of artists, thus the trailing comma.
        return self.scat,

    def data_stream(self):
        """Generate a random walk (brownian motion). Data is scaled to produce
        a soft "flickering" effect."""
        xy = (np.random.random((self.numpoints, 2))-0.5)*10
        s, c = np.random.random((self.numpoints, 2)).T
        while True:
            xy += 0.03 * (np.random.random((self.numpoints, 2)) - 0.5)
            s += 0.05 * (np.random.random(self.numpoints) - 0.5)
            c += 0.02 * (np.random.random(self.numpoints) - 0.5)
            yield np.c_[xy[:,0], xy[:,1], s, c]

    def update(self, i):
        """Update the scatter plot."""
        data = next(self.stream)

        # Set x and y data...
        self.scat.set_offsets(data[:, :2])
        # Set sizes...
        self.scat.set_sizes(300 * abs(data[:, 2])**1.5 + 100)
        # Set colors..
        self.scat.set_array(data[:, 3])

        # We need to return the updated artist for FuncAnimation to draw..
        # Note that it expects a sequence of artists, thus the trailing comma.
        return self.scat,


if __name__ == '__main__':
    a = AnimatedScatter()
    plt.show()

введіть тут опис зображення

Якщо ви використовуєте OSX і використовуєте серверну систему OSX, вам потрібно буде змінити blit=Trueзначення blit=Falseна FuncAnimationініціалізацію нижче. Бекенд OSX не повністю підтримує blitting. Продуктивність буде страждати, але приклад повинен працювати належним чином на OSX з відключеним функцією бліттингу.


Для більш простого прикладу, який просто оновлює кольори, подивіться на наступне:

import matplotlib.pyplot as plt
import numpy as np
import matplotlib.animation as animation

def main():
    numframes = 100
    numpoints = 10
    color_data = np.random.random((numframes, numpoints))
    x, y, c = np.random.random((3, numpoints))

    fig = plt.figure()
    scat = plt.scatter(x, y, c=c, s=100)

    ani = animation.FuncAnimation(fig, update_plot, frames=range(numframes),
                                  fargs=(color_data, scat))
    plt.show()

def update_plot(i, data, scat):
    scat.set_array(data[i])
    return scat,

main()

Привіт Джо, я спробував твій перший приклад, але він не працює, тоді як другий - так. Можливо, я спробую налагодити перший варіант, це допоможе мені вдосконалити свої знання python. Дякую
Нікола Віанелло

1
На жаль, перший приклад не відображається для мене також за допомогою matplotlib 1.3.1 в OS X. Я отримую, що кадр не ставить жодних точок Другий приклад працює.
JoshAdel

9
Як В СВІТІ ви придумали, що .set_array()оновить колір точок ?!
Лукас

1
Перший приклад не працює, вам доведеться змінити рядок self.Scat.set_offsets(data[:2, :]) на self.scat.set_offsets(data[:2, :].reshape(self.numpoints, 2))
AN O'Nyme

2
Чи існує якась функція, яка змінює маркери точок розсіювання?
Constantinos

13

Я написав целулоїд, щоб полегшити це. Це, мабуть, найпростіше показати на прикладі:

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

numpoints = 10
points = np.random.random((2, numpoints))
colors = cm.rainbow(np.linspace(0, 1, numpoints))
camera = Camera(plt.figure())
for _ in range(100):
    points += 0.1 * (np.random.random((2, numpoints)) - .5)
    plt.scatter(*points, c=colors, s=100)
    camera.snap()
anim = camera.animate(blit=True)
anim.save('scatter.mp4')

введіть тут опис зображення

Він використовується ArtistAnimationпід капотом. camera.snapфіксує поточний стан фігури, який використовується для створення кадрів в анімації.

Редагувати: Щоб кількісно визначити, скільки пам'яті це використовує, я пропустив її через memory_profiler .

Line #    Mem usage    Increment   Line Contents
================================================
    11     65.2 MiB     65.2 MiB   @profile
    12                             def main():
    13     65.2 MiB      0.0 MiB       numpoints = 10
    14     65.2 MiB      0.0 MiB       points = np.random.random((2, numpoints))
    15     65.2 MiB      0.1 MiB       colors = cm.rainbow(np.linspace(0, 1, numpoints))
    16     65.9 MiB      0.6 MiB       fig = plt.figure()
    17     65.9 MiB      0.0 MiB       camera = Camera(fig)
    18     67.8 MiB      0.0 MiB       for _ in range(100):
    19     67.8 MiB      0.0 MiB           points += 0.1 * (np.random.random((2, numpoints)) - .5)
    20     67.8 MiB      1.9 MiB           plt.scatter(*points, c=colors, s=100)
    21     67.8 MiB      0.0 MiB           camera.snap()
    22     70.1 MiB      2.3 MiB       anim = camera.animate(blit=True)
    23     72.1 MiB      1.9 MiB       anim.save('scatter.mp4')

Підсумовуючи це:

  • Для створення 100 ділянок використано 1,9 Мб.
  • Для створення анімації використано 2,3 Мб.
  • Цей метод створення анімації використовував 4,2 Мб пам’яті в сумі.

1
Оскільки для цього використовується ArtistAnimation, він створить 100 графіків розсіювання в пам'яті, що досить неефективно. Використовуйте це лише в тому випадку, якщо продуктивність для вас не є критичною.
ImportanceOfBeingErnest

1
Профілювання пам’яті - це гарна ідея. Ви робили те саме для FuncAnimation? Які відмінності?
ImportanceOfBeingErnest

1
Як ви відображаєте анімацію (замість того, щоб зберегти її у файл)?
argentum2f

5

Ось у чому річ. Я звик до користувача Qt та Matlab, і я не зовсім знайомий із системою анімації на matplotlib.

Але я знайшов спосіб, який може зробити будь-яку анімацію, яку ви хочете, так само, як у Matlab. Це дійсно потужно. Не потрібно перевіряти посилання на модулі, і вам добре скласти план, що завгодно. Тож я сподіваюся, що це може допомогти.

Основна ідея полягає у використанні часової події всередині PyQt (я впевнений, що інша система Gui на Python, така як wxPython та TraitUi, має однаковий внутрішній механізм для реагування на подію. Але я просто не знаю, як). Кожного разу, коли називається подія таймера PyQt, я оновлюю все полотно і перемальовую цілу картинку, я знаю, що на швидкість і продуктивність може повільно впливати, але це не так вже й багато.

Ось невеликий приклад цього:

import sys
from PyQt4 import QtGui

from matplotlib.figure import Figure
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas

import numpy as np


class Monitor(FigureCanvas):
    def __init__(self):
        self.fig = Figure()
        self.ax = self.fig.add_subplot(111)

        FigureCanvas.__init__(self, self.fig)
        self.x = np.linspace(0,5*np.pi,400)
        self.p = 0.0
        self.y = np.sin(self.x+self.p)


        self.line = self.ax.scatter(self.x,self.y)

        self.fig.canvas.draw()

        self.timer = self.startTimer(100)


    def timerEvent(self, evt):
        # update the height of the bars, one liner is easier
        self.p += 0.1
        self.y = np.sin(self.x+self.p)
        self.ax.cla()
        self.line = self.ax.scatter(self.x,self.y)

        self.fig.canvas.draw()



if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    w = Monitor()
    w.setWindowTitle("Convergence")
    w.show()
    sys.exit(app.exec_())

Ви можете налаштувати швидкість оновлення в

        self.timer = self.startTimer(100)

Я подібний до вас, хто хоче використовувати анімаційний сюжет розсіювання для створення сортувальної анімації. Але я просто не можу знайти так звану функцію "встановити". Тож я освіжив цілу канву.

Сподіваюся, це допоможе ..


Дійсно приємно! Однак я не змінив частоту оновлення, відрегулювавши self.startTimerзначення ... якісь поради щодо цього? (Так, я знаю, що минув якийсь час ...)
Х. Арпонен

-1

Чому б не спробувати це

import numpy as np
import matplotlib.pyplot as plt

x=np.random.random()
y=np.random.random()

fig, ax = plt.subplots()
ax.scatter(x,y,color='teal')
ax.scatter(y,x,color='crimson')
ax.set_xlim([0,1])
ax.set_ylim([0,1])

for i in np.arange(50):
    x=np.random.random()
    y=np.random.random()
    bha=ax.scatter(x,y)
    plt.draw()
    plt.pause(0.5)
    bha.remove()

plt.show()

Чому це було проти? Чи не працює?
Ерік
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.