Python Matplotlib绘制多子图准备训练数据和GIF动画实践

我们程序员、设计人员,按需求辛辛苦苦开发出来的统计图形,往往达不到用户的要求,原因一般是表达不全面,也有内容过多而比较乱,真是众口难调。

其实,是我们表达方式与业务人员工作脱节。业务人员看了一张图或及临近几张图就知道是什么了。例如采油工程中的示功图(见《使用Matplotlib图像化分析数据构建训练集的方法及实践》),我稍加学习,简单的一眼就能识别工况状态。

同样道理,如下图所示的每日油罐液位变化情况,如果拿出单张图来看,就能看出油罐是出油还是进油,但是,看数据时,识别是静止还是震动或气温影响的波动往往很困难。我们会认为已经做的很好了。

如果换位思考,把图给AI进行智能识别呢。
Python Matplotlib绘制多子图准备训练数据和GIF动画实践_第1张图片
这就意味着,我们设计开发时,再向前迈一步——人工智能如何识别,我上次做的就不到位(见《TensorFlow CNN卷积神经网络实现工况图分类识别(一)》),我当时训练数据集是单张图。

现如今,如果把多张图拼成一张图并标注出当前图块,或者,使用时序模型,那么效果将会更好。这是因为,我在做油罐液位数据分析时,看连续一个月的单日集成图,不懂业务的我都看出其运行周期及效率(进出斜率/余弦对比)情况。

以此,再更上一层楼,回归用户界面,为了更好的表达细节,可否转变为动画呢。我已经转化为动画,如何分析再学习。

本文先落实两个技术,一是绘制多子图拼成大图,二是绘制动画gif(MP4也可以)。

1. 绘制多子图

基于matplotlib库,通过plt.subplots(nrows=6, ncols=5)定义子图,返回一个包含figure和axes对象的元组,详解见代码(使用数组循环比较简洁)。

'''
Created on 2020年8月16日

@author: xiaoyw
'''
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.pyplot import MultipleLocator
#从pyplot导入MultipleLocator类,这个类用于设置刻度间隔
from matplotlib import animation

def get_DataFromExcel(file_name):
    
    df = pd.read_excel(file_name)

    return df

def feature_datatime(dat):
    dat['MearsureTime'] = dat['MearsureTime'].astype('datetime64')
    df_dt = pd.DataFrame(columns=('Year','Month','Day','Hour','Minute'))
 
    df_dt['Hour'] = dat['MearsureTime'].dt.hour
    df_dt['Year'] = dat['MearsureTime'].dt.year
    df_dt['Month'] = dat['MearsureTime'].dt.month
    df_dt['Day'] = dat['MearsureTime'].dt.day
    df_dt['Minute'] = dat['MearsureTime'].dt.minute
    
    return df_dt

def draw_OilCanLevel(df):
    df0 = df[(df['OilCanID']==2) & (df['Year']==2020) & (df['Month']==6)].reset_index(drop=True)
    df0 = df0.sort_values(by = ['Day','Hour','Minute'])
    count = df0.shape[0]
   
    y = []
    x = []
    for i in range(1,31):
        df_tmp = df0[df0['Day']==i]
        if df_tmp.shape[0]>0:
            x0 = ((df_tmp['Hour']*60+df_tmp['Minute'])/10).tolist()
            y0 = df_tmp['LiquidLevel'].values/100
            x.append(x0)
            y.append(y0)
    
    fig1, ax1 = plt.subplots(nrows=6, ncols=5)
    for i in range(6):               
        for j in range(5):           
            ax1[i, j].plot(x[i*5+j],y[i*5+j])
            ax1[i, j].set_xlim(0,150)
            ax1[i, j].set_ylim(0,13500/100)
            
            x_major_locator=MultipleLocator(20)
            #把x轴的刻度间隔设置为10,并存在变量里
            y_major_locator=MultipleLocator(2000/100)
            #把y轴的刻度间隔设置为20,并存在变量里
            
            ax1[i, j].xaxis.set_major_locator(x_major_locator)
            #把x轴的主刻度设置为1的倍数
            ax1[i, j].yaxis.set_major_locator(y_major_locator)
            #把y轴的主刻度设置为10的倍数
            ax1[i, j].set_ylabel('Level')
            ax1[i, j].set_xlabel('Time')
                        
    plt.show()

df0 = get_DataFromExcel('e:/drawCandata.xlsx') #('e:/drawCandata.xlsx') #('e:/CandataClean.xlsx')

df0 = pd.concat([df0,feature_datatime(df0)],axis=1)
draw_OilCanLevel(df0)
animation_gif(df0)

2. 绘制GIF动画

如果要让 matplotlib 实现动画功能的话,那么就要引入 animation 模块。

#实现每天按10分钟间隔画曲线
def animation_gif(df):
    df0 = df[(df['OilCanID']==2) & (df['Year']==2020) & (df['Month']==6)].reset_index(drop=True)
    df0 = df0.sort_values(by = ['Day','Hour','Minute'])
    count = df0.shape[0]
    
    y = []
    x = []

    for i in range(1,31):
        df_tmp = df0[df0['Day']==i]
        #取一天的数据长度
        row = df_tmp.shape[0]
        if row > 0:
            for j in range(1,int(row/10)+1):
                k = j * 10
                if k > row: #一天24*6采集次数
                    k = row + 1
                df_tmp0 = df_tmp[0:k]
                print('Row is {0}'.format(df_tmp0.shape[0]))
                x0 = ((df_tmp0['Hour']*60+df_tmp0['Minute'])/10).tolist()
                y0 = df_tmp0['LiquidLevel'].values/100
                x.append(x0)
                y.append(y0)
    #显示数据行数,也就是动画的帧数
    frame = len(x)

    fig, ax = plt.subplots()
    ax.set_xlim(0,150)
    ax.set_ylim(0,13500/100)
    x_major_locator=MultipleLocator(20)
    #把x轴的刻度间隔设置为10,并存在变量里
    y_major_locator=MultipleLocator(2000/100)
    #把y轴的刻度间隔设置为20,并存在变量里
    
    ax.xaxis.set_major_locator(x_major_locator)
    #把x轴的主刻度设置为1的倍数
    ax.yaxis.set_major_locator(y_major_locator)    
    
    ax.set_ylabel('Level')
    ax.set_xlabel('Time')    
    
    ln, = ax.plot([], [], 'r-', animated=False)  #第三个参数表示画曲线的颜色和线型 

    def update(i):
        label = 'timestep {0}'.format(i)
        print(label)
        #ax.cla() 
        # 更新线和坐标轴标签
        ln.set_data(x[i],y[i])
        
        # 返回要重绘的对象
        return ln, 
    #frames为动画帧数
    ani = animation.FuncAnimation(fig, update, frames=frame,interval=1000, blit=True)
    ani.save('e:/animation.gif', fps=10, dpi=80, writer='imagemagick')    
    plt.show()

需要注意到的是,如果要保存 gif 图像,这要求开发者电脑已经安装了 ImageMagicK。

参考:
[1]《matplotlib.pyplot.subplots》
[2]《如何通过 Matplotlib 绘制动画及保存 GIF 图片?》 CSDN博客, frank909, 2018.12
[3]《使用Python科学计算包搭建CNN算法实践(1)》 CSDN博客,肖永威 ,2018.05

你可能感兴趣的:(人工智能及Python)