Как оживить участок рассеяния?

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

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

Теперь я хочу построить график рассеяния типа

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

и создайте анимацию по индексу i. Как это сделать?

Ответ 1

Вот краткий пример использования нового модуля анимации.

Это немного сложнее, чем должно быть, но это должно дать вам фреймворк, чтобы делать более интересные вещи.

Если вы используете OSX и используете бэкэнд OSX, вам нужно изменить blit=True на blit=False в инициализации FuncAnimation ниже. Бэкэнд OSX не полностью поддерживает блиты. Производительность будет страдать, но пример должен корректно работать на OSX с отключенным blitting.

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)
        self.scat = self.ax.scatter(x, y, c=c, s=s, animated=True)
        self.ax.axis([-10, 10, -10, 10])

        # For FuncAnimation 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."""
        data = np.random.random((4, self.numpoints))
        xy = data[:2, :]
        s, c = data[2:, :]
        xy -= 0.5
        xy *= 10
        while True:
            xy += 0.03 * (np.random.random((2, self.numpoints)) - 0.5)
            s += 0.05 * (np.random.random(self.numpoints) - 0.5)
            c += 0.02 * (np.random.random(self.numpoints) - 0.5)
            yield data

    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._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,

    def show(self):
        plt.show()

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

enter image description here

Для более простого примера рассмотрим следующее:

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=xrange(numframes),
                                  fargs=(color_data, scat))
    plt.show()

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

main()

Ответ 2

Вот что. Я использовал пользователя Qt и Matlab, и я не очень хорошо знаком с анимационной системой на matplotlib.

Но у меня есть способ, который может сделать любую анимацию, которую вы хотите, точно так же, как в MATLAB. Это действительно мощно. Нет необходимости проверять ссылки на модуль, и вы можете нарисовать все, что захотите. Поэтому я надеюсь, что это поможет.

Основная идея - использовать временное событие внутри PyQt (я уверен, что другая система Gui на Python, например wxPython и TraitUi, имеет тот же внутренний механизм, что и для ответа на событие. Но я просто не знаю, как это сделать). Каждый раз, когда вызывается событие PyQt Timer, я обновляю весь холст и перерисовываю всю картину, я знаю, что скорость и производительность могут медленно влиять, но это не так много.

Вот небольшой пример:

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)

Я точно так же, как вы, который хочет использовать анимационный график рассеяния, чтобы создать сортировочную анимацию. Но я просто не могу найти так называемую функцию "set". Итак, я обновил всю майку.

Надеюсь, что это поможет.