LineCollection 动画 [英] LineCollection animation

查看:91
本文介绍了LineCollection 动画的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于以下代码(MWE),如果有一行

For the following code (MWE), if the line

ax.set_axis_off()

被注释掉,然后动画什么也不显示.否则,动画将按预期工作.我的问题是:为什么?

is commented out, then the animation shows nothing. Otherwise, the animation works as expected. My question is: why?

from itertools import tee

import numpy as np

import matplotlib
matplotlib.use('Agg')           # noqa
from matplotlib.animation import FuncAnimation, FFMpegWriter
from matplotlib.collections import LineCollection
from matplotlib.colors import ListedColormap, BoundaryNorm
import matplotlib.pyplot as plt


def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    a, b = tee(iterable)
    next(b, None)
    return zip(a, b)


def make_segs(x, y):
    xs = np.array(list(pairwise(x)))  # (n,2)
    ys = np.array(list(pairwise(y)))  # (n,2)
    segs = np.stack((xs, ys), axis=-1)  # (n,2,2)
    return segs


class _AnimationHelper():
    def __init__(self, xs, ys, z, colors=['r', 'g']):
        self.segs = np.array([make_segs(x, y) for x, y in zip(xs, ys)])
        self.z = z
        self.colors = colors
        self.fig = plt.figure()
        self.lns = []
        self.ani = FuncAnimation(
            self.fig,
            self.update,
            interval=200,
            init_func=self.init,
            frames=self.segs.shape[1],
            blit=True)

    def init(self):
        m, n = self.segs.shape[:2]
        self.fig.set_size_inches(m*5, 5)
        self.axes = self.fig.subplots(
            nrows=1, ncols=m, sharey='row')
        self.fig.tight_layout()
        cmap = ListedColormap(self.colors)
        norm = BoundaryNorm([0, 0.5, 1], cmap.N)
        zero = np.zeros(n, dtype=np.int32)
        for i in range(m):
            inds = (zero + i) == self.z
            ln = LineCollection([], cmap=cmap, norm=norm, lw=2, animated=True)
            ln.set_array(inds)
            self.lns.append(ln)

            ax = self.axes[i]
            ax.add_collection(ln)
            ax.set_xlim(0, n)
            ax.set_axis_off()  # <---- HERE

        self.axes[0].set_ylim(0, 1.1)
        for i in range(1, m):
            self.axes[i].tick_params(left=False)
        return self.lns

    def update(self, ind):
        print(ind)
        m = self.segs.shape[0]
        for i in range(m):
            self.lns[i].set_segments(self.segs[i, :(ind + 1)])
        return self.lns


N = 20
M = 3

x = np.arange(N)
xs = np.repeat(x.reshape([1, -1]), M, axis=0)
ys = np.exp(-xs) + 0.05*np.random.random((M, N))
z = np.array([2]*4 + [1]*5 + [0]*5 + [2]*5)

helper = _AnimationHelper(xs, ys, z)
writer = FFMpegWriter(fps=5, codec='mpeg4')
helper.ani.save('out/test_saveani.mp4', writer=writer, dpi=80)

推荐答案

为了保存图形,不需要使用 blit.如果不加说明,则该图将正确保存.但是,未考虑图形尺寸的更改,因为动画是在更改之前创建的.在创建动画之前创建图形和所有轴都可以正常工作,即使使用了 blitting.

For saving a figure, the use of blit is not necessary. If that is left out, the figure is saved correctly. However, the figure size change is not taken into account, because the animation is created before that change. Creating the figure and all the axes before creating the animation works perfectly fine though, even with blitting being used.

from itertools import tee

import numpy as np

import matplotlib
matplotlib.use('Agg')           # noqa
from matplotlib.animation import FuncAnimation, FFMpegWriter
from matplotlib.collections import LineCollection
from matplotlib.colors import ListedColormap, BoundaryNorm
import matplotlib.pyplot as plt


def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    a, b = tee(iterable)
    next(b, None)
    return zip(a, b)


def make_segs(x, y):
    xs = np.array(list(pairwise(x)))  # (n,2)
    ys = np.array(list(pairwise(y)))  # (n,2)
    segs = np.stack((xs, ys), axis=-1)  # (n,2,2)
    return segs


class _AnimationHelper():
    def __init__(self, xs, ys, z, colors=['r', 'g']):
        self.segs = np.array([make_segs(x, y) for x, y in zip(xs, ys)])
        self.z = z
        self.colors = colors
        self.fig = plt.figure()
        self.lns = []

        m, n = self.segs.shape[:2]
        self.fig.set_size_inches(m*5, 5, forward=True)
        self.axes = self.fig.subplots(
            nrows=1, ncols=m, sharey='row')
        self.fig.tight_layout()

        self.ani = FuncAnimation(
            self.fig,
            self.update,
            interval=200,
            init_func=self.init,
            frames=self.segs.shape[1],
            blit=True)

    def init(self):
        m, n = self.segs.shape[:2]
        cmap = ListedColormap(self.colors)
        norm = BoundaryNorm([0, 0.5, 1], cmap.N)
        zero = np.zeros(n, dtype=np.int32)
        for i in range(m):
            inds = (zero + i) == self.z
            ln = LineCollection([], cmap=cmap, norm=norm, lw=2, animated=True)
            ln.set_array(inds)
            self.lns.append(ln)

            ax = self.axes[i]
            ax.add_collection(ln)
            ax.set_xlim(0, n)
            #ax.set_axis_off()  # <---- HERE

        self.axes[0].set_ylim(0, 1.1)
        for i in range(1, m):
            self.axes[i].tick_params(left=False)
        return self.lns

    def update(self, ind):
        print(ind)
        m = self.segs.shape[0]
        for i in range(m):
            self.lns[i].set_segments(self.segs[i, :(ind + 1)])
        return self.lns


N = 20
M = 3

x = np.arange(N)
xs = np.repeat(x.reshape([1, -1]), M, axis=0)
ys = np.exp(-xs) + 0.05*np.random.random((M, N))
z = np.array([2]*4 + [1]*5 + [0]*5 + [2]*5)

helper = _AnimationHelper(xs, ys, z)
writer = FFMpegWriter(fps=5, codec='mpeg4')
helper.ani.save('test_saveani.mp4', writer=writer, dpi=80)

以上内容甚至允许使用交互式后端 matplotlib.use('TkAgg')并通过 plt.show()显示该图.

The above now even allows to use an interactive backend, matplotlib.use('TkAgg') and showing the figure via plt.show().

这篇关于LineCollection 动画的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆