python自定义函数画图_Python气象数据处理与绘图(14):封装绘图函数(简洁绘制带地图子图的代码)...

Cartopy虽然对地理图形的绘制提供了极大的方便,但是个人感觉还是有很多反人类的地方,尤其是在同一个代码中绘制多副图形的时候,比如说地理坐标轴的设置,每幅子图都要设置一遍,最终搞得代码十分的冗长。为了解决这类问题,自定义的封装函数就起了很大作用,只需在最开始定义好,接下来每次使用直接调用即可,再也不用每次画图都重新设置什么刻度,海岸线之类的了。

其实用到的就是python的def功能,通过def自定义函数,return返回所需值,可以极大的简洁重复代码。

比如说绘制下面这幅图,我分别使用未封装的代码和使用封装后的代码绘制,方便对比。

example

未使用封装函数的完整代码:

#公共设置(地图投影,地图边界,坐标刻度地理格式)

proj = ccrs.PlateCarree(central_longitude=80)

img_extent = [0,160, 0, 80]

lon_formatter = cticker.LongitudeFormatter()

lat_formatter = cticker.LatitudeFormatter()

fig2 = plt.figure(figsize=(15,15))

#子图1

f2_ax1 = fig2.add_axes([0.1, 0.1, 0.4, 0.3],projection = proj)

#边界,海岸线,湖泊,坐标刻度,坐标格式

f2_ax1.set_extent(img_extent, crs=ccrs.PlateCarree())

f2_ax1.add_feature(cfeature.COASTLINE.with_scale('50m'))

f2_ax1.add_feature(cfeature.LAKES, alpha=0.5)

f2_ax1.set_xticks(np.arange(leftlon,rightlon+20,20), crs=ccrs.PlateCarree())

f2_ax1.set_yticks(np.arange(lowerlat,upperlat+20,20), crs=ccrs.PlateCarree())

f2_ax1.xaxis.set_major_formatter(lon_formatter)

f2_ax1.yaxis.set_major_formatter(lat_formatter)

#图序

f2_ax1.set_title('(a) ',loc='left')

#填色

f2_ax1.contourf(lon,lat, r, levels=np.arange(-0.9,1.0,0.1),extend='both', zorder=0, transform=ccrs.PlateCarree(), cmap=plt.cm.RdBu_r)

#子图2,同上

f2_ax2 = fig2.add_axes([0.6, 0.1, 0.4, 0.3],projection = proj)

f2_ax2.set_extent(img_extent, crs=ccrs.PlateCarree())

f2_ax2.add_feature(cfeature.COASTLINE.with_scale('50m'))

f2_ax2.add_feature(cfeature.LAKES, alpha=0.5)

f2_ax2.set_xticks(np.arange(leftlon,rightlon+20,20), crs=ccrs.PlateCarree())

f2_ax2.set_yticks(np.arange(lowerlat,upperlat+20,20), crs=ccrs.PlateCarree())

f2_ax2.xaxis.set_major_formatter(lon_formatter)

f2_ax2.yaxis.set_major_formatter(lat_formatter)

f2_ax2.set_title('(b) ',loc='left')

f2_ax2.contourf(lon,lat, r, levels=np.arange(-0.9,1.0,0.1),extend='both', zorder=0, transform=ccrs.PlateCarree(), cmap=plt.cm.RdBu_r)

可以看到,对底图设置的越精细所需的代码越长,但是绘制多图时均为重复代码,那么再看看封装后是怎样的:

使用封装函数:

首先将重复部分进行封装,那我们先分析重复部分的内容,包含了边界,海岸线,湖泊,坐标刻度,坐标格式等内容,需要需要传递的主要是地图的边界信息和坐标的间隔信息,以及对应的子图

def contour_map(fig,img_extent,spec):

fig.set_extent(img_extent, crs=ccrs.PlateCarree())

fig.add_feature(cfeature.COASTLINE.with_scale('50m'))

fig.add_feature(cfeature.LAKES, alpha=0.5)

fig.set_xticks(np.arange(leftlon,rightlon+spec,spec), crs=ccrs.PlateCarree())

fig.set_yticks(np.arange(lowerlat,upperlat+spec,spec), crs=ccrs.PlateCarree())

lon_formatter = cticker.LongitudeFormatter()

lat_formatter = cticker.LatitudeFormatter()

fig.xaxis.set_major_formatter(lon_formatter)

fig.yaxis.set_major_formatter(lat_formatter)

封装好后,后面只需直接调用即可。需要注意的是,这里并没有return,是因为函数中直接作用在了传递进去的fig上,因此无需再return。

#公共设置

proj = ccrs.PlateCarree(central_longitude=80)

leftlon, rightlon, lowerlat, upperlat = (0,160,0,80)

img_extent = [leftlon, rightlon, lowerlat, upperlat]

fig2 = plt.figure(figsize=(15,15))

#子图1

f2_ax1 = fig2.add_axes([0.1, 0.1, 0.4, 0.3],projection = proj)

#调用封装函数

contour_map(f2_ax1,img_extent,20)

f2_ax1.set_title('(a) ',loc='left')

f2_ax1.contourf(lon,lat, r, levels=np.arange(-0.9,1.0,0.1),extend='both', zorder=0, transform=ccrs.PlateCarree(), cmap=plt.cm.RdBu_r)

#子图2

f2_ax2 = fig2.add_axes([0.6, 0.1, 0.4, 0.3],projection = proj)

#调用封装函数

contour_map(f2_ax2,img_extent,20)

f2_ax2.set_title('(b) ',loc='left')

f2_ax2.contourf(lon,lat, r, levels=np.arange(-0.9,1.0,0.1),extend='both', zorder=0, transform=ccrs.PlateCarree(), cmap=plt.cm.RdBu_r)

仅仅是两幅子图,并没有缩减太多的代码,但是当子图较多时,这个方法就十分实用了。尤其是在jupyter notebook中,仅需要在最开始的代码块中随着各种库的一起引入,后边无论新建多长的代码块,都能使用,可以说只需要定义一次,在整个科研阶段中都可以随意调用。

实际上这里只是以绘图的方式举例def功能,还有很多地方也可以用到类似的思路,比如说自己写了一个算法,比如说是滑动t检验,你需要对多个序列进行检验,如果每次都写一遍滑动t的代码,那整个脚本的长度就太可怕了,完全可以用def的方法,只定义一次,接下来每个序列只需要一行调用函数就可以得到想要的结果,并且可以通过return的设置,返回所需要的各种中间变量。

你可能感兴趣的:(python自定义函数画图)