Matplotlib 数据可视化
1.数据保存
2,画布figure
3,划分布局
4,绘图
5,显示
6,增加元素
step1:
import threading
from turtle import filling
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import matplotlib.lines as line
import numpy as np
#导入seaborn库用于让matplotlib有更好的绘制体验,seaborn库会更改底层matplotlib库设置
import seaborn as sns
x = np.arange(10)#10为终点,起点取默认值0,步长取默认值1,等比数列。type=ndarray
y = 2 * x + np.random.randint(0, 20)#偏移一个随机数
fig=plt.figure()#生成一个画布,参数默认
ax=plt.subplot(221) #画布划分成2行2列 首先在第一个区域作画
ax.plot(x, y)# plot x and y using default line style and color#plot函数可以传入list类型数据也可以传入array类型数据
ax=plt.subplot(222)
ax.plot(x, y, 'bo')# plot x and y using blue circle markers#颜色和形状可以做一个组合
ax=plt.subplot(223)
ax.plot(y) # plot y using x as index array 0..N-1#输入一个数据时 默认就是y,x步长默认为1
ax=plt.subplot(224)
ax.plot(y, 'r+-.') # ditto, but with red plusses
plt.show() # 显示图像(0,1,CHUNK)
step2:
1.我们可以用画布的plot的方法直接画线,
2.也可以用画布的add_line的方法添加一个Line2D的实例,
在画布上添加一条线2dline的方法
import threading
from turtle import shape
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import matplotlib.lines as line
import numpy as np
CHUNK = 2048 # 初始数据量
data=np.random.normal(0,1,CHUNK) # 存放数据,用于绘制图像,数据类型可为列表
#从正态分布(高斯分布)中抽取随机样本,返回一个size大小的数组 0为均值 1为标准差
print(type(data),data.shape,data)
# 定义画布
fig = plt.figure()
ax1 = plt.subplot(121,xlim=(0,2048),ylim=(-5,5))
ax2 = plt.subplot(122,xlim=(0,1),ylim=(0,5))
ax1.plot( data)
line = line.Line2D([0.1,0.2], [1,2]) # 绘制直线
ax2.add_line(line)
plt.show() # 显示图像(0,1,CHUNK)
step3:常用属性的设置
plot()方法的返回值就是一个Line2D的对象集合和某一条直线实例.
可以在plot函数里直接修改属性
可以在获取线实例对象用set属性更改
可以用plt.step()方法
import threading
from turtle import shape
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import matplotlib.lines as line
import numpy as np
# 定义画布
#figure(num=None, figsize=None, dpi=None, facecolor=None, edgecolor=None, frameon=True)
fig = plt.figure("电流采样",figsize=(10,5),facecolor='g')
CHUNK = 2048 # 初始数据量
data=np.random.normal(0,1,CHUNK) # 存放数据,用于绘制图像,数据类型可为列表
#从正态分布(高斯分布)中抽取随机样本,返回一个size大小的数组 0为均值 1为标准差
ax1 = plt.subplot(221,xlim=(0,2048),ylim=(-5,5))
ax1.plot( data)
#子图2 subplot
line = line.Line2D([0,0.2,0.4,0.6,0.8,1], [0,1,2,5,3,2]) # 绘制直线
ax2 = plt.subplot(222,xlim=(0,1),ylim=(0,5))
ax2.add_line(line)
x=np.linspace(-np.pi,np.pi,256,endpoint=True)
c,s=np.cos(x),np.sin(x)#第一根线
ax3 = plt.subplot(223,xlim=(-np.pi,np.pi),ylim=(-2,2))
ax3.plot(x,c,linewidth=4.0,color='r')
line2 =ax3.plot(x,s)#第二根线
plt.setp(line2,linewidth=3.0,color='g',ls='-.')
line3=ax3.plot(x,s+0.5)#第三根线
line3[0].set_color('b')
line3[0].set_linestyle('dashdot')
line4=ax3.plot(x,s-0.5)#第四根线
line4[0].set_linestyle(':')
line4[0].set_color('y')
line5,=ax3.plot(x,s-1)#第四根线
line5.set_linestyle('--')
line5.set_color('#000000')
Y1 = np.random.randn(5)
Y2 = np.random.randn(5)
ax4 = plt.subplot(224)
line1 = ax4.plot( Y1, marker='o', markersize=7, markerfacecolor='#FF0000', markerfacecoloralt='#00FF00', fillstyle='full', label='fillstyle=full')
line1 = ax4.plot( Y2, marker='o', markersize=7, markerfacecolor='#FF0000', markerfacecoloralt='#00FF00', fillstyle='left', label='fillstyle=left',drawstyle='steps-mid')
ax4.set_title('full', fontsize=10)
ax4.legend()#还没搞明白
plt.show() # 显示图像(0,1,CHUNK)
step4:动态图
plt.plot()函数的返回值是一个存放Line2D实例的列表!!!,而不是实例本身!
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig, ax = plt.subplots()
#初始化画图和数据
x = np.arange(0, 2*np.pi, 0.01)
line, = ax.plot(x, np.sin(x))
#更新函数
def animate(i):
line.set_ydata(np.sin(x + i / 50)) # update the data.
print(i)
if i==5 :
plt.close(fig)
return line,
#开始动画
ani = animation.FuncAnimation(
fig, animate, interval=1000, blit=True, save_count=50)
ani.save('sin_test1.gif', writer='imagemagick', fps=100)
plt.show()
step5:做一波数据更新的图示
from tkinter import N
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import matplotlib.lines as line
import numpy as np
import time
import threading
CHUNK = 2048 # 初始数据量
dataList=[]
dataX=[]
data=np.random.normal(0,1,CHUNK) # 存放数据,用于绘制图像,数据类型可为列表
print(type(data))
# 定义画布
fig = plt.figure(1)
ax = plt.subplot(221,ylim=(0,10))
ax.set_xlim(0,100)
ax.set_title("title",fontsize=8) # 设置title
plt.suptitle('Suptitle',fontsize=8)
line = line.Line2D([], []) # 绘制直线
# 初始化图像
def plot_init():
ax.add_line(line)
return line, # 必须加逗号,否则会报错(TypeError: 'Line2D' object is not iterable)
# 更新图像(animation会不断调用此函数刷新图像,实现动态图的效果)
def plot_update(i):
global dataList
global dataX
global n
line.set_xdata(dataX) # 更新直线的数据
line.set_ydata(dataList) # 更新直线的数据
# 大标题(若有多个子图,可为其设置大标题)
if n>=100:
#ani.save('sin_test1.gif', writer='imagemagick', fps=100)
plt.close(fig)
# 重新渲染子图
#ax.figure.canvas.draw() # 必须加入这一行代码,才能更新title和坐标!!!
return line, # 必须加逗号,否则会报错(TypeError: 'Line2D' object is not iterable)
# 绘制动态图
ani = animation.FuncAnimation(fig, # 画布
plot_update, # 图像更新
init_func=plot_init, # 图像初始化
frames=1,
interval=30, # 图像更新间隔
blit=True)
# 数据更新函数
def dataUpdate_thead():
global dataList
global dataX
global n
# 为了方便理解代码,这里生成正态分布的随机数据
while True: # 为了方便测试,让数据不停的更新time.sleep(1)
data=np.random.normal(0,1,CHUNK)
time.sleep(0.1)
data1=np.random.randint(0,9)
dataList.append(data1)
n=n+1
dataX.append(n)
print(dataList)
print(dataX)
if n==100:
break
# 为数据更新函数单独创建一个线程,与图像绘制的线程并发执行
ad_rdy_ev = threading.Event()
ad_rdy_ev.set() # 设置线程运行
t = threading.Thread(target=dataUpdate_thead, args=()) # 更新数据,参数说明:target是线程需要执行的函数,args是传递给函数的参数)
t.daemon = True
t.start() # 线程执行
plt.show() # 显示图像(0,1,CHUNK)
setp6: 加入串口数据
串口每发一次数据来,就更新一波图形
from tkinter import N
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import matplotlib.lines as line
import numpy as np
import time
import threading
import serial #导入模块
import serial.tools.list_ports
CHUNK = 2048 # 初始数据量
dataList=[]
dataX=[]
POWER_DATA=[]
TIME_DATA=[]
data=np.random.normal(0,1,CHUNK) # 存放数据,用于绘制图像,数据类型可为列表
print(type(data))
# 定义画布
fig = plt.figure(1)
ax = plt.subplot(221,ylim=(0,10))
ax.set_xlim(0,100)
ax.set_title("title",fontsize=8) # 设置title
plt.suptitle('Suptitle',fontsize=8)
line = line.Line2D([], []) # 绘制直线
# 初始化图像
def plot_init():
ax.add_line(line)
return line, # 必须加逗号,否则会报错(TypeError: 'Line2D' object is not iterable)
# 更新图像(animation会不断调用此函数刷新图像,实现动态图的效果)
def plot_update(i):
global dataList
global dataX
global n
#line.set_xdata(dataX) # 更新直线的数据
#line.set_ydata(dataList) # 更新直线的数据
line.set_xdata(TIME_DATA) # 更新直线的数据
line.set_ydata(POWER_DATA) # 更新直线的数据
# 大标题(若有多个子图,可为其设置大标题)
if n>=100:
#ani.save('sin_test1.gif', writer='imagemagick', fps=100)
#plt.close(fig)
n=100
# 重新渲染子图
#ax.figure.canvas.draw() # 必须加入这一行代码,才能更新title和坐标!!!
return line, # 必须加逗号,否则会报错(TypeError: 'Line2D' object is not iterable)
# 绘制动态图
ani = animation.FuncAnimation(fig, # 画布
plot_update, # 图像更新
init_func=plot_init, # 图像初始化
frames=100,
interval=30, # 图像更新间隔
blit=True)
# 数据更新函数
def dataUpdate_thead():
global dataList
global dataX
global n
# 为了方便理解代码,这里生成正态分布的随机数据
while True: # 为了方便测试,让数据不停的更新time.sleep(1)
data=np.random.normal(0,1,CHUNK)
time.sleep(1)
data1=np.random.randint(0,9)
dataList.append(data1)
n=n+1
dataX.append(n)
#print(dataList)
#print(dataX)
if n==100:
break
def recive_data(a):
s=True
#超时设置,None:永远等待操作,0为立即返回请求结果,其他值为等待超时时间(单位为秒)
timex=1
# 打开串口,并得到串口对象
ser=serial.Serial("COM2",115200,timeout=timex)
print("串口已经启动\r\n")
while s:
global TIME_DATA
data1=ser.readline().decode("gbk")
if data1 !='':#每收到一个数据 开始处理
#读一个字节//read.hex()
TIME_DATA.append(float(n1))
n1+=1
text="数据"+str(n1)+"已经收到\r\n"
result=ser.write(text.encode("gbk"))
print("写总字节数:",result)
data1=data1.rstrip('\r\n')
data=data1.split(",")
print(data,type(data))
POWER_DATA.append(float(data[0]))
print(POWER_DATA,type(POWER_DATA),TIME_DATA,type(TIME_DATA))
if n1==10:
time.sleep(0.1)
ser.close()#关闭串口
print("串口已经关闭]\r\n")
# 为数据更新函数单独创建一个线程,与图像绘制的线程并发执行
ad_rdy_ev = threading.Event()
ad_rdy_ev.set() # 设置线程运行
t = threading.Thread(target=dataUpdate_thead, args=()) # 更新数据,参数说明:target是线程需要执行的函数,args是传递给函数的参数)
t2=threading.Thread(target=recive_data, args=("t2",))
t.daemon = True