代码如下:
心得后附。
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
class AnimatedScatter(object):
"""An animated scatter plot using matplotlib.animations.FuncAnimation."""
def __init__(self, numpoints=50):
self.numpoints = numpoints
self.stream = self.data_stream()
# Setup the figure and axes...
self.fig, self.ax = plt.subplots()
# Then setup FuncAnimation.
self.ani = animation.FuncAnimation(self.fig, self.update, interval=5,
init_func=self.setup_plot, blit=True)
def setup_plot(self):
"""Initial drawing of the scatter plot."""
x, y, s, c = next(self.stream)
self.scat = self.ax.scatter(x, y, c=c, s=s, animated=True)
self.ax.axis([-10, 10, -10, 10])
# For FuncAnimation's sake, we need to return the artist we'll be using
# Note that it expects a sequence of artists, thus the trailing comma.
return self.scat,
def data_stream(self):
"""Generate a random walk (brownian motion). Data is scaled to produce
a soft "flickering" effect."""
data = np.random.random((4, self.numpoints))
xy = data[:2, :]
s, c = data[2:, :]
xy -= 0.5
xy *= 10
while True:
xy += 0.03 * (np.random.random((2, self.numpoints)) - 0.5)
s += 0.05 * (np.random.random(self.numpoints) - 0.5)
c += 0.02 * (np.random.random(self.numpoints) - 0.5)
yield data
def update(self, i):
"""Update the scatter plot."""
data = next(self.stream)
# Set x and y data...
self.scat.set_offsets(data[:2, :])
# Set sizes...
self.scat._sizes = 300 * abs(data[2])**1.5 + 100
# Set colors..
self.scat.set_array(data[3])
# We need to return the updated artist for FuncAnimation to draw..
# Note that it expects a sequence of artists, thus the trailing comma.
return self.scat,
def show(self):
plt.show()
if __name__ == '__main__':
a = AnimatedScatter()
a.show()
简单解释一下程序,我的理解
1. 程序定义了一个动态散点类
然后在主程序中实例化了这个类并调用了类的show()函数
class AnimatedScatter(object):
...
if __name__ == '__main__':
a = AnimatedScatter()
a.show()
2. 下面看看这个类都实现的功能
class AnimatedScatter(object):
def __init__(self, numpoints=50):
def setup_plot(self):
def data_stream(self):
def update(self, i):
def show(self):
上述函数,其实都是为了这句服务的:self.ani = animation.FuncAnimation(self.fig, self.update, interval=5, init_func=self.setup_plot, blit=True)
3. 下面对程序进行注释
import matplotlib.pyplot as plt #引入pyplot绘图函数
import matplotlib.animation as animation #引入动画函数
import numpy as np
class AnimatedScatter(object): #定义类
def __init__(self, numpoints=50): #定义类初始函数 请与 绘图的初始化函数区分开
self.numpoints = numpoints #散点数为50
self.stream = self.data_stream() #调用类的数据流函数,此函数提供了无尽的数据流,给50个散点的X,Y坐标,s是直径,c是颜色这4个值进行赋值。相当于每次迭代提供(4,50)的一个数据块。
self.fig, self.ax = plt.subplots() #设置绘图画布及绘图区域
self.ani = animation.FuncAnimation(self.fig, self.update, interval=5,
init_func=self.setup_plot, blit=True) #进入此句后,程序进入迭代状态,直到退出。此FuncAnimation()函数先调用init_func对画面初始化,然后以5ms一帧的速率用update函数进行迭代。blit是指动态图进行位块输送的优化。
def setup_plot(self): #设置绘画,相当于绘图的初始化函数
x, y, s, c = next(self.stream) #迭代,用stream对x,y,s,c进行一次赋值,注意stream指向data_stream()
self.scat = self.ax.scatter(x, y, c=c, s=s, animated=True) # 利用上述值绘制散点图
self.ax.axis([-10, 10, -10, 10]) #设立X,Y坐标轴的起始与终止点
return self.scat, # 初始化函数返回散点图的句柄
def data_stream(self): #数据流函数,注意此函数在绘图的初始化函数和迭代函数中均被调用
data = np.random.random((4, self.numpoints))#初始化一个(4,50)数组,数组中数为【0,1)的随机数
xy = data[:2, :] #取数组的前2行,为50个点 的XY坐标赋值,注意xy是指向data数组前两行的指针
s, c = data[2:, :] #取数组的后两行,分别为50个点的S和C赋值,同上,S和C指向data数组后两行
xy -= 0.5 #对XY的值做调整
xy *= 10 #对XY的值做调整,以便匹配-10:10的坐标
while True: #进入迭代,每次上个函数setup_pl
xy += 0.03 * (np.random.random((2, self.numpoints)) - 0.5) #迭代直接修改了data的值
s += 0.05 * (np.random.random(self.numpoints) - 0.5)
c += 0.02 * (np.random.random(self.numpoints) - 0.5)
yield data #返回data值,注意data是个(4,50)的数组
def update(self, i): #此函数每次迭代都会被调用,此函数在绘制动态图中已经被定义为迭代函数,此迭代函数的作用是利用data的值,给散点函数的50个点重新赋值,此i有何作用还请大牛指点。
data = next(self.stream) #更新data值
self.scat.set_offsets(data[:2, :]) #设置散点的XY
self.scat._sizes = 300 * abs(data[2])**1.5 + 100#设置散点直径
self.scat.set_array(data[3]) #设置散点颜色
# We need to return the updated artist for FuncAnimation to draw..
# Note that it expects a sequence of artists, thus the trailing comma.
return self.scat, #为何返回散点绘图函数句柄,不明白?是因为动画函数需要么?
def show(self): #开始绘制函数
plt.show()
if __name__ == '__main__': #主函数
a = AnimatedScatter() #定义类,注意定义类会调用类的初始化函数,从而启动整个流程
a.show() # 开始绘制,这步只是将上一步的绘制显示到屏幕上,具体为什么能从上面的迭代过程跳出来开始绘制动画,这个我也不懂啥机制。