Matplotlib的基础入门

一、matplotlib 介绍

Matplotlib是一个Python 2D绘图库,可以生成各种硬拷贝格式和跨平台交互式环境的图形。Matplotlib可用于Python脚本,Python和IPython shell,Jupyter笔记本,Web应用程序服务器等。pyplot模块提供类似MATLAB的接口,特别是与IPython结合使用时。 对于高级用户,你可以通过面向对象的界面或通过MATLAB用户熟悉的一组函数完全控制线型,字体属性,轴属性。

二、实验环境说明

  • python3.6.4
  • IDE:Pycharm 2018(很好用,python的web开发神器)
  • 操作系统:windows10
  • 实验源数据下载

三、注意点

  • 在绘图结构中,figure创建窗口,subplot创建子图。所有的绘画只能在子图上进行。plt表示当前子图,若没有就创建一个子图。所有你会看到一些教程中使用plt进行设置,一些教程使用子图属性进行设置。他们往往存在对应功能函数。

一幅图的结构如下:

Matplotlib的基础入门_第1张图片

  • 在绘图结构中,figure创建窗口,subplot创建子图。所有的绘画只能在子图上进行。axes表示子图对象,Axes对象,这就是你想象中的“一幅图”,它是具有数据空间的图像区域。给定的图形可以包含许多轴,但给定的Axes对象只能在一个图中。plt表示当前子图,若没有就创建一个子图。所有你会看到一些教程中使用plt进行设置,一些教程使用子图属性进行设置。他们往往存在对应功能函数。
  • 所有绘图函数都需要np.array或np.ma.masked_array对象作为输入类型。如果是 “类数组(array-like)” 对象(如pandas数据对象和np.matrix)可能会或可能不会按预期工作。最好在绘图之前将它们转换为np.array对象。
    比如使用Pandas生成的数据,转化为np数组:
a = pandas.DataFrame(np.random.rand(4,5), columns = list('abcde'))
a = a.values

三、一般的python脚本风格(画图模板)

  • 导入支撑库
#导入依赖库
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
'''
'''
  • 画图模板流程
#然后依次调用np.arange,np.zeros,np.pi,plt.figure,plt.plot,plt.show等。使用pyplot接口创建图像,然后使用对象方法
#1、生成画图所需数组数据,数据可以直接导入或者是算法,函数的输出等
x = np.arange(0, 10, 0.2)
y = np.sin(x)

#2、创建窗口,子图对象
fig, ax = plt.subplots()

#3、在创建的对应Axes对象(相当于画布)上面利用一些方法进行作画
ax.plot(x, y)

#4、对图进行修饰,使其变的美观(添加子图,注释,文本,等等)
#x轴标签
ax.set_xlabel('y轴', fontsize=15)
#y轴标签
ax.set_ylabel('x轴', fontsize=15)
#标题
ax.set_title('python可视化')
#添加图例
ax.legend()
#添加网格
ax.grid(True)
#5、脚本显示图片
plt.show()

Matplotlib的基础入门_第2张图片


四、可视化实例

4.1 复现一篇报告中的分析图

原图如下:

Matplotlib的基础入门_第3张图片


复现的脚本如下:

#!/usr/bin/env python 
# -*- coding:utf-8 -*-

#导入依赖库
import xlrd
import numpy as np
import pandas as pd
# print(pd.__version__)
import matplotlib.pyplot as plt


# 这两句代码用来正确显示图中的中文字体,后续都要加上
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号

#利用pandas读入大车的单车源强数据
df = pd.read_excel('C:/Users/13109/desktop/单车源强数据2.xlsx','大车',na_vlues=['NA'])

'''
绘图相关
'''
#数据预处理,使用pandas处理
df = df.iloc[:,2:6]
df = df.dropna(how='any')#删除任何带有空值的行
df['声压级(mean)'] = (df['Soundlevel ']+df['Soundlevel_2'])/2
df['大车平均车速(mean)'] = (df['Rear_speed']+df['Radar_speed '])/2
#将pandas的数据帧转化为np数组
dfnp = df.values
x = dfnp[:,5]
x1 = np.log10(x)
y = dfnp[:,4]
x2 = np.linspace(30,110,898)
y1 = 22+36.32*np.log10(x2)
y2 = y1-5
y3 = y1+5

#窗口,对象的生成
fig = plt.figure()     #开启一个窗口,同时设置大小,分辨率
ax1 = fig.add_subplot(1,2,1)  #通过fig添加子图,参数:行数,列数,第几个。

#绘制第一个子图
# fig, ax1 = plt.subplots()
line1 = ax1.scatter(x, y, label='测试数据',color='#44cef6',s=10)
line2 = ax1.plot(x2,y1,label='规范拟合数据',color='#ffa400',alpha=0.5, linewidth = '5')
line3 = ax1.plot(x2,y2,label='规范拟合数据-5db',color='#00e09e',linestyle='--', linewidth = '5')
line4 = ax1.plot(x2,y3,label='规范拟合数据+5db',color='#493131',linestyle=':', linewidth = '5')
#x轴标签
ax1.set_xlabel('大车车速(km/h)', fontsize=15)
#y轴标签
ax1.set_ylabel('声压级(DB)', fontsize=15)
#标题
ax1.set_title('这是一张大车车速与声压级的关系图')
#添加图例
ax1.legend()
#添加网格
ax1.grid(True)
#在Axes的任意位置添加文本
ax1.text(30,100,'子图',fontsize=14,style='italic',color='red')
#可选箭头在任意位置添加注释 Axes
ax1.annotate(r'$L_(ol)=22+36.32\log(V_l)$', xy=(38, 79), xytext=(45, 73),
            arrowprops=dict(facecolor='black', shrink=0.01))

##添加一个子图,rect=[左, 下, 宽, 高],是使用的绝对布局,不和以存在窗口挤占空间
axes1 = plt.axes([.2, .75, .05,.1], facecolor='y')
#在子图上画图
axes1.plot(x2,y1)

#绘制第二个子图
ax2 = fig.add_subplot(1,2,2)  #通过fig添加子图,参数:行数,列数,第几个。
ax2.scatter(x1, y, label='测试数据',color='#44cef6',s=10)
ax2.plot(np.log10(x2),y1,label='规范拟合数据',color='#ffa400',alpha=0.5, linewidth = '5')
ax2.plot(np.log10(x2),y3,label='规范拟合数据+5db',color='#493131',linestyle=':', linewidth = '5')
#x轴标签
ax2.set_xlabel('大车车速(log(V))', fontsize=15)
#y轴标签
ax2.set_ylabel('声压级(DB)', fontsize=15)
#标题
ax2.set_title('这是一张大车车速与声压级的关系图')
#添加图例
ax2.legend()
#添加网格
ax2.grid(True)
#在Axes的任意位置添加文本
# ax1.text(30,100,'子图',fontsize=14,style='italic',color='red')
#可选箭头在任意位置添加注释 Axes
ax2.annotate(r'$L_(ol)=22+36.32\log(V_l)$', xy=(1.6, 80), xytext=(1.6, 72),
            arrowprops=dict(facecolor='black', shrink=0.01))
##再次添加一个子图,rect=[左, 下, 宽, 高],是使用的绝对布局,不和以存在窗口挤占空间
axes2 = plt.axes([.60, .75, .05,.1], facecolor='y')
#在子图上画图
axes2.plot(np.log10(x2),y1)
plt.show()
plt.close('all')

复现结果打印输出:

Matplotlib的基础入门_第4张图片

4.2 复现曲线拟合并绘制结果

需要复现的曲线拟合如下:

Matplotlib的基础入门_第5张图片

4.2.1 复现思路流程(较为复杂)

step1:首先数据预处理过程中的异常值检测与处理(本文直接删除异常值);

step2:数据分组,并且预处理实现声压级进行能量平均(声压级能量平均算法);

step3: 对预处理之后的样本数据进行一次拟合,并且绘制相关图像;


4.2.2 样本异常值检测与处理

  • 异常值检测(使用箱线图的方法)
    箱线图优点:箱型图并不限制数据分布,只是直观表现出数据分布的本来面貌。其识别异常值的结果比较客观,而且判断标准以四分位数和四分位间距为标准,多达25%的数据可以变得任意远而不会扰动这个标准,鲁棒性更强,所以更受大家亲睐。

箱线图基本原理:异常值被定义为大于QU+1.5IQRQU+1.5IQR或小于QL−1.5IQRQL−1.5IQR的值。QUQU是上四分位数,表示全部观察值中有1/4的数据比他大,QLQL是下四分位数,表示全部数据中有1/4的数据比他小。IQR是四分位间距,是QUQU和QLQL的差,其间包含了观察值的一半。

基本的箱线图:

Matplotlib的基础入门_第6张图片


实现的脚本如下:

#依赖导入
import pandas as pd
import matplotlib.pyplot as plt

# 这两句代码用来正确显示图中的中文字体,后续都要加上
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号

#读入大车的单车源强数据
df = pd.read_excel('C:/Users/13109/desktop/单车源强数据2.xlsx','大车',na_vlues=['NA'])

#数据初始化,使用pandas处理
df = df.iloc[:,2:6]
df = df.dropna(how='any')#删除任何带有空值的行
df['声压级(mean)'] = (df['Soundlevel ']+df['Soundlevel_2'])/2
df['大车平均车速(mean)'] = (df['Rear_speed']+df['Radar_speed '])/2


#实验样本索引查看
df1 = df.iloc[:,4:6]
#实验数据导出
# df1.to_csv('C:/Users/13109/desktop/df1.csv',encoding="gb2312")

#绘制原始的箱线图,并返回异常值字典
p = df1.plot.box(sym='r+',return_type = 'dict')

箱线图绘制结果如下:
Matplotlib的基础入门_第7张图片

!下面的代码和上面的是一个脚本)

  • 异常值删除(删除部分使用了两种方法),处理之后的样本导出
'''
异常值处理的常用方法
删除:对于数据量比较小的数据,删除会造成样本不足,减少有用信息。
视为缺失值:用均值、插值等方法进行填补
不处理:将缺失值视为一种特征,统计其缺失个数等信息作为缺失特征。
'''
#大车平均声压级异常数据的获取
x = p['fliers'][0].get_xdata()
y = p['fliers'][0].get_ydata()
y.sort() #从小到大排序

print(y)
#在箱线图上绘制注释异常值注释
for i in range(len(x)):
  # print(i)
  if y[i]>97:
    plt.annotate(y[i], xy = (x[i],y[i]), xytext=(x[i]+0.05,y[i]))

#这里对声压级样本的异常值数据进行删除
'''
删除异常数据样本的第一种方法,双重循环遍历方法,该方法运行效率较低
(用于删除声压级异常样本)
'''
y = list(set(y))#用于数组排序之后删除重复数据
j=0
for i in range(0,897):
    for k in range(len(y)):
    #     if df1.iloc[:, 0][i] >= 96.8 or df1.iloc[:,0][i] <= 76.55:
        if y[k] == df1.loc[i,['声压级(mean)']].values[0]:
            j += 1
            df1.drop(index=i,inplace=True)
            break
print('声压级标签异常值一共删除了'+str(j)+'行异常值数据')

'''
删除异常数据样本的第二种方法,利用直接选择索引法,简单实用,pandas还要好好学
'''
def delete_v(y,df1):
    j1 = 0
    for k in range(len(y)):
        j1 += 1
        df1.drop(index=df1[df1.iloc[:,1].isin([y[k]])].index[0], inplace = True)
    return df1,j1

y1 = p['fliers'][1].get_ydata()
y1.sort()  # 从小到大排序
print(y1)
df1,j1 = delete_v(y1,df1)
print('大车平均车速标签异常值一共删除了'+str(j1)+'行异常值数据')


#重建索引,并重新绘制删除异常样本之后的箱线图
df1.index=list(range(len(df1)))
df1.plot.box(sym='r+',return_type = 'dict')
print(df1)

#剔除异常值之后的样本文件导出
# df1.to_excel('C:/Users/13109/desktop/df1.xlsx',encoding="gb2312")

plt.show()

打印输出结果:

[71.9  74.6  74.9  75.   75.25 76.05 76.45 76.55 76.55 97.   97.15 99.25
 99.25]
声压级标签异常值一共删除了13行异常值数据
[ 30.    31.65  32.65  33.95  34.25  34.5   91.    91.    92.05  92.55
  93.    93.5   94.5   95.75  96.    97.    97.    99.75  99.75 105.
 108.  ]
大车平均车速标签异常值一共删除了21行异常值数据
     声压级(mean)  大车平均车速(mean)
0        91.50         77.35
1        95.05         67.85
2        92.80         65.80
3        88.20         63.80
4        84.15         49.00
..         ...           ...
859      91.55         67.00
860      81.95         64.00
861      86.60         65.00
862      81.00         67.00
863      86.50         55.00

[864 rows x 2 columns]


异常值删除之后的箱线图绘制结果如下:

Matplotlib的基础入门_第8张图片


4.2.3 样本预处理值数据分组聚合(并拟合画图)

  • 样本预处理值数据分组的原理

Matplotlib的基础入门_第9张图片


  • 具体实现

实现的脚本如下:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import math


# 这两句代码用来正确显示图中的中文字体,后续都要加上
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号

#读入剔除异常值之后的数据
df1 = pd.read_excel('C:/Users/13109/desktop/df1.xlsx','Sheet1',na_vlues=['NA'])

'''
数据预处理,从而得到拟合样本
使得测试数据更加具有代表性,将车速以0.1km/h为间隔进行分区,
在该区域内的车速进行算术平均得到 ,并将该区域内对应的声压级进行能量平均 
'''
quartiles = pd.cut(df1['大车平均车速(mean)'],250)#数据分组,使用pandas.cut实现分位数分组
# print(quartiles[:])
df2 = df1.groupby(quartiles)
df11 = df2['大车平均车速(mean)'].mean()
df3 = df2['声压级(mean)']

def top(df):
    mean=0
    for i in range(len(df)):
        mean=10**(0.1*df.values[i])+mean
    if len(df) == 0:
        return 0
    else:
        x = mean/(len(df))
        y = 10*(math.log(x,10))
        return y

df12=df3.apply(top)#使用apply方法,使用自定义top函数来对分组数据系列进行聚合

#把两个series变量重新组合成数据帧dataframe格式变量
df = pd.DataFrame({
     '大车平均车速(mean)': df11,
                      '声压级(mean)': df12})
df = df.dropna(how='any')
df.index = range(len(df))

#删除车速小于55,但是声压级大于90的异常值(人为删除)
# df = df.drop(index=df[df['大车平均车速(mean)'] > 50].index[0], inplace = True)
# df.drop(index=df[df.iloc[50:len(df),1]>90].index, inplace=True)
df.drop(index=df[(df['大车平均车速(mean)']<55) & (df['声压级(mean)']>90)].index, inplace = True)

## 数据预处理完毕,进而获取能量平均拟合数据等进行绘制图像
x = df.values[:,0]
y = df.values[:,1]
x2 = np.linspace(40,95,190)
y1 = 22+36.32*np.log10(x2)
x0 = np.log10(x)

#对数据进行一次多项式拟合
z1 = np.polyfit(x0, y, 1)#用一次多项式拟合
p1 = np.poly1d(z1)
print(p1) #在屏幕上打印拟合多项式
yvals=p1(x0)#也可以使用yvals=np.polyval(z1,x)


#绘制图形
fig = plt.figure()     #开启一个窗口,同时设置大小,分辨率
ax1 = fig.add_subplot(1,1,1)  #通过fig添加子图,参数:行数,列数,第几个。

# fig, ax1 = plt.subplots()
line1 = ax1.scatter(x, y, label='能量平均数据',color='#44cef6',s=10)
line2 = ax1.plot(x2,y1,label='规范拟合曲线',color='#ffa400',alpha=0.5, linewidth = '3')
line3=ax1.plot(x, yvals, color='#493131',label='能量平均数据拟合曲线',linewidth = '3')
#x轴标签
ax1.set_xlabel('大车车速(km/h)', fontsize=15)
#y轴标签
ax1.set_ylabel('声压级(DB)', fontsize=15)
#标题
ax1.set_title('大型车能量平均拟合曲线与规范对比')
#添加图例
ax1.legend()
#添加网格
# ax1.grid(True)
#在Axes的任意位置添加文本
ax1.text(30,100,'子图',fontsize=14,style='italic',color='red')
#可选箭头在任意位置添加注释 Axes
ax1.annotate(r'$L_(ol)=71.43+8.806\log(V_l)$', xy=(80, 88), xytext=(71, 82),
            arrowprops=dict(facecolor='black', shrink=0.01))

ax1.annotate(r'$L_(ol)=22+36.32\log(V_l)$', xy=(46.1, 82.4), xytext=(53, 79),
            arrowprops=dict(facecolor='black', shrink=0.01))

plt.show()

最终实现的复现能量平均拟合曲线结果如下:
Matplotlib的基础入门_第10张图片


五、参考文章内容链接

  • python数据可视化系列教程——matplotlib绘图全解
  • Matplotlib 中文文档
  • Matplotlib 官方文档
  • python用箱型图进行异常值检测
  • pandas数据分组和聚合篇
  • pandas库的基础入门
  • python 多项式拟合
  • Pandas: Drop函数(Dataframe删除指定行列

你可能感兴趣的:(python数据分析相关,可视化,python,数据分析)