瞎哔哔
前言
本人不幸从龙王山皇家气象学院毕业后,又继续投入了祖国气象事业怀抱。为了肩负国家崛起的重任(?),不得不苦学python,其过程之痛苦按下不表。
于今日开学之际简单做一些暑假所学之小结,谨以此回望那个笨拙、不知道怎么获取知识、一学习编程语言就想昏倒的,当初的自己。
冀以尘雾之微补益山海,荧烛末光增辉日月。
(补:我偶像目前是杨效业学长(大气院的优秀学长之一(某站id是摸鱼的那位)
(万一十年后我还在从事气象相关事业,看到这篇博客会不会被自己的中二之魂震惊到)
简介
matplotlib,就是我们『Linux与python,后面记不住了』那门课的第四章,主要是一个用于气象类画图的库。官网链接:https://matplotlib.org/stable/plot_types/basic/index.html
切记
实操中有什么不会的,直接
help(#里面是不会的、想要查询的内容#)
大部分时间都可以获得想要的解答。有的可能不能直接写进括号,尝试一下定义ax后,help(ax.想要查询的)。我在这篇中默认你通过了英语六级,看得懂基础英文释义。(虽然两者没有直接关联)
然后就认真开始写了!
最后强调一下,代码给出的只是局部,读者可自行根据上下文补全
(主要是省略了安装库、创建画布、投影等等)
画布
创建画布
import matplotlib.pyplot as plt
先把库安装上,才可以用。
fig=plt.figure(dpi=200)
dpi是清晰度,200就够用了。创建出来的fig就是画布的名字。然后在画布里添加子图。
ax1=fig.add_axes([0.1, 0.1, 1.2,1.0])
前两个表示起始位置,后两个表示子图的长和宽。
ax = plt.subplot(1, 1, 1)
这是另一种创建子图的方法,但是我不太会用。
地图投影
你要画地形图的话,就需要用到地图投影,对应的代码应该长成这样:
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
ax1=fig.add_axes([0.1, 0.1, 1.2,1.0],projection=ccrs.PlateCarree())
from cartopy.io.shapereader import Reader
SHP=r'#shp存放路径#\map'
ax1.add_geometries(Reader(os.path.join(SHP, 'China.shp')).geometries(),ccrs.PlateCarree(), facecolor='none', edgecolor='grey', linewidth=1.5)
上为叠加国界线(国界线、省界线等应为shp文件)
ax1.coastlines(lw=1.5)
上为叠加海岸线。同理可添加陆地、海洋、河流。但是不好说,我印象里时灵时不灵的。
至于白化?我也不会。
画图
我感觉我写的磨磨唧唧的,要加快速度了。
网格线
不建议添加,因为我每次加了都被导师说画图不美观而删除。
ax.grid(True, linestyle='-', linewidth=0.3, color='gray',alpha=0.5)
直线
ax.plot(year,t,label='temperature',alpha=0.5,c='black',lw=2)
第一个地方写x轴,第二个地方写y的大小。两者不匹配会报错。
x轴接在一起
我想要两段x轴接在一起怎么办?比如x轴是20-30年,但是我有一组x=20-25的y和一组x=26-30的y
直接写进去就好了。
ax2.bar(year[0:14],delta_t[0:14],label='delta', linewidth=2,color='MediumSlateBlue',alpha=0.6)
ax2.bar(year[14:23],delta_t[14:23],label='delta', linewidth=2,color='MediumTurquoise',alpha=0.5)
(我不想放运行不成功的代码,在这段里,bar表示柱状图,其他与plot一样)
地图投影画方框(透明)
已经是地图投影了,就直接经纬度,然后四条直线画出方框
ax1.plot([1992.5,2001.4],[0.7,0.7],linestyle='-', color='b', linewidth=2.5)
ax1.plot([1992.5,2001.4],[-4.2,-4.2],linestyle='-', color='b', linewidth=2.5)
ax1.plot([1992.5,1992.5],[0.7,-4.2],linestyle='-', color='b', linewidth=2.5)
ax1.plot([2001.4,2001.4],[0.7,-4.2],linestyle='-', color='b', linewidth=2.5)
图例及其相关
ax1.legend(fontsize=18, frameon=False,loc=7)
条形图/柱状图
刚刚举了一个例子,再来一个:
ax2.bar(year,delta_t,label='delta', linewidth=2, color='MediumSlateBlue',alpha=0.6)
柱状图显示数值:
原文链接:https://blog.csdn.net/qq_35240689/article/details/126743893?spm=1001.2014.3001.5506
for bar in bars:
height = bar.get_height()
ax.annotate(f'{height+100:.1f}', xy=(bar.get_x() + bar.get_width() / 2, height),
fontsize=14, color='black',
xytext=(0, 4), textcoords='offset points', ha='center', va='bottom')
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_35240689/article/details/126743893
我自己也仿照写过:
baro=ax1.bar(np.arange(29)+0.05,pr3[1:],lw=0.6,color='k',label='Observation',width=0.3,alpha=0.7)
for bar in baro:
height = bar.get_height()
if height>=50:
ax1.annotate(f'{height:.1f}', xy=(bar.get_x() + bar.get_width() / 2, height),
fontsize=14, color='black',
xytext=(0, 4), textcoords='offset points', ha='center', va='bottom')
如果后面要接着调用,要给ax.bar命名。(示例中我命名为了baro)
柱状图对齐
barc=ax1.bar(np.arange(29)+0.35,cpr3[1:],lw=0.6,color='b',label='ctrl-rail',width=0.3,alpha=0.7)
bars=ax1.bar(np.arange(29)+0.65,spr3[1:],lw=0.6,color='r',label='sens-rail',width=0.3,alpha=0.7)
help(ax.bar)之后你可以查看,他是可以规定从调节align参数调节的,但是实际效果并不好。
我当时好像是想把barc的左半边和x轴0刻度线对齐,使用align参数、设置x轴对应的位置(np.arange(29)+0.35)均不能达到目的。最后是通过移动y轴相对位置达成了目的。
等值线填色图
噩梦起源。
cf=ax.contourf(x,y,t,transform=ccrs.PlateCarree(),cmap='Spectral_r',extend='max',
levels=np.arange(0,40,4),linewidths=0.8)
contourf是区域填色,contour是等值线填色,虽然我严重认可后者的颜值,但是前者更深得民心,日常应用也多为前者。
x和y就是一维数组,lat和lon,t是二维数组,两个维度形状应该分别和xy一致。transform就是投影方式。cmap是使用的颜色。
matplotlib自带颜色的链接:
https://blog.csdn.net/qq_43201025/article/details/131043840?spm=1001.2014.3001.5506
颜色自设定
然而实际应用中我们大多是自己写颜色条,我觉得导师不懂内置颜色的审美。双色条真的很好看啊。等值线图countourf颜色设定如下:
from matplotlib.cm import get_cmap
from matplotlib import cm, colors, ticker
proj = ccrs.PlateCarree()
colorlist = ['#000080','#4169E1','#6495ED','#87CEFA','#B0E0E6','#E1FFFF','#FFFACD','#FFD700','#FFA500','#FF7F50','#FF0000','#B22222']
# colorlist = ['海军蓝','皇军蓝','矢车菊','淡蓝色','火药蓝','淡青色','柠檬薄纱','金','橙色','珊瑚','纯红','耐火砖']
cf = ax1.contourf(lon, lat, t, colors=colorlist,transform=proj,extend='both')
colorbar
colorbar就是contourf的颜色条。我主要用到的是为colorbar设置位置。
cf1 = ax1.contourf(lonc, latc, mfdc, colors=colorlist3,levels=bounds2, transform=proj,extend='both')
axcb1=fig.add_axes([0.2,1.77,1.0,0.03])
cb1=plt.colorbar(cf1,fraction=0.05, pad=0.15,drawedges=True,orientation='horizontal',cax=axcb1)
axcb就是你可以设置colorbar的位置。
风场
风羽图
用的很少,对应的函数是ax.barb
箭头图
用的很多。我印象里基本上我画个矢量就是用它。风场也是一样。
cq=ax1.quiver(lon,lat,u,v,transform=ccrs.PlateCarree(),width=wid,scale=sca*1.5,color='black')
命名cq之后,矢量箭头可以不跟他画在同一张图上。比如我导的要求是在图内部的右下角添加空白条,然后画箭头。(添加空白图形/添加空白长方形)我的处理方法是添加了ax2后把quiverkey画在ax2上,再把ax2的坐标轴删除,即得到空白长方形。
key=ax2.quiverkey(cq,quiverleft,quiverright,quiverwind,label=quiverlabel,labelpos='E', coordinates='data')
注意这里的覆盖顺序,ax2优先覆盖在ax1上,如果在ax1上画quiverkey,就看不见。
我是不是越写越抽象了,我怀疑初学者看到这里可能有点懵圈。别急,你去看看我偶像,id摸鱼今天在摸鱼吗,在隔壁某站的教学视频,你就明白了。
流线图
画法和箭头图一样的,就是最后显示的结果是流线。ax.streamplot,我画过几次,因为我看不出辐合辐散,需要借助流线图。但是我导他们就纯看箭头图就明白了。嗯,所以说,这东西可能只对初学者有用吧。
文字
ax1.text(0.02, 0.9, "helloworld", fontsize=28, transform=ax1.transAxes, fontweight="bold")
文字设置上标
words=fig.text(0.53,1.57,s='10$^-$$^5$ kg/m$^2$·s',fontdict=None,fontsize=25)
$^2$就可以达成目的了。但是这个方法的劣势是一次只能修改一个上标字符。
更多方法参考:https://blog.csdn.net/qq_57313910/article/details/132699247?spm=1001.2014.3001.5506
坐标轴
这段代码是我从师兄那边抄过来的。大意为设置画图时的基础字体和大小。遇到很难找到代码的(比如说quiverkey的字体大小)这类的设置,就可以直接改动这一部分。节省很多事。
plt.rcParams['font.weight'] = 'bold'
plt.rcParams['font.family'] = 'Times New Roman'
plt.rcParams['font.size'] = 25
内容较多,可通过小标题查询
隐藏坐标轴
ax2.get_xaxis().set_visible(False) # 隐藏x坐标轴
ax2.get_yaxis().set_visible(False) # 隐藏y坐标轴
隐藏边界线
ax.spines['top'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['right'].set_visible(False)
我还看到可以设置坐标轴的宽度为0的方法,理论上也应该可以达成目的。
设置坐标轴粗细
ax1.spines['bottom'].set_linewidth(2) ###设置底部坐标轴的粗细
ax1.spines['left'].set_linewidth(2) ####设置左边坐标轴的粗细
地图投影
很不负责地说,每次地图投影的坐标轴我都是以下这段代码整段搬上去的。他们好像功能重复了又好像没重复。
import matplotlib.pyplot as plt
import cartopy.mpl.ticker as cticker
import cartopy.feature as cfeat
import cartopy.crs as ccrs
lat_formatter=cticker.LatitudeFormatter()
lon_formatter=cticker.LongitudeFormatter()
ax1.xaxis.set_major_formatter(lon_formatter)
ax1.yaxis.set_major_formatter(lat_formatter)
ax1.set_xticks(np.arange(leftlon,rightlon+0.1,5),crs=ccrs.PlateCarree())
ax1.set_yticks(np.arange(lowerlat,upperlat+0.1,2),crs=ccrs.PlateCarree())
后面两个是设置坐标间距。
设置地图投影的范围
leftlon,rightlon,lowerlat,upperlat=( 70 , 110 , 20 , 45 )
img_extent=[leftlon,rightlon,lowerlat,upperlat]
ax3.set_extent(img_extent)
设置x轴y轴轴题
plt.xlabel("",fontsize=28, fontname="Times New Roman") #fontweight="bold"
plt.ylabel("",fontsize=28, fontname="Times New Roman") #fontweight="bold"
自定义x轴/y轴
point = []
print(len(rain))
for i in range(0, len(rain), 24):
iday = int(day + (hour + i) / 24)
ihour = (hour + i) % 24
point.append('%02d' % (iday))
ax.set_xlim(0, len(rain) - 1)
ax.set_xticks(range(0, len(rain), 24))
ax.set_xticklabels(point, fontsize=35, rotation=0, fontname="Times New Roman",fontweight="bold")
这段代码的意思呢,就是我写了个列表,然后大概是x月x日,这样,来命名x轴。
重点将我的列表设置成x轴的那个参数是『ax.set_xticklabels』。y轴只需要x改成y。
修改x轴/y轴字体、大小
ax.set_xlabel("date", fontsize=45, fontname="Times New Roman", labelpad=20., fontweight="bold")
ax.set_ylabel('precipitation(mm)', fontsize=45, fontname="Times New Roman",labelpad=30.,fontweight="bold")
设置x轴、y轴刻度与轴字的间距
ax.tick_params(axis='x', width=2, colors='k', length=12, pad=9)
ax.tick_params(axis='y', width=2, colors='k', length=12, pad=9)
脆皮女大困了,,,加油,,,
设置x轴,y轴位置
就是零刻线位置,使他们对齐。我语言表述系统开始bug了。
ax1.spines['left'].set_position(('data',-2))
ax1.spines['top'].set_position(('data',600))
这是给了我类似帮助的一篇干货:https://blog.csdn.net/houston12138/article/details/136403329?spm=1001.2014.3001.5506
看到这里辛苦你了也辛苦我了
不知不觉我竟然已经倾囊尽授(好吧,不是这样用的)已经江郎才尽了,加油,我们的路都很长,这里是我一小段旅途的歇脚之处,也是未来的路继续向前的信心来源(写这么长的干货给我提供的情绪价值真的很饱满好吧)祝读者和我都能一帆风顺,前途似锦。
ps. 第一次用,不知道博客可不可以修改,后面如果有补充我尽量更新到这篇上。