首页/文章/ 详情

基于matploblib的面向对象风格的绘图方式

11月前浏览1987
传统的绘图方式,典型如matlab,是面向过程的。尽管思维上更加直接,但灵活性不足。面向对象风格(以下简称OO风格)的绘图方式拥有更多的定制自由度。万物皆对象,这也是我个人偏好OO风格的原因。
Python主要通过调用matplotlib宏包绘图。matplotlib宏包可以通过面向过程调用,类似matlab的方式,对应pylab模块;也可以采用面向对象的方式调用,对应pyplot模块。这里仅介绍如何通过OO风格的调用matplotlib宏包绘图。而且,这里也仅关注绘图的框架,其余大量的绘图细节控制,请参考matplotlib手册(见文末)。
本文使用python3,编辑器则推荐使用spyder 3和jupyter notebook。PyCharm适合大型Python软件工程,笨重且不易上手。
matplotlib适合绘制线图,也可以绘制二维云图。至于三维流场的显示,建议使用ParaView。以下代码都已在linux系统(ubuntu18.04 & manjaro 18)上通过编译测试。
     

如何绘图?

   
首先,创建一个画布对象。    
就像作画之前,要先准备一张宣纸。    
   

创建画布对象的命令:

 fig = plt.figure()

创建画布对象后,就可以针对fig这个画布对象操作了。

括号中可以增加对画布的大小、分辨率以及颜色等的控制参数。

其次,画布对象剖分,建立axes子图对象。    
 

比如,需要在画布上创建两个子图对象,排布方式是“两行一列”,可以使用如下的代码:

 ax0 = fig.add_subplot(211) # 第一子图对象
 ax1 = fig.add_subplot(212) # 第二子图对象


然后,直接操作两个子图对象ax0和ax1绘图即可。

下面是一个简单的示例代码:

 import numpy as np # 调用数值计算包

 import matplotlib.pyplot as plt # 调用绘图包

 x = np.arange(0., 4.*np.pi, 0.1) # 准备数据

 y = np.sin(x)

 z = np.cos(x)

       

 fig = plt.figure() # 定义一个画布对象fig

       

 ax0 = fig.add_subplot(211) # 在画布对象上定义两个axes子对象

 ax1 = fig.add_subplot(212) # 排列方式是2 rows & 1 col

       

 ax0.plot(x,y) # 绘制线图

 ax1.plot(x,z)

 plt.tight_layout() # 使布局紧凑

 plt.show() # 在屏幕上显示图片        
<左右滑动>  

如果提示没有安装numpy或者matplotlib宏包,ubuntu系统下可以使用apt安装

 sudo apt installpython3-numpy
 sudo apt install python3-matplotlib


如果是manjaro系统,可以使用pacman安装。

最后,编译输出图片。  
 

如下所示:

 

图1 示例代码的图片效果

至此,我们已经展示了如何采用OO风格调用matplotlib宏包绘图:从全局到局部,再到细节,不断的定义对象,画布对象、axes子图对象……

为了改进各子图的细节,还需要进一步基于axes子图对象定义更多的子对象,比如axis坐标轴对象等。图1在细节上还非常粗糙,下面将展示如何控制图片整体布局以及更多细节。
   

绘制更多细节

 
 
1 保存图片

plt.show()只能在屏幕上显示效果图片。

若要保存图片,可使用命令:

plt.savefig('./figure01.png', dpi=200)

也可以保存为.jpeg、.eps、.pdf等其它的图片格式。dpi=200是输出图片的分辨率。

2 创建子图对象的方式
  • 创建方式一

 ax0 = fig.add_subplot(211)

 ax1 = fig.add_subplot(212)

第一节的示例展示就是采用这种方法,这种创建子图对象的方法可以满足大部分的期刊绘图要求。上面的命令意思是将画布分为“两行一列”,第一子图对象位于第1行第1列的位置,第二个子图对象占据第2行第1列的位置。  
 

可以用一行命令同时建立画布对象和子图对象:

 fig, ax = subplots(2,1)

这时,ax是一个2×1的数组,可以分别使用ax[0]和ax[1]引用。

  • 创建方式二:以网格的形式建立子对象

这种方式将整个画布分为若干网格单元,然后定义其中的每个子图对象占据的单元位置和数目。相比第一种方式,稍复杂,但更灵活,子图之间也不必须排列整齐。

ax0 = plt.subplot2grid((3,3), (0,0),rowspan=1, colspan=2)
ax1 = plt.subplot2grid((3,3), (0,2), rowspan=3, colspan=1)
ax2 = plt.subplot2grid((3,3), (1,0), rowspan=2, colspan=2)

<左右滑动>    

以第一个子图对象为例,括号中参数表示:将画布分为3×3共9个网格单元。子图对象ax0的位置是(0,0),占据一行两列共2个网格单元。其中位置坐标从画布的左上角算起。

  • 创建方式三

以上两种方式,建立的子图对象之间是隔离的。还有些情况,我们需要子图之间有重叠,比如一张子图是另外一张子图的特写放大。下面的命令可以满足要求

ax0 = fig.add_axes([0.1, 0.1, 0.8, 0.8])
ax1 = fig.add_axes([0.2, 0.5, 0.4, 0.3])

其中,方括号中,前两个表示子图的坐标,第三和第四个参数数值表示子图的长度和高度。坐标零点位于画布的左下角。  
当然还有其它的创建子图对象的方式,比如gridspec,大家可以自行查阅。

3 全局控制

如果需要自定义画布内所有目标对象涉及的字体及字体大小、颜色等,命令如下:

matplotlib.rcParams.update({'font.size':15,
                            'font.family':'STIXGeneral',
                            'mathtext.fontset':'stix',
                            'text.usetex':True})


4 最后的输出图

import matplotlib

import numpy as np

import matplotlib.pyplot as plt          
from matplotlib.ticker import FuncFormatter          
         
matplotlib.rcParams.update({'font.size':22,          
                            'font.family': 'STIXGeneral',          
                            'mathtext.fontset': 'stix',          
                            'text.usetex': True})          
         
#fig, ax1 = plt.subplots(1, 1, figsize=(8, 5))          
fig = plt.figure(figsize=(8,5))          
ax1 = fig.add_axes([0.1, 0.15, 0.775, 0.75])          
         
x = np.arange(0, 2.*np.pi, 0.05)          
y1 = x ** 2.0          
         
ax1.plot(x, y1, marker='o', markevery=5, color='r', markersize=10,          
         label=r'$x^2$')          
ax1.set_xlabel(r'$x$')          
ax1.set_ylabel(r'$y_1 = x^2$')          
ax1.legend(loc=0, frameon=True)          
         
xticks1 = [0, np.pi/3.0, np.pi/3.0*2., np.pi, np.pi/3.0*4.0, np.pi/3.0*5.0, 2.0*np.pi]          
ax1.set_xticks(xticks1)          
xticklabels = [0, r'$\pi/3$', r'$2\pi/3$', r'$\pi$', r'$4\pi/3$', r'$5\pi/3$', r'$2\pi$']          
ax1.set_xticklabels(xticklabels)          
         
ax1.set_title(r'dual $y$-axix')          
ax1.set_ylim([-2.5, 44])          
ax1.set_xlim([-0.5, 6.75])          
         
ax1.tick_params('y', which='major', direction='in', length=8, width=2)          
ax1.tick_params('x', which='major', direction='in', length=8, width=2)          
         
ax2 = ax1.twinx()          
y2 = np.sin(x)          
         
ax2.plot(x, y2, marker='d', markevery=5, color='gold', markersize=10,          
         label=r'$\sin x$')          
ax2.set_ylabel(r'$y_2 = \sin x$')          
ax2.legend(loc=0, frameon=True)          
         
def formatnum(x, pos):          
    return '$%+4.1f$' % x          
         
formatter = FuncFormatter(formatnum)          
ax2.yaxis.set_major_formatter(formatter)          
         
ax2.set_ylim([-1.2, 1.2])          
ax2.tick_params('y', which='major', direction='in', length=8, width=2)          
         
fig.subplots_adjust(left=0.15, right=0.95, bottom=0.15, top=0.95)          
fig.savefig('figure02.png', dpi=200)          
编译后,输出的图片效果如图2所示。
 
 
   

图2 改进部分细节后的效果

       
       

总 结

OO风格调用matplotlib宏包绘图的步骤总结为图3:  
 

图3 绘图流程

更多细节控制,可参考以下网站:    

https://www.tutorialspoint.com/matplotlib/index.htm

matplotlib的官方主页:https://matplotlib.org/

来源:多相流在线
OpenFOAM碰撞多相流湍流核能电力电子python材料控制ParaView
著作权归作者所有,欢迎分享,未经许可,不得转载
首次发布时间:2023-06-23
最近编辑:11月前
积鼎科技
联系我们13162025768
获赞 97粉丝 83文章 254课程 0
点赞
收藏
未登录
还没有评论

课程
培训
服务
行家

VIP会员 学习 福利任务 兑换礼品
下载APP
联系我们
帮助与反馈