说在前面,写这个呢仅仅是为了记录下自己在学习过程中的一些问题以及排坑,代码也有很多待优化的地方,大佬们轻喷。
码字不易,转载务必注明出处!
先说下为什么要画这个图吧,本人石油工程研狗,帮老板板砖的时候总免不了画画图,有一天老板甩给我一篇论文,指了指文中一图。
于是我便开始在网络搜寻画法,百度关键词Python 、极坐标、云图、polar 、pcolor 均未果,仅找到了些许Matlab的代码,无奈实在没找到用python画图的代码,于是开始了自己的摸索。
首先这个是要先建立一个极坐标,然后导入数据插值(此处我有遇坑),最后在极坐标的基础上绘制这种伪色彩图的效果,找到了两种绘图方法pcolor
和contourf
两种方法,两种方法的区别我百度了一下,知乎-pcolor 和 contourf这两个函数有什么不同?,各位可以参考,也欢迎各位在评论区讨论区别。最终我选择了pcolor
。只因为pcolor
画出来的图更像吧。
数据是老师给的本专业领域的数据,同行看一眼应该就知道是什么了,非同行也不太用了解,就当是个学习资料了。
pos | 0 | 30 | 60 | 90 |
---|---|---|---|---|
0 | 1.101447148 | 1.308827831 | 1.526038083 | 1.603848713 |
30 | 1.101447148 | 1.279591136 | 1.49432297 | 1.577829862 |
60 | 1.101447148 | 1.204513965 | 1.435064241 | 1.52576792 |
90 | 1.101447148 | 1.108569817 | 1.404547306 | 1.499676995 |
120 | 1.101447148 | 1.204513965 | 1.435064241 | 1.52576792 |
150 | 1.101447148 | 1.279591136 | 1.49432297 | 1.577829862 |
180 | 1.101447148 | 1.308827831 | 1.526038083 | 1.603848713 |
210 | 1.101447148 | 1.279591136 | 1.49432297 | 1.577829862 |
240 | 1.101447148 | 1.204513965 | 1.435064241 | 1.52576792 |
270 | 1.101447148 | 1.108569817 | 1.404547306 | 1.499676995 |
300 | 1.101447148 | 1.204513965 | 1.435064241 | 1.52576792h |
330 | 1.101447148 | 1.279591136 | 1.49432297 | 1.577829862 |
360 | 1.101447148 | 1.308827831 | 1.526038083 | 1.603848713 |
// 导入数据
import numpy as np
import pandas as pd
df = pd.read_csv('data.csv')
# 注意!此处记得转化为弧度!
pos = np.array(df['pos']/180*np.pi)
ind = np.array(df.columns[1:], dtype=np.int)
values = np.array(df[ind.astype('str')])
# 把一维数据转化为二维绘图数据
r, theta = np.meshgrid(ind,pos)
至此数据导入完毕
插值之前,我们可以看一下图片质量。
from matplotlib import pyplot as plt
plt.figure(figsize=(10,10))
ax = plt.subplot(projection='polar')
ax.contourf(theta,r, values,cmap='jet',vmin=1, vmax=1.65)
ax.set_rgrids([30,60,90])
plt.grid(c='black')
本人在此处遇到大坑!!试了一下午没找到原因
首先是插值算法的选择,scipy.interpolate.interp2d
和scipy.interpolate.griddata
两种算法都能满足我的插值需求,即已知x,y,z,通过扩增的X,Y获取Z这种方式。
关于这两种插值的区别在新浪博客-matlab二维插值–interp2与griddata中有提到,但是关于interp2d
要求数据单调这一点,我是使用的时候没什么区别。
先是scipy.interpolate.interp2d
from scipy.interpolate import interp2d
#计算插值函数
func = interp2d(pos, ind, values.T,kind='cubic')
#绘图数据点
tnew = np.linspace(0, 2*np.pi, 200) # theta
rnew = np.linspace(0, 90, 100) # r
#
vnew = func(tnew,rnew)
#生成绘图二维数据
tnew, rnew = np.meshgrid(tnew, rnew)
此处我遇到了两个坑,首先是interp2d
函数的前两个参数,因为pos
和ind
在我这里分别是极坐标的角度和径向值,在我最开始插值的时候遇到了以下错误
func = interp2d(pos, ind, values,kind='cubic')
# 运行此语句会提示输入参数shape不对,于是改成了下面
func = interp2d(ind, pos, values,kind='cubic')
# 运行此语句后不会报错,但是拟合数据绘图出现严重偏差!
个人理解,在插值计算的时候,应该把按照theta,r的顺序输入参数。
然后是scipy.interpolate.griddata
查文档可发现,要求输入的坐标点和值,即要求坐标对(x,y)
形式输入point,并且长度要和value的长度一致,故需要先生成数据对
points=[]
for i in range(len(theta.flatten())):
points.append([theta.flatten()[i], r.flatten()[i]])
这里使用了很笨的办法,因为我尝试了直接以(theta, r)
作为point的输入值,结果依然是报错,不flatten
直接输入也都会报错。
griddata
插值完整代码
from scipy.interpolate import griddata
points=[]
for i in range(len(theta.flatten())):
points.append([theta.flatten()[i], r.flatten()[i]])
tnew_2 = np.linspace(0, 2*np.pi, 200) # x
rnew_2 = np.linspace(0, 90, 100) # y
tnew_2, rnew_2 = np.meshgrid(tnew_2, rnew_2)
vnew_2 = griddata(points, values.flatten(), (tnew_2, rnew_2), method='cubic')
绘图部分就相对简单了,就是各种调节参数让图好看,大家可以自由发挥了,下面呈上scipy.interpolate.interp2d
和scipy.interpolate.griddata
两种方式的结果图
scipy.interpolate.interp2d
插值结果
scipy.interpolate.griddata
插值结果
图像都还差不多!