如何为散点图设置动画?

时间:2012-02-22 19:32:23

标签: python matplotlib

我正在尝试制作散点图的动画,其中点的颜色和大小在动画的不同阶段发生变化。对于数据,我有两个numpy ndarray,其中包含x值和y值:

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

现在我想绘制一个

类型的散点图
pylab.scatter(x,y,c=data[i,:])

并在索引i上创建动画。我该怎么做?

4 个答案:

答案 0 :(得分:83)

假设您有散点图scat = ax.scatter(...),那么您可以

  • 更改职位

        scat.set_offsets(array)
    

    其中arrayN x 2形状的x和y坐标。

  • 更改尺寸

        scat.set_sizes(array)
    

    其中array是以点为单位的1D数组。

  • 更改颜色

        scat.set_array(array)
    

    其中array是将进行色彩映射的一维数组值。

以下是使用animation module的简单示例 它稍微复杂一点,但这应该给你一个框架来做更好的事情。

(2019年4月编辑的代码与当前版本兼容。对于较旧的代码,请参阅revision history

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()

enter image description here

如果您使用OSX并使用OSX后端,则需要在下面的blit=True初始化中将blit=False更改为FuncAnimation。 OSX后端不完全支持blitting。性能将受到影响,但该示例应该在OSX上正确运行且禁用blit。


有关更新颜色的简单示例,请查看以下内容:

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()

答案 1 :(得分:3)

这是事情。我曾经是Qt和Matlab的用户,我对matplotlib上的动画系统并不熟悉。

但我确实找到了一种可以制作任何类型动画的方法,就像在matlab中一样。它真的很强大。无需检查模块参考,您可以根据需要绘制任何内容。所以我希望它可以提供帮助。

基本的想法是在PyQt中使用time事件(我确信Python上的其他Gui系统就像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)

我就像你想要使用动画散点图来制作排序动画一样。但我只是找不到所谓的“设置”功能。所以我刷新了整个canva。

希望有所帮助......

答案 2 :(得分:3)

我写了celluloid来简化这个过程。可能最容易通过示例显示:

int second = decomposedPortion(baz);
TypeR result = foo(first, second);

enter image description here

它在引擎盖下使用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捕获图形的当前状态,该状态用于在动画中创建帧。

编辑:为了量化使用的内存量,我将其运行到memory_profiler

camera.snap

总结一下:

  • 使用1.9 MiB创建100个地块。
  • 制作动画时使用的是2.3 MiB。
  • 这种制作动画的方法总共使用了4.2 MiB的内存。

答案 3 :(得分:-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()