使用 Python 科学绘图

使用 matplotlib 绘图

读取数据

import pandas as pd
data = pd.read_csv('%s'%(file), sep=' ', skiprows=2, names=['x','y','z','T'])

自动将第一行作为 index,可以这样调用:data['x']
也可以手动设置 index:names=['x','y','z','T']
通过 skiprows 设置需要忽略的行:

  • 数字指定:skiprows = 2 表示忽略前 2 行。
  • 列表指定:skiprows = [0] 表示忽略第 0 行。
  • 列表指定:skiprows = range(1, 10)) 表示忽略第 1 到 9 行,保留第 0 行,和第 10 行及以后的行。

默认逗号为分隔符,也可以设为 \t等。

图型

点线图 plot

plot(x, y) # 最简单的,x y 是一一对应的数组
plot(x, y, color='green', linestyle='dashed', linewidth=2, marker='o', markersize=12)

colors
markers
Linestyles
colormaps

Base Colors:

unfilled markers:
unfilled-markers
filled markers

可以将 plot 中的线宽设为 0,这样只剩下 symbol:

plot(data['Z'], data['T'], marker='.', linewidth=0)

竖直线和水平线

水平线

ax.axhline(y=0, xmin=0, xmax=1, color='black', linewidth=2)
ax.axhline(0, color='black', linewidth=2)

竖直线

ax.axvline(x=0, ymin=0, ymax=1, color="r")
ax.axvline(0, color="r")

散点图 scatter

colorMap=plt.cm.hot
plt.scatter(X, Y, c=Z, s=1, marker='s', cmap=colorMap)

散点用 X Y 表示,用 Z 着色,色带是 plt.cm.hot,size是 1。
更多设置参考网址

我的一般做法:

#colorMap=plt.cm.hot_r
#colorMap=plt.cm.hot
colorMap=Cube1_20.mpl_colormap

x = np.array(Z)
y = np.array(PV)
z = np.array(sourcePV)

idx = z.argsort()
x, y, z = x[idx], y[idx], z[idx]

colorMap=Cube1_20.mpl_colormap
plt.scatter(x, y, c=z, s=1, cmap=colorMap)

#plt.legend(loc='best') 如果上边scatter中设定了label,则可以开启legend。
plt.xlabel('Z [-]',fontsize=12)
plt.ylabel('PV [-]',fontsize=12)

plt.savefig("scatter_sourcePV_ZPV.png",dpi=500)
plt.savefig("scatter_sourcePV_ZPV.pdf",bbox_inches='tight',pad_inches=0.01)
plt.close('all')

云图 contourf

data = pd.read_csv(file, sep='\t')
Z = data['Z']
C = data['C']
T = data['T']

xi=np.linspace(min(Z),max(Z),1000)
yi=np.linspace(min(C),max(C),1000)
[XX,YY]=np.meshgrid(xi,yi)
ZZ=griddata((Z,C), T, (XX,YY), method='cubic')

colorMap=Cube1_20.mpl_colormap
im=plt.contourf(XX, YY, ZZ, 20, cmap=colorMap)
cbar = plt.colorbar(im)
ax=plt.gca()
ax.set_aspect(1.0) # set uniform length of axis

越界时指定颜色,其中,extend : {'neither', 'both', 'min', 'max'}

levels=np.arange(-10,4200000,1000)
colorMap=Cube1_20.mpl_colormap
cp=plt.contourf(XX, YY, ZZ, levels=levels, cmap=colorMap, extend='both')
cp.cmap.set_under('yellow')
cp.cmap.set_over('cyan') #注意顺序,此行须在 plt.colorbar 之前
cbar = plt.colorbar(cp)
cbar.ax.set_title('T')

小于某个数时颜色全部为空白:

levels=np.arange(0.0015,0.7515,0.0015)
im=plt.contourf(XX, YY, ZZ,levels=levels)#这里不能使用extend,如果使用的话,那么小于下限时,颜色直接是 min 的颜色。

设置图中的数值上下限:

设置色条中的上下限:

等值线

import colorcet as cc
colorMap=cc.cm["fire"]
plt.contourf(XX, YY, ZZ, 200, cmap=colorMap) #这是云图,200 表示分为 200 道等值线
plt.contour(XX, YY, ZZ, 1, levels=[1000], linewidths=2, colors='y') #这是等值线,1表示一条等值线,levels里边是这个值

配件

图片颜色

自带 调色

colorMap = plt.cm.get_cmap('winter') 
colorMap=plt.get_cmap("YlOrRd")
colorMap=pyplot.cm.jet

palettable 调色

源码:https://github.com/jiffyclub/palettable

from palettable.mycarta import Cube1_20
from palettable.colorbrewer.sequential import Greys_9
colorMap=Cube1_20.mpl_colormap
colorMap=Greys_9.mpl_colormap

colorcet 调色

源码:https://github.com/pyviz/colorcet

import colorcet as cc
colorMap=cc.cm["blues"]
colorMap=cc.cm["fire"]

反转颜色

自带的反转就是在后边加一个 _r,比如:colorMap=plt.cm.hot_r

反转非自带的颜色
def reverse_colourmap(cmap, name = 'my_cmap_r'):
"""
In:
cmap, name
Out:
my_cmap_r

Explanation:
t[0] goes from 0 to 1
row i: x y0 y1 -> t[0] t[1] t[2]
/
/
row i+1: x y0 y1 -> t[n] t[1] t[2]

so the inverse should do the same:
row i+1: x y1 y0 -> 1-t[0] t[2] t[1]
/
/
row i: x y1 y0 -> 1-t[n] t[2] t[1]
"""
reverse = []
k = []

for key in cmap._segmentdata:
k.append(key)
channel = cmap._segmentdata[key]
data = []

for t in channel:
data.append((1-t[0],t[2],t[1]))
reverse.append(sorted(data))

LinearL = dict(zip(k,reverse))
my_cmap_r = mpl.colors.LinearSegmentedColormap(name, LinearL)
return my_cmap_r


cmap=cc.cm["fire"]
cmap_r = reverse_colourmap(cmap)

色条 colorbar

简单使用

colorMap=pyplot.cm.jet
sc = plt.scatter(X, Y, c=Z, s=1, cmap=colorMap)
plt.colorbar(sc)

所有用法

API
API2

色条位置偏移使用 pad,色条尺寸缩小使用 shrink

plt.colorbar(sc, pad = 0.07,shrink=0.8)

指定色条位置的具体坐标

cbar_ax = fig.add_axes([0.19, 0.06, 0.7, 0.015]) #left,bottom,left_length,bottom_length
cbar=plt.colorbar(sc, cax=cbar_ax, orientation='horizontal')

指定色条的坐标值

cbar.formatter.set_powerlimits((0, 0))#科学计数法
cbar_ticks = np.linspace(0., 5e-3, num=3, endpoint=True)
cbar.set_ticks(cbar_ticks)

色条上的数值,怎么才能显示 max min?

色条上的tick,如果色条竖直,默认是朝右的,如果色条水平,默认朝下的。

可以这样更改:

cbar.ax.xaxis.set_ticks_position('top')#色条水平,horizontal
cbar.ax.yaxis.set_ticks_position('left')#色条竖直,vertical

也可以这样:

cbar.ax.yaxis.tick_left()

添加变量名,推荐使用 set_title

set_title 默认在最上方,不管色条是水平还是竖直。有个参数 pad 表示向上偏移距离。

cbar.ax.set_title('$\Omega\ [-]$', pad=10)

添加变量名,另一个方法 set_label

cbar.set_label('$\Omega\ [-]$')

变量名改变位置

色条是水平的,这里的 bottom 表示变量名放在水平色条的下边,labelpad 是向下的偏移距离。

cbar.set_label('T',verticalalignment='bottom', labelpad=-10)

Vertical alignment must be one of (‘top’, ‘bottom’, ‘center’, ‘baseline’)
Horizontal alignment must be one of (‘center’, ‘right’, ‘left’)

对于水平色条,horizontalalignment 不管用?

图例 legend

plt.plot(X, Y, label="sim") # 这里的 label 即图例
plt.legend(loc='upper left') # 图例位置
plt.legend(loc='best') # 自动选择最合适的位置
plt.plot(legend=None)

上下左右:upper lower left right

在循环里边画很多条线时,只想保留一个 legend,循环结束后:

from collections import OrderedDict
handles, labels = plt.gca().get_legend_handles_labels()
by_label = OrderedDict(zip(labels, handles))
plt.legend(by_label.values(), by_label.keys())

关于位置的高级用法:

ax1.legend(loc='upper right', bbox_to_anchor=(1.05, 4.3), ncol=3, fontsize=10)

bbox_to_anchor 表示最左和最上的位置。这个位置是0-1,超过1表示坐标轴以外
ncol=3 表示三栏

参考资料

科学计数法

色条:

sc = plt.scatter(X, Y, c=Z, s=1,cmap=Cube1_20.mpl_colormap)  
cbar = plt.colorbar(sc)
cbar.formatter.set_powerlimits((-1, 1))
cbar.update_ticks()

这样小于 10^(-1),或者大于 10^(1) 的值就会用科学计数法。

坐标轴

设置坐标轴 label

plt.xlabel('r [mm]',fontsize=12)
```


### 调整坐标轴范围

```python
plt.axis([0, 4, 0, 4]) # 改变取值范围,[xmin, xmax, ymin, ymax]
plt.axis(xmin =0, xmax = 0.5, ymin = 0, ymax = 0.55)
plt.xlim(0,0.35)
plt.ylim(0,0.2)

自定义刻度

x_new=np.array([5,10,15,20])
plt.xticks(x_new)

刻度朝内

plt.tick_params(direction='in')

刻度小数点位数

import matplotlib.ticker as ticker
plt.gca().xaxis.set_major_formatter(ticker.FormatStrFormatter('%.6f'))

隐藏坐标

在包含几个子图的图标中,可能需要隐藏一些重复的坐标

ax1 = plt.subplot(420+i) 
plt.setp(ax1.get_xticklabels(), visible=False)
plt.setp(ax1.get_yticklabels(), visible=False)

隐藏 ticks 和 label

ax1.set_xticks([])

隐藏子刻度

plt.minorticks_off()

x y 坐标等比例

这个用于CFD模拟场的云图,保证 x y 长度是等比例的。

ax=plt.gca()
ax.set_aspect(1.0) # set uniform length of axis

使用 LaTeX 公式

$ 包围起来并在前边加上 r 即可,最好 $ 和公式之间留一个空格。

plt.xlabel(r'Scalar dissipation rate $ [s^{-1}] $',fontsize=12)

任意位置添加文字

plt.text(1, 17, r"z=%s mm"%(str(Z)))

子图 subplot

plt.subplots_adjust(left=0.11,bottom=0.1,top=0.97,right=0.9,hspace=0.000001,wspace=0.000001) 

i=0
for Z in ['2','10','30','50']:
i=i+1
ax1 = plt.subplot(410+i)
plt.plot(R_Mean,U_Mean,linestyle='--',marker='o', color='r',label="sim")

subplot(410+i) 表示子图 4x1 排列,即 4 行 1 列。此处的循环,令 i 分分别等于 1 2 3 4。

也可以用subplot(4,1,i)表示。

绘制着色的多个子图(云图或者上色=的散点图)需要注意他们的数据 min max可能不同。
可以设置 vmin vmax是他们保持一致:

plt.scatter(x1, y1, c=z1, s=2, marker='o', vmin=minZ, vmax=maxZ)
plt.scatter(x2, y2, c=z2, s=2, marker='s', vmin=minZ, vmax=maxZ)

图片标题

plt.title('source_Yc',fontsize=12)

alpha 表示不透明度,1表示完全不透明

可以用于 plot scatter contour contourf 中。

输出图片

紧凑布局

plt.savefig("scatter_sourcePV_ZPV.png",dpi=500)
plt.savefig("scatter_sourcePV_ZPV.pdf",bbox_inches='tight',pad_inches=0.01)

python 相关

利用正则表达式获取当前目录下的某些文件

import glob
files = glob.iglob(r'0.*')
for file in files:
print file

换行

ylabel('this is vertical\ntest', multialignment='center')#\n表示换行

灰色系列填充彩图

在图中使用其它字体

https://stackoverflow.com/a/53645383
我成功操作的经历:

把字体拷贝到:
/public/home/yao1/packages_ZY/anaconda_ZY/anaconda3/lib/python3.6/site-packages/matplotlib/mpl-data/fonts/ttf
然后:
rm -rf ~/.cache/matplotlib/

使用字体:

from matplotlib import rcParams
rcParams.update({'font.size': 12, 'font.family': 'Times New Roman'})

from matplotlib import rcParams
rcParams.update({'font.size': 12, 'font.family': 'simsun'})

ax1.legend(loc='upper right', bbox_to_anchor=(0.92, 3.7), ncol=3,fontsize=10,prop={'family':'simsun'})

plt.text(1.03,5.4,'平均值',fontname='simsun')

疑难解答

服务器绘图

报错 QXcbConnection: Could not connect to display

solution:
在脚本的最前边加上

import matplotlib
matplotlib.use('Agg')
文章作者: Yan Zhang
文章链接: https://openfoam.top/matplotlib/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 OpenFOAM 成长之路
微信打赏给博主更多动力吧~