在Python中使用Matplotlib绘制常见图表

Matplotlib 是一个非常强大的 Python 画图工具,通过绘制线图、散点图、等高线图、条形图、柱状图、3D 图形、甚至是图形动画等,可以更加直观的呈现科学计算等遇到的大量数据。

1、基本元素

在matplotlib的层级结构中,最高层是由matplotlib.pyplot模块提供的“状态机环境”(state-machine environment),通过它来为当前维度绘制图像元素,例如曲线、文本、图片等。接下来一层是第一级的面向对象接口,在这一层中用户可以使用pyplot创建并追踪图像对象,并由此创建一个或多个数据轴系,这些轴系在之后用于图的绘制。

如下所示为图像的各个元素:

Figure指的是整张图片对象,用于包含一个或多个数据轴系(Axes),如果没Axes,则图像为空。

fig = plt.figure()  # 创建一个图像对象
fig.suptitle('No axes on this figure')  # 添加一个标题

fig, ax_lst = plt.subplots(2, 2)  # 创建包含2×2个子图的图像

Aexs是轴(Axis)的复数,翻译为轴系、坐标系,可以将其理解为整个图像(Figure)的一个子图,一个图形可以包含多个子图,我们在子图中进行具体图表的绘制。通过plt.plot()函数可以创建子图对象,通过set_title()可以设置子图的标题,set_xlabel()、set_ylabel()对图的横纵坐标的标签进行设置。

Axis指具体的坐标轴,其中trick代表坐标轴的刻度,通过Location对象控制刻度的位置,Formatter格式化刻度显示的字符串,通过这两个对象可以精确地控制刻度的显示。

Artist对象:在图像中任何元素都可以看作Artist,包括2D线条(Line)、文本、以及Axis和图像Figure,当图片被渲染时,这些对象被绘制到图片中。大多数Artist对象绑定于一个具体轴Axis,这样的对象不可以在轴系之间共享。

matplot的输入数据最好转化为np.array类型,使用其他的数据类型例如np.matrix、pandas等可能会报错,因此在传入参数前先将其他类型通过numpy转换一下。

matplotlib建议的引入必要库与编码方式如下,绘图时首先通过plt接口创建Figure对象与子图对象ax,之后通过ax调用函数绘图,通过定义函数来进行图像绘制可以避免许多重复操作,而且便于代码维护。例如下面定义了my_plotter()完成图像绘制,传入子图ax,两个数据data1,data2,以及图像绘制参数param_dic。

import matplotlib.pyplot as plt    # 引入必要的库
import numpy as np
%matplotlib inline     

# 定义函数进行图像绘制操作
def my_plotter(ax,data1,data2,param_dic):
    ax.plot(x, y,**param_dic)

x = np.arange(0, 10, 0.2)    # 准备数据
y = np.sin(x)

fig, ax = plt.subplots(1)    # 创建子图
my_plotter(ax,x, y,{ 'linestyle':'dashed','label':'sinx'})  # 调用函数绘制图像

2、基本用法

创建图像并绘制函数

首先需要导入必须的函数库matplotlib.pyplot与numpy。如果使用jupyternotebook则需要添加%matplotlib inline设置以显示图片

通过plt.figure()创建一个图像,其中num属性指出显示图像的窗口,figsize属性可以指定图像的大小

通过plt.plot()进行曲线的绘制,前两个数组参数为图像x、y的坐标值。之后的可选参数对可以对线条的颜色(color)、宽度(linewidth)、样式(linestyle)、不透明度(alpha)进行设置

plt.scatter()绘制单独的一个点,而不是连起来的曲线,同样前两个参数为数组,对应点的x、y坐标。属性s设置点的大小,color设置颜色

最后通过plt.show()输出图像

import numpy as np
import matplotlib.pyplot as plt
# 设置行内显示
%matplotlib inline      

x = np.linspace(-5, 5, 50)        # 在-5~5内均匀取50个数
y1 = 2*x + 1                      # 定义一个线性函数
y2 = x**2                         # 定义一个二次函数

plt.figure(num=3, figsize=(10, 5))                              # 创建一个图形对象
plt.plot(x, y2, alpha=0.5)                                      # 绘制曲线
plt.plot(x, y1, color='red', linewidth=1.0, linestyle='--')     
plt.scatter([1],[1],s=200,color='orange')                       # 绘制一个点
plt.show()                                                      # 显示图像  

调整坐标轴

通过plt.xlim可以调整x坐标轴的范围,plt.xlabel设置坐标轴的名字,同理plt.ylim与ylabel对y轴进行设置。matlab中无法使用中文,需要对字符集进行设置。

plt.xticks()可以自定义坐标刻度,将刻度以数组的形式传入,并且可以传入自定义显示的刻度值

设置坐标轴刻度的位置:通过axes对象.xaxis获取到x轴,并通过set_ticks_position()方法来设置位置,可选位置有:top,bottom ,both,default,none,对应的y轴刻度有:left,right,both,default,none

# 设置行内显示
%matplotlib inline  
plt.rcParams['font.sans-serif'] = ['SimHei']    # 设置字符集显示中文
plt.rcParams['axes.unicode_minus'] = False      # 设置负号正确显示

x = np.linspace(-5, 5, 50)        
y1 = 2*x + 1    
y2 = x**2   

plt.figure(num=3, figsize=(10, 5))   
plt.plot(x, y2)     
plt.plot(x, y1, color='red', linewidth=1.0, linestyle='--')
plt.xlabel('x轴')                                           # 设置显示x轴标签
plt.xlim(-2,2)                                              # 设置x轴的范围为-2~2
plt.xticks([-2,-1,0,1,2])                                   # 设置x轴刻度
axes=plt.gca()
axes.xaxis.set_ticks_position('top')                        # 设置x坐标显示在上边框
plt.ylabel('y轴')
plt.ylim(-5,5)                                              # 设置y轴的范围为-5~5
plt.yticks([-3,-1,0,1,3],['低','较低','中等','高','较高'])     # 自定义刻度值
axes.yaxis.set_ticks_position('left')                       # 设置y坐标显示在左边框
        

我们还可以对图片的四个边框进行设置,通过plt.gca()获取轴系对象axes,通过.spines['right']获取右边框,之后可以set_color来设置其颜色,用set_position()来设置边框位置

axes.spines['right'].set_color('none')                      # 获取并设置右边框透明
axes.spines['top'].set_color('none')
axes.spines['bottom'].set_position(('data', 0))             # 将底部边框放到x=0的位置
axes.spines['left'].set_position(('data',0))                # 将左边框放到y=0的位置

3、图例和标注

在使用plt.plot()进行函数绘制时可以添加label属性来定义曲线的名称。

通过plt.legend()在图片中显示图例,其loc属性定义图例的位置,值有'best' : 0,'upper right' : 1, 'upper left' : 2, 'lower left' : 3, 'lower right' : 4, 'right' : 5, 'center left' : 6, 'center right' : 7, 'lower center' : 8, 'upper center' : 9, 'center' : 10,其中best代表自动分配最佳位置

plt.plot(x, y1, label='linear')
plt.plot(x, y2, color='red', linewidth=1.0, linestyle='--', label='square')
plt.legend(loc='upper right')

也可以将plot()结果保存为l1,l2对象,再传入legend函数中的handles属性,这样legend函数可以对图中指定的线条对象添加图例,并通过labels属性设置图例的内容

l1, = plt.plot(x, y1)
l2, = plt.plot(x, y2, color='red', linewidth=1.0, linestyle='--')
# 对指定线条对象添加图例
plt.legend(handles=[l1,l2,], labels=['linear','square'], loc='best')

通过plt.annotate()函数在图片中添加注释,第一个参数为注释的内容,fontsize注释大小,xycoords表示注释点的位置的表示方式,data代表根据数据,xy代表传入的数据,textcoords='offset points'代表注释的位置为根据点偏移,xytext设置偏移值,arrowprops以dict方式传入箭头的类型和弧度属性

通过plt.text()在图片中添加文本,前两个参数为文本的位置,第三个参数为文本内容,fontdict对文本字体、颜色进行设置,ha='center'设置居中对齐,va='bottom'设置向底部对其

plt.scatter([1],[1],s=100,color='orange')
# 添加自定义注释
plt.annotate('x²=2x-1',fontsize=20,xycoords='data',xy=(1,1),
             textcoords='offset points',xytext=(20,-30),
             arrowprops=dict(arrowstyle='->',connectionstyle='arc3,rad=.2'))
# 添加文本
plt.text(0.5,-1,"This is a text",fontdict={'size':15,'color':'green'},ha='center', va='top')

4、绘制图像

散点图

通过scatter()绘制散点图,s属性为点的大小,c为点的颜色,alpha点的不透明度

n = 1024    # data size
X = np.random.normal(0, 1, n) # 每一个点的X值
Y = np.random.normal(0, 1, n) # 每一个点的Y值
C = np.arctan2(Y,X)           # 为每个点生成颜色
plt.scatter(X, Y, s=75, c=C, alpha=0.5)

plt.show()

条形图

通过plt.bar()函数绘制条形图,前两个参数传入柱状图的x位置和y的值的数组,facecolor属性设置主题颜色,edgecolor设置边框颜色

n = 10
X = np.arange(n)        # X取1~12
Y1 = np.array([8,9,12,6,5,10,11,13,4,2])
Y2 = np.array([5,6,8,3,14,10,3,2,1,4])

plt.bar(X, Y1, facecolor='blueviolet', edgecolor='orange')
plt.bar(X, -Y2)

# 在柱状图顶部添加文本标注
for x, y in zip(X, Y1):
    plt.text(x, y , y, ha='center', va='bottom')
    
plt.show()

如上右图所示,通过plt.hist(data)可以绘制数据的统计分布直方图,参数bins指定划分的统计区间。

等高线图

等高线的数据是三维数据,X,Y为自变量,Z为因变量函数值,根据函数值的不同显示相同的值作为等高线

通过plt.contourf()函数进行颜色的填充,前三个参数为对应地X、Y、Z的值,cmap为填充的颜色,这里使用了matlabplot提供的一个颜色映射方案,根据值的由小到大映射为从蓝到红色

plt.contour()进行等高线的绘制,colors='black'线条颜色为黑色,linewidth=.5线条宽度为0.5

通过clabel()绘制文本,inline将文本填充到线条内

通过colorbar()函数可以为图片添加一个函数值对应颜色条

n = 256
x = np.linspace(-3, 3, n)
y = np.linspace(-3, 3, n)
X,Y = np.meshgrid(x, y)     # 编制为256×256的网格,并把对应的坐标值返回给X、Y数组
def fun(x,y):               # 定义函数值Z,是一个三维函数椭圆抛物面
    return x**2+y**2

F = plt.contourf(X, Y, fun(X, Y), 8, alpha=.75,cmap='RdBu')             # 进行颜色填充
C = plt.contour(X, Y, fun(X, Y), 8, colors='black', linewidth=.5)       # 绘制等高线
plt.clabel(C, inline=True, fontsize=10)                                 # 标注文本
plt.colorbar(F)                                                         # 添加一个colorbar
plt.show()

三维图像

在绘制3D图形前需要额外引入一个包Axes3D,通过它来将当前的图像转化为3D图

同样3D图需要三维数据,X、Y编制为网格是自变量,Z是函数值

通过plt.plot_surface()绘制3D图形,属性rstride 和 cstride 分别代表 row 和 column 的跨度,跨度越小,图形上的网格越密集,cmap为函数值的配色映射方案

通过等高线的绘制函数plt.contour()可以为3D图形在平面绘制投影,zdir='z'代表沿着Z轴进行投影,这样投影会出现在X-Y平面上,offset代表投影的偏移位置


import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D         #引入3D绘图库
%matplotlib inline

fig = plt.figure()
ax = Axes3D(fig)                                # 将当前图像转化为3D

X = np.arange(-10, 10, 0.5)
Y = np.arange(-10, 10, 0.5)
X, Y = np.meshgrid(X, Y)            # 编制 X-Y 平面的网格
Z = np.sqrt(X ** 2 + Y ** 2)        # Z值,定义为抛物面图形
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap='hsv')  # 绘制3D图
ax.contourf(X, Y, Z, zdir='z', offset=0, cmap='hsv')        # 添加沿Z轴方向的投影
plt.show()

绘制动画

绘制动画需要从matplotlib中额外引入animation库

之后先绘制其中一帧的图像,比如这里要绘制sinx的动画,先在0~2Π取自变量x数组,再绘制其sinx的曲线line

接着定义动画初始帧的显示函数init(),返回初始的line对象。然后定义其每一帧的图像显示函数animate,其参数i代表第i帧,根据i返回不同的line对象。

最后通过animation.FuncAnimation()绘制图像,其参数fig为之前创建的图片对象,init_func为初始化显示函数,func为每一帧的显示函数,interval为更新频率(单位ms),frames为动画一共有多少帧,blit为True代表每次只更新有变化的点

最后将返回的ani对象的save()方法将其保存为gif,这里使用的writer为imagemagick

import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation                 # 引入动画库
%matplotlib inline

fig,ax=plt.subplots()                            # 创建画布

x=np.arange(0,2*np.pi,0.01)                      # 从0~2Π每隔0.01取一个数
line,=ax.plot(x,np.sin(x))                       # 绘制sinx的图像

def init():                                      # 定义初始帧显示函数
    line.set_ydata(np.sin(x))
    return line,
def animate(i):                                  # 定义每一帧的显示函数
    line.set_ydata(np.sin(x+i/10))
    return line,

# 绘制动画
ani=animation.FuncAnimation(fig=fig,init_func=init,func=animate,interval=20,frames=100,blit=True)
ani.save('sinx.gif',writer='imagemagick')        # 保存动画为gif

plt.show()

5、多张图片

通过plt.subplot()可以划分为多个子图并选中其中的某个位置,例如subplot(2,2,1)代表创建2×2的子图,并且选中其中的第一个子图,也可以省略中间的逗号:subplot(224)代表选中2×2个子图中的第四个。除了直接通过plt对象绘制子图外,subplot可以返回子图对象,可以通过子图对象调用plot()来绘图。

import matplotlib.pyplot as plt
%matplotlib inline

plt.figure()

# 选中2×2子图中的第一个并画一条线
plt.subplot(2,2,1)
plt.plot([0,1],[2,3])
# 选中2×2子图的第四个画一条线
ax2=plt.subplot(224)
ax2.plt.plot([2,1],[3,4])

plt.show()

注意这里的划分并不是真正的分割图像,只是为了定位子图而假定将整个图像进行划分。例如下面的代码首先将画布认为2行1列选中第一块,就是上面的一行大的,再将其认为2行3列选择第四块,那就是第二行的第一个。通过不同的划分和选择可以得到不同大小与不同位置的子图。如果涉及到冲突的区域,后面的子图会将之前的子图覆盖掉。

# 划分为2行1列,选中第一块
plt.subplot(2,1,1)
plt.plot([0,1],[2,3])
# 划分为2行3列,选中第四块
plt.subplot(234)
plt.plot([2,1],[3,4])

   

通过subplot2grid()方法可以更加方便的划分和选择子图,如下所示subplot2grid((3, 3), (0, 0), colspan=3)表示将图片分为3×3区域,从第0行0列开始,横向跨越colspan列数为3,纵向跨越rowspan行数默认为1。

注意在一整张图中可以通过title()、xlabel()、ylabel()来设置标题和坐标名,但是在子图中需要在函数名之前加一个set_

ax1 = plt.subplot2grid((3, 3), (0, 0), colspan=3)
ax1.plot([1, 2], [1, 2])    # 画小图
ax1.set_title('ax1_title')  # 设置小图的标题

ax2 = plt.subplot2grid((3,3), (2,1),colspan=2)
ax2.plot([2,1],[1,0])
ax2.set_xlabel('ax2_x')    # 设置小图的坐标轴名
ax2.set_ylabel('ax2_y')

gridspec()函数可以让我们像使用python数组那样方便地选择子图区域。使用前先从matplotlib中引入该模块,通过Gridspec()函数将图像划分为区域,然后返回gs对象,通过gs对象可以像数组那样选择子区域。例如gs[1, :2],逗号之前代表对行序号的选择,如果只有一个数字代表选中全部序号为1的行,逗号之后为列,这里0:2代表选中从0到2列之前的所有列,其中从0开始可以省略。对应地如果选中指导结尾的话也可以省略,即gs[1, : ]。如果序号为-2,代表选中倒数第二个

import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec      # 引入库
%matplotlib inline

plt.figure()
gs = gridspec.GridSpec(3, 3)                # 将图像划分为3×3个区域
ax1 = plt.subplot(gs[0, :])                 # 选中第0行,所有列
ax2 = plt.subplot(gs[-1, -2])               # 选中倒数第1行,倒数第2列
plt.show()

 通过subplots()可以一次性创建并返回多个子图对象,如下所示为划分四个子图并且依次返回给ax11~ax22四个对象,并且四个对象的位置不能乱。其中sharex代表图像共享X坐标轴。plt.tight_layout()代表紧凑显示

f, ((ax11, ax12), (ax21, ax22)) = plt.subplots(2, 2, sharex=True, sharey=True)
ax11.scatter([1,2], [1,2])
plt.tight_layout()
plt.show()

画中画:通过figure对象的add_axes()可以在图片中添加另一个图片,其传入的参数为图片所在画布的四个边框的位置比例,返回创建的子图对象ax,利用ax进行绘制

x=[0,1]
y=[2,3]
fig = plt.figure()

ax1 = fig.add_axes([0.1, 0.1, 0.8, 0.8])    # 创建一个大图对象
ax1.plot(x, y, 'r')                         # 大图绘制
ax2 = fig.add_axes([0.2, 0.6, 0.25, 0.25])  # 创建小图
ax2.plot(x, y, 'b')                         # 小图绘制

plt.show()

子图拷贝:通过子图对象ax的twinx()函数可以在相同位置拷贝x轴相同的另一个重叠的ax对象,只不过y轴放到了对称的位置,最后两个子图会重叠显示

fig, ax1 = plt.subplots()
ax2 = ax1.twinx()                       # 拷贝ax对象

ax1.plot([0,1], [2,3], 'g-')            # 在原图中绘制
ax1.set_xlabel('X data')
ax1.set_ylabel('Y1 data', color='g')    # 原图的y轴在左侧
ax2.plot([0,1], [3,2], 'b-')            # 拷贝对象中绘图
ax2.set_ylabel('Y2 data', color='b')    # 拷贝子图的y轴在右侧
plt.show()

 

发布了124 篇原创文章 · 获赞 65 · 访问量 13万+

猜你喜欢

转载自blog.csdn.net/theVicTory/article/details/104571096
今日推荐