如何为散点图制作动画?


83

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

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

现在我想绘制一个散点图

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

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


2
matplotlib文档中有一个示例:Rain模拟
ImportanceOfBeingErnest

Answers:


142

假设您有一个散点图scat = ax.scatter(...),则可以

  • 改变立场

          scat.set_offsets(array)
    

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

  • 改变大小

          scat.set_sizes(array)
    

其中array是以点为单位的一维尺寸数组。

  • 改变颜色

          scat.set_array(array)
    

其中array是一维值数组,将对其进行颜色映射。

这是一个使用animation模块的简单示例。
它比必须的要复杂一些,但是这应该为您提供一个做奇特的事情的框架。

(代码编辑于2019年4月以与当前版本兼容。有关旧代码,请参阅修订历史记录

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为。OSX后端不完全支持blitting。性能会受到影响,但是示例应在禁用blitting的情况下在OSX上正确运行。blit=FalseFuncAnimation


对于一个仅更新颜色的简单示例,请查看以下内容:

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的知识。谢谢
Nicola Vianello

1
不幸的是,第一个示例在OS X上使用matplotlib 1.3.1都没有为我显示。我得到的框架没有显示任何点。第二个示例有效。
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
是否有任何功能可以更改散点的标记?
君士坦丁斯

13

我写了赛璐to,以使其更容易。可能最容易举例说明:

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

总结一下:

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

1
由于此操作使用ArtistAnimation,因此将在内存中创建100个散点图,这效率很低。仅在性能对您不重要的情况下才使用此功能。
ImportanceOfBeingErnest

1
内存分析是一个好主意。您是否也这样做了FuncAnimation?有什么区别?
ImportanceOfBeingErnest

1
如何分散动画(与将动画保存到文件有关)?
argentum2f

5

这是东西。我曾经是Qt和Matlab的用户,但对matplotlib上的动画系统不太熟悉。

但是我确实找到了一种方法,可以像制作matlab一样制作任何想要的动画。它真的很强大。无需检查模块引用,就可以绘制所需的任何东西。因此,我希望它能有所帮助。

基本思想是在PyQt内部使用时间事件(我确定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)

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

希望能帮助到你..


非常好!但是,通过调整该self.startTimer值,刷新率没有任何变化。关于此的任何提示?(是的,我知道已经有一段时间了……)
H. Arponen

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

为什么这被否决?不行吗
eric
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.