如何为散点图设置动画?

Nic*_*llo 57 python matplotlib

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

data.shape = (ntime, npoint)
x.shape = (npoint)
y.shape = (npoint)
Run Code Online (Sandbox Code Playgroud)

现在我想绘制一个类型的散点图

pylab.scatter(x,y,c=data[i,:])
Run Code Online (Sandbox Code Playgroud)

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

Joe*_*ton 99

这是使用新动画模块的快速示例.

它稍微复杂一点,但这应该给你一个框架来做更好的事情.

如果你在OSX和使用OSX后端,您需要更改scat = ax.scatter(...)arrayN x 2下面的初始化.OSX后端不完全支持blitting.性能将受到影响,但该示例应该在OSX上正确运行并禁用blit.

    scat.set_offsets(array)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

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

    scat.set_sizes(array)
Run Code Online (Sandbox Code Playgroud)

  • 你是怎么发现`.set_array()` 会更新点颜色的?! (17认同)
  • 有没有什么函数可以改变散点的标记? (3认同)
  • 不幸的是,第一个示例在 OS X 上使用 matplotlib 1.3.1 时也没有显示。我得到的框架没有显示任何点。第二个例子有效。 (2认同)

Tom*_*Tom 9

TL/DR:ax.set_...如果您在使用散点图动画方法时遇到问题,您可以尝试清除每一帧的绘图(即ax.clear())并根据需要重新绘制内容。这比较慢,但是当您想在小动画中更改很多内容时可能很有用。


这是一个演示这种“清晰”方法的示例:

import itertools

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

# set parameters
frames = 10
points = 20
np.random.seed(42)

# create data
data = np.random.rand(points, 2)

# set how the graph will change each frame
sizes = itertools.cycle([10, 50, 150])
colors = np.random.rand(frames, points)
colormaps = itertools.cycle(['Purples', 'Blues', 'Greens', 'Oranges', 'Reds'])
markers = itertools.cycle(['o', 'v', '^', 's', 'p'])

# init the figure
fig, ax = plt.subplots(figsize=(5,5))

def update(i):
    # clear the axis each frame
    ax.clear()

    # replot things
    ax.scatter(data[:, 0], data[:, 1],
               s=next(sizes),
               c=colors[i, :],
               cmap=next(colormaps),
               marker=next(markers))

    # reformat things
    ax.set_xlabel('world')
    ax.set_ylabel('hello')

ani = animation.FuncAnimation(fig, update, frames=frames, interval=500)
ani.save('scatter.gif', writer='pillow')
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

我从 matplotlib 和其他来源看到的教程似乎没有使用这种方法,但我看到其他人(以及我自己)在这个网站上建议它。我看到了一些优点和缺点,但我很欣赏其他人的想法:

优点

  • 您可以避免使用set_...散点图的方法(即.set_offsets(),,.set_sizes()...),这些方法具有更晦涩且不太详细的文档(尽管主要答案将使您在这里走得很远!)。另外,不同的绘图类型有不同的方法(例如,用于set_data线条,但不用于散点)。通过清除轴,您可以像 matplotlib 中的任何其他绘图一样确定每帧的绘制元素。
  • 更重要的是,尚不清楚某些属性是否set可用,例如标记类型(如注释)或颜色图。ax.set_...例如,由于标记和颜色图的更改,我不知道如何使用 创建上述绘图。但这是非常基本的ax.scatter()

缺点

  • 它可能会慢得多;即清除和重绘所有内容似乎比这些set...方法更昂贵。所以对于大型动画来说,这种方法可能有点痛苦。
  • 清除轴也会清除轴标签、轴限制、其他文本等内容。因此,这些类型的格式化内容需要包含在update(否则它们将消失)。如果您希望更改某些内容,但其他内容保持不变,这可能会很烦人。

当然,速度是一个很大的缺点。这是一个显示差异的示例。鉴于此数据:

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

np.random.seed(42)
frames = 40

x = np.arange(frames)
y = np.sin(x)
colors = itertools.cycle(['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet'])
data = [(np.random.uniform(-1, 1, 10) + x[i],
         np.random.uniform(-1, 1, 10) + y[i])
        for i in range(frames)]
Run Code Online (Sandbox Code Playgroud)

您可以使用以下set...方法进行绘图:

fig, ax = plt.subplots()

s = ax.scatter([], [])

ax.set_xlim(-2, frames+2)
ax.set_ylim(min(y) - 1, max(y) + 1)

def update(i):
    s.set_offsets(np.column_stack([data[i][0], data[i][1]]))
    s.set_facecolor(next(colors))

ani = animation.FuncAnimation(fig, update, frames=frames, interval=100)
ani.save('set.gif', writer='pillow')
Run Code Online (Sandbox Code Playgroud)

或者“清除”方法:

fig, ax = plt.subplots()

def update(i):
    ax.clear()
    ax.scatter(data[i][0], data[i][1], c=next(colors))
    ax.set_xlim(-2, frames+2)
    ax.set_ylim(min(y) - 1, max(y) + 1)

ani = animation.FuncAnimation(fig, update, frames=frames, interval=100)
ani.save('clear.gif', writer='pillow')
Run Code Online (Sandbox Code Playgroud)

要得到这个数字:

在此输入图像描述

使用%%time,我们可以看到清除和重新绘制所需的时间是原来的两倍以上:

  • 为了set...Wall time: 1.33 s
  • 为了明确:Wall time: 2.73 s

使用frames参数以不同的比例进行测试。对于较小的动画(较少的帧/数据),两种方法之间的时间差异无关紧要(对我来说,有时会导致我更喜欢清除方法)。但对于较大的情况,使用set_...可以节省大量时间。


Jac*_*vam 6

我写了赛璐 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')
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

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')
Run Code Online (Sandbox Code Playgroud)

总结一下:

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

  • 由于这使用了 ArtistAnimation,它将在内存中创建 100 个散点图,这是相当低效的。仅当性能对您不重要时才使用它。 (2认同)

tk_*_*963 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_())
Run Code Online (Sandbox Code Playgroud)

您可以在

        self.timer = self.startTimer(100)
Run Code Online (Sandbox Code Playgroud)

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

希望能帮助到你..