在 matplotlib 中使用 for 循环定义要动画的多个绘图
Posted
技术标签:
【中文标题】在 matplotlib 中使用 for 循环定义要动画的多个绘图【英文标题】:Defining multiple plots to be animated with a for loop in matplotlib 【发布时间】:2014-03-23 04:14:45 【问题描述】:Thanks to Jake Vanderplas,我知道如何使用matplotlib
开始编写动画情节。这是一个示例代码:
from matplotlib import pyplot as plt
from matplotlib import animation
fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(0, 100))
line, = plt.plot([], [])
def init():
line.set_data([], [])
return line,
def animate(i):
line.set_data([0, 2], [0,i])
return line,
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=100, interval=20, blit=True)
plt.show()
假设现在我想绘制大量函数(这里说四个),在循环的帮助下定义。我做了一些伏都教编程,试图了解如何模仿逗号后面的行,这就是我得到的(不用说它不起作用:AttributeError: 'tuple' object has no attribute 'axes'
)。
from matplotlib import pyplot as plt
from matplotlib import animation
fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(0, 100))
line = []
N = 4
for j in range(N):
temp, = plt.plot([], [])
line.append(temp)
line = tuple(line)
def init():
for j in range(N):
line[j].set_data([], [])
return line,
def animate(i):
for j in range(N):
line[j].set_data([0, 2], [10 * j,i])
return line,
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=100, interval=20, blit=True)
plt.show()
我的一些问题是:我怎样才能让它发挥作用?奖励(可能链接):line, = plt.plot([], [])
和 line = plt.plot([], [])
有什么区别?
谢谢
【问题讨论】:
【参考方案1】:在下面的解决方案中,我展示了一个更大的示例(还有条形图),它可以帮助人们更好地理解其他情况下应该做什么。在代码之后,我解释了一些细节并回答了奖金问题。
import matplotlib
matplotlib.use('Qt5Agg') #use Qt5 as backend, comment this line for default backend
from matplotlib import pyplot as plt
from matplotlib import animation
fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(0, 100))
N = 4
lines = [plt.plot([], [])[0] for _ in range(N)] #lines to animate
rectangles = plt.bar([0.5,1,1.5],[50,40,90],width=0.1) #rectangles to animate
patches = lines + list(rectangles) #things to animate
def init():
#init lines
for line in lines:
line.set_data([], [])
#init rectangles
for rectangle in rectangles:
rectangle.set_height(0)
return patches #return everything that must be updated
def animate(i):
#animate lines
for j,line in enumerate(lines):
line.set_data([0, 2], [10 * j,i])
#animate rectangles
for j,rectangle in enumerate(rectangles):
rectangle.set_height(i/(j+1))
return patches #return everything that must be updated
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=100, interval=20, blit=True)
plt.show()
说明
这个想法是绘制您需要的内容,然后重用 matplotlib
返回的艺术家(查看更多 here)。这是通过首先绘制您想要的虚拟草图并保留matplotlib
给您的对象来完成的。然后在您的 init
和 animate
函数上,您可以更新需要动画的对象。
请注意,在plt.plot([], [])[0]
中,我们有一个线条艺术家,因此我使用[plt.plot([], [])[0] for _ in range(N)]
收集它们。另一方面,plt.bar([0.5,1,1.5],[50,40,90],width=0.1)
返回一个可以为 矩形艺术家 迭代的容器。 list(rectangles)
只需将此容器转换为要与lines
连接的列表。
我将线条与矩形分开,因为它们的更新方式不同(并且是不同的艺术家),但 init
和 animate
将它们全部返回。
额外问题的答案:
line, = plt.plot([], [])
将plt.plot
返回的列表的第一个元素分配给可验证的line
。
line = plt.plot([], [])
只需分配整个列表(只有一个元素)。
【讨论】:
非常感谢。请问plt.plot
列表的第一个元素是什么?
plt.plot
返回matplotlib.artist.Artist
s 的列表,因此当您仅绘制一行时,它会返回仅包含一项的列表:matplotlib.lines.Line2D
艺术家。但是,如果您像lines = plt.plot( *([[], []]*N) )
那样绘制多行,它会返回列表中的所有行。
谢谢。最后一个问题。 animate
的return
中line
后面的逗号不是强制的吗?如果我正确理解您的解决方案,则没有这样的逗号。
没有逗号,但请检查我是否这样做plt.plot([], [])[0]
以获得第一个值。 line, = plt.plot([], [])
语法是使用 a,b = [1,2]
上的 python 赋值的解包功能使 line = plt.plot([], [])[0]
这一行更简洁
嗨,我可以问一个问题来扩展这个吗?在您的示例中,您有多个 lines
对象,但是如果我想更新 lines
和 image
对象会发生什么(例如更新点的位置并更新动画中的 matshow()
数组。我可以把这两个在同一个元组中?【参考方案2】:
这是一个更易读的修改示例。 这只是 matplotlib 网站上添加的另一段代码。让我感到震惊的是,我最初并没有意识到 plt 函数正在返回列表,忽略尾随逗号,甚至是如何将事物联系在一起,这似乎是由库本身隐含地处理的。但关键是创建几个可更新的对象,并将它们从两个关键函数中返回,作为同一列表的一部分,并且它们将在动画运行时同步。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
fig, ax = plt.subplots()
xdata, ydata = [], []
xdata2,ydata2= [], []
ln, = plt.plot([], [], 'ro')
ln2, = plt.plot([], [], 'ro')
def init():
ax.set_xlim(0, 2*np.pi)
ax.set_ylim(-1, 1)
return ln,ln2
def update(frame):
xdata.append(frame)
ydata.append(np.sin(frame))
ln.set_data(xdata, ydata)
xdata2.append(frame)
ydata2.append(np.cos(frame))
ln2.set_data(xdata2,ydata2)
return ln,ln2
ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128),
init_func=init, blit=True)
plt.show()
为了更有趣,将动画回调更改为以下内容:
def update(frame):
xdata.append(frame)
ydata.append(np.sin(frame))
ln.set_data(xdata, ydata)
delta = 2*np.pi/128
xdata2.append([frame*2,frame*2+delta])
ydata2.append([np.cos(frame*2), np.cos(frame*2+delta)])
ln2.set_data(xdata2,ydata2)
return ln,ln2
【讨论】:
以上是关于在 matplotlib 中使用 for 循环定义要动画的多个绘图的主要内容,如果未能解决你的问题,请参考以下文章
Python使用matplotlib来for循环实时画图为啥会出现多个图出来,循环几次就出来几个图,啥原因?
Python使用matplotlib可视化连续(数值)变量的堆叠的直方图自定义堆叠直方图中不同分组条形的色彩(Histogram for Continuous Variable)