Cartopy雖然對地理圖形的繪制提供了極大的方便,但是個(gè)人感覺還是有很多反人類的地方,尤其是在同一個(gè)代碼中繪制多副圖形的時(shí)候,比如說地理坐標(biāo)軸的設(shè)置,每幅子圖都要設(shè)置一遍,最終搞得代碼十分的冗長。為了解決這類問題,自定義的封裝函數(shù)就起了很大作用,只需在最開始定義好,接下來每次使用直接調(diào)用即可,再也不用每次畫圖都重新設(shè)置什么刻度,海岸線之類的了。
其實(shí)用到的就是python的def功能,通過def自定義函數(shù),return返回所需值,可以極大的簡潔重復(fù)代碼。
比如說繪制下面這幅圖,我分別使用未封裝的代碼和使用封裝后的代碼繪制,方便對比。

未使用封裝函數(shù)的完整代碼:
#公共設(shè)置(地圖投影,地圖邊界,坐標(biāo)刻度地理格式)
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)
#邊界,海岸線,湖泊,坐標(biāo)刻度,坐標(biāo)格式
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)
可以看到,對底圖設(shè)置的越精細(xì)所需的代碼越長,但是繪制多圖時(shí)均為重復(fù)代碼,那么再看看封裝后是怎樣的:
使用封裝函數(shù):
首先將重復(fù)部分進(jìn)行封裝,那我們先分析重復(fù)部分的內(nèi)容,包含了邊界,海岸線,湖泊,坐標(biāo)刻度,坐標(biāo)格式等內(nèi)容,需要需要傳遞的主要是地圖的邊界信息和坐標(biāo)的間隔信息,以及對應(yīng)的子圖
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)
封裝好后,后面只需直接調(diào)用即可。需要注意的是,這里并沒有return,是因?yàn)楹瘮?shù)中直接作用在了傳遞進(jìn)去的fig上,因此無需再return。
#公共設(shè)置
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)
#調(diào)用封裝函數(shù)
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)
#調(diào)用封裝函數(shù)
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)
僅僅是兩幅子圖,并沒有縮減太多的代碼,但是當(dāng)子圖較多時(shí),這個(gè)方法就十分實(shí)用了。尤其是在jupyter notebook中,僅需要在最開始的代碼塊中隨著各種庫的一起引入,后邊無論新建多長的代碼塊,都能使用,可以說只需要定義一次,在整個(gè)科研階段中都可以隨意調(diào)用。
實(shí)際上這里只是以繪圖的方式舉例def功能,還有很多地方也可以用到類似的思路,比如說自己寫了一個(gè)算法,比如說是滑動(dòng)t檢驗(yàn),你需要對多個(gè)序列進(jìn)行檢驗(yàn),如果每次都寫一遍滑動(dòng)t的代碼,那整個(gè)腳本的長度就太可怕了,完全可以用def的方法,只定義一次,接下來每個(gè)序列只需要一行調(diào)用函數(shù)就可以得到想要的結(jié)果,并且可以通過return的設(shè)置,返回所需要的各種中間變量。