一个箭头quiver([X,Y],U,V,[C],**kw)组成的quiver的几个参数的理解,其中kw的参数为:units:默认值为width,width/heigth:箭头的宽度就是x轴或者y轴的总长度,没错,就是总长度;dots/inches:箭头的宽度是设置的dpi还是设置的inch尺寸,影响width参数,比如画布尺寸设置为plt.figure(figsize=(144,72),dpi=10),这个canvas占1440*720px,如果quiver设置units="dots",width=5,表示基本单位是10个像素,宽度5倍就是画一个箭头的宽度占50px,所以数据需要采样,否则会粘在一起;x/y/xy:基于x、y或xy的平方根的宽度,如果设置了x轴或y轴坐标,则step长度为1,与画布的像素大小一致。这样一个像素对应一个整数坐标值x,那么箭头杆的宽度就可以控制了。箭杆的基本长度为根号2px;width:float类型,用来控制箭杆的宽度,我只知道units=dots时的宽度的理解,但是对于units=x/y/xy时的宽度是指我根据上面的临时理解;angle:uv/xy,uv箭头的纵横比(axisaspectratio)为1,所以如果U==V,图中箭头的方向为水平轴逆时针45度(正向右);xy箭头从(x,y)指向(x+u,y+v),比如用它画一个渐变场(gradientfield)headwidth:float类型,默认3,用来控制半宽箭头三角形底部的值是杆宽的倍数;headlength:float类型,默认5,用于控制箭头斜边的长度,该值是指杆宽的倍数,例如4.5是指杆宽的4.5倍;scale:float类型,默认为None,用于控制杆的长度,值越小,轴越长,如果为None,则使用matplotlib自动缩放算法,箭头长度单个scale_units参数指定scale_units:如果这个值设置为width/heigth,那么scale应该设置为0.000x,这几乎是想要的结果,如果设置为英寸,它与你的dpi和scale有关,forplt.figure(figsize=(144,72),dpi=10)比例=1、scale_units="inches"和scale=0.1,scale_units="x/xy/不写"画出一样的结果;pivot:tail/mid/middle/tip,默认tail指的是箭头的中心,其实就是画样图的地方。所有代码参考#_*_coding:utf-8_*_importmatplotlib.pyplotaspltfromPILimportImageimportnumpyasnpimportosimportsysimportjsonimporth5pyFILLVALUE=-32767defassigncolor(tardataset,mask,colorbar):iftardataset[mask].size>0:如果len(colorbar)>=4:tardataset[mask]=colorbar否则:tardataset[mask]=[colorbar[0],colorbar[1],colorbar[2],255]returntardataset[mask]defsingle_drawer(dataset,colorbar,tardataset):#特殊值处理nullmask=np.isnan(dataset[:])|np.isinf(dataset)tardataset[nullmask]=[255,255,255,0]forindexinrange(0,len(colorbar)):#获取需要判断的值valuemask=tardataset[:,:]==[-1,-1,-1,-1]#3D转2D,方便与数据集的mask合并valuemask=valuemask[:,:,0]mask=dataset==colorbar[index][0]目标数据集[valuemask&mask]=assigncolor(tardataset,valuemask&mask,colorbar[index][1])returntardatasetdefgradient_drawer(dataset,colorbar,tardataset):#特殊值处理nullmask=np.isnan(dataset[:])|np.isinf(dataset)tardataset[nullmask]=[255,255,255,0]#小于最小值valuemask=tardataset[:,:]==[-1,-1,-1,-1]valuemask=valuemask[:,:,0]mask=dataset<=colorbar[0][0]tardataset[valuemask&mask]=assigncolor(tardataset,valuemask&mask,colorbar[0][1])forindexinrange(0,len(colorbar)-1):#获取需要判断的值valuemask=tardataset[:,:]==[-1,-1,-1,-1]ifindex==18:print(valuemask.shape)valuemask=valuemask[:,:,0]mask=(dataset>colorbar[index][0])&(dataset<=colorbar[index+1][0])tempmask=valuemask&maskiftempmask[tempmask==真]。大小>0:比率=(1.0*(dataset[valuemask&mask]-colorbar[index][0])/(colorbar[index+1][0]-colorbar[index][0])).reshape(-1,1)colorrange=(np.array(colorbar[index)+1][1]-np.array(colorbar[index][1])).reshape(1,-1)temp=np.dot(ratio,colorrange)+np.array(colorbar[index][1])如果len(colorbar[index][1])<4:alphaband=np.ones((temp.shape[0],1))alphaband[::]=255temp=np.column_stack((temp,alphaband))tardataset[valuemask&mask]=temp#最大价值valuemask=tardataset[:,:]==[-1,-1,-1,-1]valuemask=valuemask[:,:,0]mask=dataset>colorbar[-1][0]tardataset[valuemask&mask]=assigncolor(tardataset,valuemask&mask,colorbar[-1][1])returntardatasetdefdrawWindDir(in_file,u_ds,v_ds,dir_file,cb_file):#读取调色板gradient_cb=[]single_cb=[]withopen(cb_file,"r")ascb_json:cb_data=json.load(cb_json)gradient_cb=cb_data["gradient"]single_cb=cb_data["single"]#读取风速h5py_obj=h5py.File(in_file,'r')u_data=np.array(h5py_obj[u_ds])v_data=np.array(h5py_obj[v_ds])sws_data=np.array(h5py_obj["SWS"])#获取宽高uh,uw=np.shape(u_data)vh,vw=np.shape(v_data)#上下翻转数据u=np.flip(u_data,0)v=np.flip(v_data,0)#读取风速的有效范围sws_valid=h5py_obj["SWS"].attrs['validrange']#使用风速的有效值控制无效值区域提取valid_mask=(sws_data>=sws_valid[0])&(sws_data<=sws_valid[1])#用u,v向量计算风速wp=np.empty((uh,uw),dtype=np.float)wp[:,:]=FILLVALUEwp[valid_mask]=np.sqrt(np.power(u[valid_mask]/100.0,2)+np.power(v[valid_mask]/100.0,2))#初始化输出数据集tardataset=np.ones((uh,uw,4),dtype=np.int)tardataset[::]=-1#移除singlepalette的值tardataset=single_drawer(sws_data,single_cb,tardataset)#根据渐变调色板重新分配result_data=gradient_drawer(sws_data,gradient_cb,tardataset)#输出风速底图new_image=Image.fromarray(result_data.astype(np.uint8)).convert('RGBA')new_image.save(in_file.replace(".HDF",".png"),'png')#风向xy坐标,uv向量,1440,720,去除无效值u_valid=valid_maskX,Y=np.meshgrid(np.arange(0,uw,1),np.flipud(np.arange(0,uh,1)))U=u.astype(np.int64)V=v.astype(np.int64)newU=np.zeros((uh,uw))newV=np.zeros((呃,uw))newU[u_valid]=U[u_valid]/np.sqrt(np.power(U[u_valid],2)+np.power(V[u_valid],2))newV[u_valid]=V[u_valid]/np.sqrt(np.power(U[u_valid],2)+np.power(V[u_valid],2))#无效值为nannewU[newU==0]=np.nannewV[newV==0]=np.nan#创建画布fig1=plt.figure(figsize=(uw,uh),dpi=1)ax1=fig1.add_subplot(111)#去掉坐标轴,去掉两边的空白,并控制输出的xy轴范围plt.axis('off')plt.subplots_adjust(top=1,bottom=0,left=0,right=1,hspace=0,wspace=0)plt.ylim(0,呃)plt.xlim(0,uw)#网格采样i=10Q=ax1.quiver(X[::i,::i],Y[::i,::i],newU[::i,::i],newV[::i,::i],scale=0.1,width=1,units="xy",angles='uv',headwidth=3.5,headlength=4,pivot="mid")ax1.scatter(X[::i,::i],Y[::i,::i],color='r',s=30)plt.show()fig1.savefig(dir_file,transparent=True)plt.close()defmergeDirSpd(spd_img,dir_img,out_img):backimage=Image.open(spd_img)frontimage=Image.open(dir_img)#暂时没有考虑因素不一致outimage=Image.alpha_composite(backimage,frontimage)outimage.save(out_img)if__name__=="__main__":in_path=sys.argv[1]ds=sys.argv[2]cb_file=sys.argv[3]ifos.path.isdir(in_path):forw_root,w_dirs,dir_filesinos.walk(in_path):forone_fileindir_files:if'.HDF'inone_fileand"SWS"inone_file:in_file=os.path.join(w_root,one_file)spd_img=in_file.replace(".HDF",".png")dir_img=in_file.replace(".HDF","_dir.png")out_img=in_file.replace(".HDF","_dp.png")u_ds="wind_vel_u"v_ds="wind_vel_v"drawWindDir(in_file,u_ds,v_ds,dir_img,cb_file)mergeDirSpd(spd_img,dir_img,out_img)elifos.path.isfile(in_path):in_file=in_pathspd_img=in_file.replace(".HDF",".png")dir_img=in_file.replace(".HDF","_dir.png")out_img=in_file.replace(".HDF","_dp.png")u_ds="dwind_vel_u"v_ds="wind_vel_v"drawWindDir(in_file,u_ds,v_ds,dir_img,cb_file)mergeDirSpd(spd_img,dir_img,out_img)
