【问题标题】:How to draw animation by taking snapshot with matplotlib?如何通过使用 matplotlib 拍摄快照来绘制动画?
【发布时间】:2022-01-10 02:18:57
【问题描述】:

在我的项目中,我为每个时间步绘制了许多多边形。

在每一步,多边形的数量都是不同的,因此很难保留 Axes.patchs 并翻译它们来制作动画。

我想用最终数字创建动画(调用matplotlib.pyplot.show()后显示),怎么做?

我们以 sin 曲线为例:

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

fig = plt.figure()
ims = []
x = np.linspace(0, 2 * np.pi, 100)
y = np.sin(x)
z = np.cos(x)
for i in range(1,100):
    tmpx = x[:i]
    tmpy = y[:i]
    tmpz = z[:i]
    plt.plot(tmpx, tmpz)
    im = plt.plot(tmpx, tmpy)
    ims.append(im)

ani = animation.ArtistAnimation(fig, ims, interval=200)
ani.save('/home/test.gif', writer='imagemagick')

plt.show()

有两种曲线:动画正弦曲线和静态余弦曲线。

  • 每个步骤的 sin 曲线都保存为 Line2D 对象
  • 余弦曲线在每一步都保持不变。

这样,我们为每个步骤显示不同的Artist 对象。

但我想为每一步保留光栅化的Line2D 图。

我找到了AxesImage/FigureImage 的类,但我不知道如何保存栅格化图形并使其工作。

我尝试使用以下代码将figure.canvas 转换为AxesImage

def fig2AxesImage(fig):
    import PIL.Image as Image
    fig.canvas.draw()

    w, h = fig.canvas.get_width_height()
    buf = numpy.fromstring(fig.canvas.tostring_argb(), dtype=numpy.uint8)
    buf.shape = (w, h, 4)

    # canvas.tostring_argb give pixmap in ARGB mode. Roll the ALPHA channel to have it in RGBA mode
    buf = numpy.roll(buf, 3, axis=2)
    image = Image.frombytes("RGBA", (w, h), buf.tostring())
    image = numpy.asarray(image)
    return plt.imshow(image, animated=True)

但是通过这种方式,我必须在下一帧开始时清除画布,这使得最终动画成为空白视频。 (但我为每个步骤输出的.jpg 数字得到了正确的内容)

在将matplotlib.pyplot.figure() 的光栅化画布图形保存为动画视频之前,有没有人这样做过?

【问题讨论】:

  • 你试过赛璐珞库了吗?
  • 赛璐珞真是一部优秀的作品!完美解决问题!
  • @JohanC 非常感谢。但是我必须使用的 python 2.7 不支持赛璐珞。所以我把它转换成python 2.7。代码贴在下面。

标签: python matplotlib animation


【解决方案1】:

用于 python 2.7 的赛璐珞

''' copy from celluloid'''

# from typing import Dict, List  # not supported by python 2.7. So comment it
from collections import defaultdict

from matplotlib.figure import Figure
from matplotlib.artist import Artist
from matplotlib.animation import ArtistAnimation

__version__ = '0.2.0'

class Camera:
    def __init__(self, figure):
        self.figure_ = figure
        self.offsets_ = { k:defaultdict(int) \
            for k in ['collections', 'patches', 'lines', 'texts', 'artists', 'images']
        }

        self.photos_ = []

    def snap(self):
        frame_artists = []
        for i, axis in enumerate(self.figure_.axes):
            if axis.legend_ is not None:
                axis.add_artist(axis.legend_)
            for name in self.offsets_:
                new_artists = getattr(axis, name)[self.offsets_[name][i]:]
                frame_artists += new_artists
                self.offsets_[name][i] += len(new_artists)
        self.photos_.append(frame_artists)

    def animate(self):
        return ArtistAnimation(self.figure_, self.photos_)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-23
    相关资源
    最近更新 更多