Package: sacpy
SACPY -- A Python Package for Statistical Analysis of ClimateSacpy, an effecient Statistical Analysis tool for Climate and Meteorology data.Author : Zilu Menge-mail :zilumeng@uw.edugithub :https://github.com/ZiluM/sacpypypi :https://pypi.org/project/sacpy/Document:https://zilum.github.io/sacpy/version : 0.0.20Why choose Sacpy?Fast!For example, Sacpy is more than 60 times faster than the traditional regression analysis with Python (seespeed test). The following is the time spent performing the same task. Sacpy is fastest.Turn to climate data customization!Compatible with commonly used meteorological calculation libraries such as numpy and xarray.Concise codeYou can finish drawing a following figure with just seven lines of code. seeexamples of concise.You can use SVD/MCA to get the image below easily.Install and updateYou can use pip to install.pip install sacpyOr you can visithttps://gitee.com/zilum/sacpy/tree/main/distto download.whl file, thenpip install .whl_fileupdate:pip install --upgrade sacpyor you can download.whlfile and then install usepip install .whl_file.SpeedAs a comparison, we use thecorrfunction in the xarray library,corrcoeffunction in numpy library, cdist in scipy, apply_func in xarray  andfor-loop. The time required to calculate the correlation coefficient between SSTA and nino3.4 for 50 times is shown in the figure below.It can be seen that we are four times faster than scipy cdist, five times faster than xarray.corr, 60 times faster than forloop, 110 times faster than xr.apply_func and 200 times faster than numpy.corrcoef.Moreover, xarray and numpy can not return thep value. We can simply check the pvalue attribute of sacpy to get the p value.All in all, if we want to get p-value and correlation or slope, we only to chooseSacpy is 60 times faster than before.Exampleexample1Calculate the correlation between SST and nino3.4 indeximportnumpyasnpimportscapyasscpimportmatplotlib.pyplotaspltimportsacpy.Map# need cartopy or you can just not importimportcartopy.crsasccrs# load sstsst=scp.load_sst()['sst']# get ssta (method=1, Remove linear trend;method=0, Minus multi-year average)ssta=scp.get_anom(sst,method=1)# calculate Nino3.4Nino34=ssta.loc[:,-5:5,190:240].mean(axis=(1,2))# regressionlinreg=scp.LinReg(Nino34,ssta)# plotfig=plt.figure(figsize=[7,3])ax=plt.axes(projection=ccrs.PlateCarree(central_longitude=180))lon,lat=ssta.lon,ssta.lat# shadingm=ax.scontourf(lon,lat,linreg.corr)# significant plotn=ax.sig_plot(lon,lat,linreg.p_value,color="k",marker="..")# initialize mapax.init_map(stepx=50,ysmall=2.5)# colorbarplt.colorbar(m)# saveplt.savefig("../pic/nino34.png",dpi=200)Result(For a detailed drawing process, seeexample):example2multiple linear regression on Nino3.4 IOD Index and ssta patternimportnumpyasnpimportscapyasscpimportmatplotlib.pyplotasplt# load sstsst=scp.load_sst()['sst']# get ssta (method=1, Remove linear trend;method=0, Minus multi-year average)ssta=scp.get_anom(sst,method=1)# calculate Nino3.4Nino34=ssta.loc[:,-5:5,190:240].mean(axis=(1,2))# calculate IODIdexIODW=ssta.loc[:,-10:10,50:70].mean(axis=(1,2))IODE=ssta.loc[:,-10:0,90:110].mean(axis=(1,2))IODI=+IODW-IODE# get xX=np.vstack([np.array(Nino34),np.array(IODI)]).T# multiple linear regressionMLR=scp.MultLinReg(X,ssta)# plot IOD's effectimportsacpy.Mapimportcartopy.crsasccrsfig=plt.figure(figsize=[7,3])ax=plt.axes(projection=ccrs.PlateCarree(central_longitude=180))lon,lat=ssta.lon,ssta.latm=ax.scontourf(lon,lat,MLR.slope[1])# significant plotn=ax.sig_plot(lon,lat,MLR.pv_i[1],color="k",marker="..")# initialize mapax.init_map(stepx=50,ysmall=2.5)plt.colorbar(m)plt.savefig("../pic/MLR.png",dpi=200)Result(For a detailed drawing process, seeexample):example3What effect will ENSO have on the sea surface temperature in the next summer?importnumpyasnpimportsacpyasscpimportmatplotlib.pyplotaspltimportxarrayasxr# load sstsst=scp.load_sst()['sst']ssta=scp.get_anom(sst)# calculate Nino3.4Nino34=ssta.loc[:,-5:5,190:240].mean(axis=(1,2))# get DJF mean Nino3.4DJF_nino34=scp.XrTools.spec_moth_yrmean(Nino34,[12,1,2])# get JJA mean sstaJJA_ssta=scp.XrTools.spec_moth_yrmean(ssta,[6,7,8])# regressionreg=scp.LinReg(DJF_nino34[:-1],JJA_ssta)# plotimportcartopy.crsasccrsimportsacpy.Mapfig=plt.figure(figsize=[7,3])ax=plt.axes(projection=ccrs.PlateCarree(central_longitude=180))lon,lat=np.array(ssta.lon),np.array(ssta.lat)m=ax.scontourf(lon,lat,reg.slope)n=ax.sig_plot(lon,lat,reg.p_value,color="k",marker="///")ax.init_map(stepx=50,ysmall=2.5)plt.colorbar(m)plt.savefig("../pic/ENSO_Next_year_JJA.png",dpi=300)Same asIndian Ocean Capacitor Effect on Indo–Western Pacific Climate during the Summer following El Niño(Xie et al.), the El Nino will lead to Indian ocean warming in next year JJA.example4EOF analysisimportsacpyasscpimportnumpyasnpimportmatplotlib.pyplotasplt# get datasst=scp.load_sst()["sst"].loc[:,-20:30,150:275]ssta=scp.get_anom(sst)# EOFeof=scp.EOF(np.array(ssta))eof.solve()# get spartial pattern and pcpc=eof.get_pc(npt=2)pt=eof.get_pt(npt=2)# plotimportcartopy.crsasccrsimportsacpy.Maplon,lat=np.array(ssta.lon),np.array(ssta.lat)fig=plt.figure(figsize=[15,10])ax=fig.add_subplot(221,projection=ccrs.PlateCarree(central_longitude=180))m1=ax.scontourf(lon,lat,pt[0,:,:],cmap='RdBu_r',levels=np.linspace(-0.75,0.75,15),extend="both")ax.scontour(m1,colors="black")ax.init_map(ysmall=2.5)# plt.colorbar(m1)ax2=fig.add_subplot(222)ax2.plot(sst.time,pc[0])ax3=fig.add_subplot(223,projection=ccrs.PlateCarree(central_longitude=180))m2=ax3.scontourf(lon,lat,pt[1,:,:],cmap='RdBu_r',levels=np.linspace(-0.75,0.75,15),extend="both")ax3.scontour(m2,colors="black")ax3.init_map(ysmall=2.5)ax4=fig.add_subplot(224)ax4.plot(sst.time,pc[1])cb_ax=fig.add_axes([0.1,0.06,0.4,0.02])fig.colorbar(m1,cax=cb_ax,orientation="horizontal")plt.savefig("../pic/eof_ana.png",dpi=300)example5Mean value (Composite Analysis) t-test for super El Nino (DJF Nino3.4 > 1)importsacpyasscpimportnumpyasnpimportmatplotlib.pyplotaspltsst=scp.load_sst()["sst"]ssta=scp.get_anom(sst,method=0)# get Dec Jan Feb SSTAssta_djf=scp.XrTools.spec_moth_yrmean(ssta,[12,1,2])Nino34=ssta_djf.loc[:,-5:5,190:240].mean(axis=(1,2))# select year of Super El Ninoselect=Nino34>=1ssta_sl=ssta_djf[select]mean,pv=scp.one_mean_test(ssta_sl)# plotimportsacpy.Mapimportcartopy.crsasccrsfig=plt.figure(figsize=[7,3])ax=plt.axes(projection=ccrs.PlateCarree(central_longitude=180))lon,lat=np.array(ssta.lon),np.array(ssta.lat)m=ax.scontourf(lon,lat,mean)n=ax.sig_plot(lon,lat,pv,color="k",marker="..")ax.init_map(stepx=50,ysmall=2.5)plt.colorbar(m)plt.savefig("../pic/one_test.png")Result:example6SVD(MCA) analysis.importsacpyasscpimportxarrayasxrimportmatplotlib.pyplotaspltimportnumpyasnpfromxmcaimportarrayimportsacpy.Mapimportcartopy.crsasccrs# load datasst=scp.load_sst()['sst'].loc["1991":"2021",-20:30,150:275]ssta=scp.get_anom(sst)u=scp.load_10mwind()['u']v=scp.load_10mwind()['v']uua=scp.get_anom(u)vua=scp.get_anom(v)uv=np.concatenate([np.array(uua)[...,np.newaxis],np.array(vua)[...,np.newaxis]],axis=-1)# calculationsvd=scp.SVD(ssta,uv,complex=False)svd.solve()ptl,ptr=svd.get_pt(3)pcl,pcr=svd.get_pc(3)upt,vpt=ptr[...,0],ptr[...,1]sst_pt=ptl# plot progress, see example/SVD.ipynbresult:examples of conciseIf you want to plot example1's figure , you need write:fromcartopy.mpl.tickerimportLongitudeFormatter,LatitudeFormatterfrommatplotlib.tickerimportMultipleLocatorimportcartopy.crsasccrsplt.rc('font',family='Times New Roman',size=12)ax=plt.axes(projection=ccrs.PlateCarree(central_longitude=180))m=ax.contourf(ssta.lon,ssta.lat,linreg.corr,cmap="RdBu_r",levels=np.linspace(-1,1,15),extend="both",transform=ccrs.PlateCarree())n=plt.contourf(ssta.lon,ssta.lat,linreg.p_value,levels=[0,0.05,1],zorder=1,hatches=['..',None],colors="None",transform=ccrs.PlateCarree())xtk=np.arange(-180,181,60)ax.set_xticks(xtk)# ax.set_xticks(xtk,crs=ccrs.PlateCarree())ax.set_yticks(np.arange(-50,51,20),crs=ccrs.PlateCarree())ax.yaxis.set_major_formatter(LatitudeFormatter())ax.xaxis.set_major_formatter(LongitudeFormatter(zero_direction_label=True))ax.xaxis.set_minor_locator(MultipleLocator(10))ax.yaxis.set_minor_locator(MultipleLocator(5))ax.coastlines()ax.set_aspect("auto")plt.colorbar(m)So troublesome!!!But if youimport sacpy.Map, you can easily write:importsacpy.Mapimportcartopy.crsasccrsfig=plt.figure(figsize=[7,3])ax=plt.axes(projection=ccrs.PlateCarree(central_longitude=180))lon,lat=ssta.lon,ssta.latm=ax.scontourf(lon,lat,rvalue)n=ax.sig_plot(lon,lat,p,color="k",marker="..")ax.init_map(stepx=50,ysmall=2.5)plt.colorbar(m)How wonderful, how concise !AcknowledgementsThank Prof. Feng Zhu (NUIST,https://fzhu2e.github.io/) for his guidance of this project.Thank for Prof. Tim Li (University of Hawaii at Mānoa,http://iprc.soest.hawaii.edu/people/li.php) ,Prof. Lin Chen (NUIST,https://faculty.nuist.edu.cn/chenlin12/zh_CN/index.htm) and Dr. Ming Sun (NUIST) 's help.Sepcial thanks: Lifei Lin (Sun Yat-sen University) 'srepr_html.pyto visualize class in jupyter!Change Logversion 0.0.1Nothing!version 0.0.5First official editionversion 0.0.6Updated the speed test and changed small errorsversion 0.0.7Add examples and change README.mdversion 0.0.9Add mult_corr,partial_corr in LinReg.py and spec_moth_dat, spec_moth_yrmean in XrTools.Change examples.version 0.0.10Add EOF analysisversion 0.0.11Change Example Dataversion 0.0.12Fix a bug in XrToolsAdd Map.py for quick plotversion 0.0.13Change example!version 0.0.14Add SVD(MCA) analysis and visualization of LinReg in Jupyter.version 0.0.15Add Map.py for test and new wrapper progress for Map.py and Linregversion 0.0.16Optimized support for xarrayversion 0.0.17update mask function for LinRegadd shp mask functioncorrect SVDversion 0.0.18add new function of EOFcorrect some errors of EOF and SVDversion 0.0.19add new function for Mapfix some errors of Map