【问题标题】:How to use line.set_data for data that is a 2 dimensional array in matplotlib?如何将 line.set_data 用于 matplotlib 中的二维数组数据?
【发布时间】:2021-06-07 10:14:05
【问题描述】:

我正在尝试在 matplotlib 中一次为多行设置动画。为此,我遵循 matplotlib.animation 文档中的教程:

https://matplotlib.org/stable/api/animation_api.html

本教程的想法是创建一条线ln, = plt.plot([], [])并使用ln.set_data更新该线的数据以生成动画。虽然当线数据是n个数据点的一维数组(形状=(n,))时这一切都很好,但当线数据是二维数组(形状=(n,k))时我遇到了麻烦要绘制的 k 条线。

更准确地说,plt.plot 接受数组作为输入,每列对应于要绘制的新线。这是一个简单的例子,用一个 plt.plot 调用绘制了 3 条线:

import matplotlib.pyplot as plt
import numpy as np


x = np.linspace(0, 2 * np.pi, 100).reshape(-1, 1)
x = np.concatenate([x] * 3, axis=1)

# generate 3 curves
y = np.copy(x)
y[:, 0] = np.cos(y[:, 0])
y[:, 1] = np.sin(y[:, 1] )
y[:, 2] = np.sin(y[:, 2] ) + np.cos(y[:, 2])

fig, ax = plt.subplots()
plt.plot(x,y)
plt.show()

但是,如果我尝试使用 .set_data 来设置生成动画所需的数据,我会遇到问题:

import matplotlib.pyplot as plt
import numpy as np


x = np.linspace(0, 2 * np.pi, 100).reshape(-1, 1)
x = np.concatenate([x] * 3, axis=1)

# generate 3 curves
y = np.copy(x)
y[:, 0] = np.cos(y[:, 0])
y[:, 1] = np.sin(y[:, 1] )
y[:, 2] = np.sin(y[:, 2] ) + np.cos(y[:, 2])

fig, ax = plt.subplots()
p, = plt.plot([], [], color='b')
p.set_data(x, y)
plt.show()

有没有办法set_data 用于二维数组?虽然我知道我可以创建三个绘图 p1, p2, p3 并在每个循环上调用 set_data,但我的真实数据包含 1000-10,000 行来绘制,这使得动画太慢了。

非常感谢您的帮助。

【问题讨论】:

    标签: python numpy matplotlib matplotlib-animation


    【解决方案1】:

    一种方法是创建Line2D 对象列表并在循环中使用set_data。请注意,ax.plot() 始终返回行列表,即使只绘制了一条线。

    import matplotlib.pyplot as plt
    from matplotlib.animation import FuncAnimation
    import numpy as np
    
    x = np.linspace(0, 2 * np.pi, 100)
    
    # generate 10 curves
    y = np.sin(x.reshape(-1, 1) + np.random.uniform(0, 2 * np.pi, (1, 10)))
    
    fig, ax = plt.subplots()
    ax.set(xlim=(0, 2 * np.pi), ylim=(-1.5, 1.5))
    # lines = [ax.plot([], [], lw=2)[0] for _ in range(y.shape[1])]
    lines = ax.plot(np.empty((0, y.shape[1])), np.empty((0, y.shape[1])), lw=2)
    
    def animate(i):
        for line_k, y_k in zip(lines, y.T):
            line_k.set_data(x[:i], y_k[:i])
        return lines
    
    anim = FuncAnimation(fig, animate, frames=x.size, interval=200, repeat=False)
    plt.show()
    

    【讨论】:

    • 太好了,这很有意义。谢谢@JohanC​​pan>
    【解决方案2】:

    set_data() 给出的数组将是两个一维数组,所以在这种情况下需要三个 set_data()。

    import matplotlib.pyplot as plt
    from matplotlib.animation import FuncAnimation
    import numpy as np
    
    x = np.linspace(0, 2 * np.pi, 100).reshape(-1, 1)
    x = np.concatenate([x] * 3, axis=1)
    
    # generate 3 curves
    y = np.copy(x)
    y[:, 0] = np.cos(y[:, 0])
    y[:, 1] = np.sin(y[:, 1] )
    y[:, 2] = np.sin(y[:, 2] ) + np.cos(y[:, 2])
    
    fig, ax = plt.subplots()
    ax = plt.axes(xlim=(0,6), ylim=(-1.5, 1.5))
    line1, = ax.plot([], [], lw=2)
    line2, = ax.plot([], [], lw=2)
    line3, = ax.plot([], [], lw=2)
    
    
    def animate(i):
        line1.set_data(x[:i, 0], y[:i, 0])
        line2.set_data(x[:i, 1], y[:i, 1])
        line3.set_data(x[:i, 2], y[:i, 2])
        return line1,line2,line3
    
    anim = FuncAnimation(fig, animate, frames=100, interval=200, repeat=False)
    plt.show()
    

    【讨论】:

    • 动画一旦你了解它是如何工作的就很容易了。如果我的回答对您的问题有所帮助,请接受此作为正确答案。
    • 您好,感谢您的回复。正如我在问题中所说:“”虽然我知道我可以创建三个图 p1、p2、p3 并在每个循环中调用 set_data,但我的真实数据包含 1000-10,000 行来绘制...... "" 我试图列出所有图,然后在update 函数期间循环更新它们的数据。但是,这不起作用,因为update 的输出需要是绘图而不是绘图列表。
    • 将所有行放在一个列表中还不够吗?然后返回那个列表?类似lines = [ax.plot([], [], lw=2)[0] for _ in range(y.shape[1])],并在循环中使用set_data
    • @JohanC lines 不知道如何为 Line2D 对象列表编写 set_data() 。毕竟,lines[0].set_data() 需要 3 行。请指教。
    • 我添加了一个答案,并将我的评论翻译成代码。这只是您的方法扩展到循环。 (注意ax = plt.axes(...)plt.subplots() 创建的子图之上创建了第二个子图。您可能需要删除其中一个)
    猜你喜欢
    • 2017-04-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-05
    • 2018-10-29
    • 1970-01-01
    • 2019-02-07
    相关资源
    最近更新 更多