matplotlib包下下的animation模块的FuncAnimation方法可以称的上matplotlib功能最强大的方法之一了,使用它可以创建很多丰富美丽的数据图像,而且可以随着时间变动而变动。
比如可以进行硬件的仿真等等。
核心要导入: from matplotlib.animation import FuncAnimation
它的特点就是可以用一个给定的时间间隔不断的重复执行某个绘制函数, 从而实现动态数据的绘制。


可以看到颜色在不停的变化, 如果数据集动态改变, 那么尺寸也会动态改变(因为从新的axes上进行绘制了),这样达不到我们要的效果。
其根本原因就是,当前绘制图形的实例: axes对象没有重置, 那么在绘制新的图象时, 它的各种参数都会采用系统默认的参数进行变动,比如:最初颜色是蓝色, 当第二次绘制时,蓝色在当前axes实例下已经绘制过了,系统则会绘制上不同的颜色(有规律)。
知道根本原因后我们可以这样更改:
每次重新绘制的时候,先清除当前axes对象(绘图对象),让它重置,然后再用新的数据集绘制,这样每次绘制出来的数据从颜色上来说每次都是蓝色了,从其他属性来说也是一样的, 这样看上去效果会很棒。
动态生成数据:

生成数据源码:
import csv
import random
import time
# 3个属性下的初始值
x_value = 0
total_1 = 1000
total_2 = 1000
# 生成的csv数据的头部标签
fieldnames = ["x_value", "total_1", "total_2"]
# 写入文件头部标签, 因文件打开方式是w, 故而会覆盖掉前面的内容从头开始写
with open('data_6.csv', 'w') as csv_file:
# 以字典的方式写入文件
csv_writer = csv.DictWriter(csv_file, fieldnames=fieldnames)
# 写入头部信息: x_vale, total_1, total_2的标签信息
csv_writer.writeheader()
# 永真循环, 程序每隔一秒(time.sleep(1))就写入一次数据
while True:
with open('data_6.csv', 'a') as csv_file:
csv_writer = csv.DictWriter(csv_file, fieldnames=fieldnames)
# 因为创建的是DictWriter(以字典的方式写入文件), 因此创建的数据也是字典格式的, 键是列的标签, 值是对应标签上的数据
info = {
"x_value": x_value,
"total_1": total_1,
"total_2": total_2
}
# 写入一行信息
csv_writer.writerow(info)
# 打印刚刚写入的信息
print(x_value, total_1, total_2)
# 时间往后移一天
x_value += 1
# 两个value值随机变动
total_1 = total_1 + random.randint(-6, 8)
total_2 = total_2 + random.randint(-5, 6)
# 程序等待1秒钟
time.sleep(1)
动态展示数据:



展示数据源码:
# coding=utf-8
import random
from itertools import count
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
plt.style.use('fivethirtyeight')
# 利用itertools里的count创建一个迭代器对象,默认从0开始计数, 是一个"无限大"的等差数列
index = count()
x_vals = []
y_vals = []
def animate(i):
# i表示的是经历过的"时间", 即每调用一次animate函数, i的值会自动加一
# 我们从一个动态生成数据的csv文件中获取数据来模拟动态数据
data = pd.read_csv('data_6.csv')
# 获得该动态数据的所有列的所有数据(当前生成的), 到下一次运行时该数据如果变动了, 绘出来的图形自然也变动了
x = data['x_value']
y1 = data['total_1']
y2 = data['total_2']
# plt对象的cla方法: clear axes: 清除当前轴线(前面说过axes对象表示的是plt整个figure对象下面的一个绘图对象, 一个figure可以有多个axes, 其实就是当前正在绘图的实例).
# 我们可以不清除当前的axes而沿用前面的axes, 但这样会产生每次绘出来的图形都有很大的变化(原因是重新绘制的时候,颜色,坐标等都重新绘制,可能不在同一个地方了,所以看上去会时刻变化).
# 因此必须要清除当前axes对象,来重新绘制.
plt.cla()
plt.plot(x, y1, label='Channel 1')
plt.plot(x, y2, label='Channel 2')
plt.legend(loc='upper left')
plt.tight_layout()
# FuncAnimation可以根据给定的interval(时间间隔, ms为单位)一直重复调用某个函数来进行绘制, 从而模拟出实时数据的效果.
ani = FuncAnimation(plt.gcf(), animate, interval=1000)
plt.show()
再介绍一个不需要每次都重置axes轴来绘制的方法(效果是一样的,只是稍微复杂点):

在上面这个图里面,每个line对象代表了”图中的一根线“。然后根据它们动态调整数据,源码稍微有点复杂,但最终获得的效果和前面的例子是一样的。
源码:
# coding=utf-8
# Another way to do it without clearing the Axis
from itertools import count
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
plt.style.use('fivethirtyeight')
x_vals = []
y_vals = []
plt.plot([], [], label='Channel 1')
plt.plot([], [], label='Channel 2')
def animate(i):
data = pd.read_csv('data_6.csv')
x = data['x_value']
y1 = data['total_1']
y2 = data['total_2']
# plt对象的get current axex方法, 返回当前绘制对象的axes轴(也相当于一个plt,它有plt对象几乎所有方法,可以直接像plt对象一样使用它)
ax = plt.gca()
# 获得当前绘制的两条曲线对象
line1, line2 = ax.lines
# 分别给两条曲线设置其对应的数据(动态刷新)
line1.set_data(x, y1)
line2.set_data(x, y2)
# 分别求出两条曲线在x,y方向上的最小值和最大值
xlim_low, xlim_high = ax.get_xlim()
ylim_low, ylim_high = ax.get_ylim()
# 重新设置当前最小的x和最大的x(沿着横轴最左端和最右端的数据)--> 横轴最左端(起点)不动,而将横轴最右端的数据增加5也就是实现动态向后移动
ax.set_xlim(xlim_low, (x.max() + 5))
# 获得动态生成数据集数据的当前最大值
y1max = y1.max()
y2max = y2.max()
# 用一个临时变量保存动态生成数据集两列下所有数据的最大值
current_ymax = y1max if (y1max > y2max) else y2max
# 获得动态生成数据集数据的当前最小值
y1min = y1.min()
y2min = y2.min()
# 用一个临时变量保存动态生成数据集两列下所有数据的最小值
current_ymin = y1min if (y1min < y2min) else y2min
# 重新设置当前最小的y和最大的y(沿着竖轴最下端和最上端的数据)--> 分别将竖轴最下端的数据和最上端的数据设置成动态数据集中当前最大的数据+5和最小的数据-5(有点难理解....)
ax.set_ylim((current_ymin - 5), (current_ymax + 5))
# FuncAnimation方法可以在间隔interval时间(ms)后重复运行某个函数(该函数必须要有一个参数,表示的是当前运行该函数第几次了)
ani = FuncAnimation(plt.gcf(), animate, interval=1000)
plt.legend()
plt.tight_layout()
plt.show()
网友评论