气象处理技巧—时间序列处理4

文摘   2024-08-27 08:02   北京  

时间序列处理4

本节是时间序列处理的最后一个章节,主要是如何在使用matplotlib定制化时间显示的梯度、格式,以使出图更加方便、美观。前几章都是如何对时间序列进行操作,而本节则是将数据可视化过程中一些常见定制时间显示模式进行简单介绍。

xarray中的dt功能对时间的格式化

在前面章节中,我们已经多次使用过xarray的dt下的功能,对时间序列进行处理了。dt还有strftime功能,用于对时间序列的格式化。格式化后的time项,将可以直接使用在matplotlib的绘图命令中。
我们首先读取一个精确到纳秒的文件:

import xarray as xr
file=r'C:\Users\Administrator\Desktop\20230703_pp.grib'
ds=xr.open_dataset(file)
ds

这样的时间序列,实际上是非常不方便的,客观上来说,气象研究基本不可能使用这么精确的数字,即便有,也是常人用不了的,同时为了在后续的使用中方便识读,我们就可以使用dt.strftime功能将他格式化,这里使用的实际是一份再分析逐小时资料,所以我们将格式化的最小单位设计为小时。

Time=ds['time'].dt.strftime('%m月%d日%H时')
Time

格式化后,数据变为简洁有力的中式表达方法。同时,matplotlib可以识别经过标准格式化的时间序列:

Time=ds['time'].dt.strftime('%m月%d日%H时')
Q=ds['q'].loc[:,850,40,108]
ax=plt.figure(figsize=(4,2),dpi=400).add_axes([0,0,1,1])
ax.plot(Time,Q,)
ax.set_xticks(Time[::6])
ax.tick_params(labelrotation=45)

使用标准格式化的时间序列,matplotlib可以直接识别,不用进一步定制坐标轴标签格式了。
格式化的关键是%后带的各种字母,带有不一样的含义,而中文,或者其他合法字符不关键,比如我还可以使用短横线代替中文的年月日:

Time=ds['time'].dt.strftime('%Y-%m-%d-%H')
Time

下面罗列了一些常用的格式化符号:

格式化符号格式化时间备注
%Yyear的大写,四位数年,如1995年
%yyear,两位数的年,如95年
%mmonth
%dday
%Hhour的大写
%Mminute的大写
%Ssecond的大写

但是要注意,这种方法是生成了一个新的时间数组strftime(见图中),并没有改变time的原值。原值的dtype是datetime64,而新生成的strftime实际dtype是object。我们是将他变成了符合国人习惯的表达方式而已。该种方法使我们在使用再分析资料绘制时间高度变化图,时间纬度变化图时,更加方便,比如按照上面数据,我们来绘制一个(109°E,40°N)上空,比湿的时间——高度变化图:

Time=ds['time'].dt.strftime('%m月%d日%H时')
Q=ds['q'].loc[:,:,40,109]
ax=plt.figure(figsize=(4,2),dpi=400).add_axes([0,0,1,1])
level=np.arange(0,24,2)
ac=ax.contour(Time,Q.isobaricInhPa,Q.values.T*1000,levels=level,colors='k',linewidths=0.3)
ax.contourf(Time,Q.isobaricInhPa,Q.values.T*1000,levels=level,cmap='Blues')
ax.clabel(ac,fontsize=7)
ax.invert_yaxis()
ax.set_yticks([1000,925,850,700,500,300,200,100])
ax.set_ylim(1000,100)
ax.tick_params(labelsize=6)
ax.set_xticks(Time[::6])
ax.tick_params(labelrotation=45,axis='x')

上图可以简单看出比湿经历了一个回落的过程,到4号00时以后,比湿下降到一个较低的水平。当然,这里还是世界时,要变成北京时,可以参考时间序列处理1里面的内容。

matplotlib中的date模块对时间的格式化

通过matplotlib.date模块,我们可以实现matplotlib内部定制化时间序列。还是从实例出发,为了和上面xarray的方式进行区别,我们使用pandas来生成一年份的时间序列。

import pandas as pd
time=pd.date_range(start='2023-01-01',periods=365,freq='D')
data=np.random.rand(365)*10
ax=plt.figure(figsize=(4,2),dpi=400).add_axes([0,0,1,1])
ax.plot(time,data,lw=0.5)

在默认情况下,matplotlib可以优化横坐标轴的时间分布,但是一般不太符合实际,一般一年中,取每月第一天作为横坐标轴。当然,最原始的方法是结合set_xticks、set_xticklabels两个定制时间格式化:

ax.set_xticks(np.array(['2023-01-01','2023-02-01','2023-03-01','2023-04-01',
                        '2023-05-01','2023-06-01','2023-07-01','2023-08-01',
                        '2023-09-01','2023-10-01','2023-11-01','2023-12-01']))

不过,我们也可以通过date模块的结合来定制化时间显示,这个的底层原理是使用坐标轴的formatter功能,进行时间标准化,下面第一个是将中文加入到时间格式化里:

import matplotlib.dates as mdates
ax.set_xticks(pd.date_range(end='2023-12',periods=12,freq='MS'))
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y年%m月%d日'))

核心语句是三段,第一段导入模块,第二段指定要显示的刻度,这里我们生成了每个月的一号,第三段类似xarray中的方法,格式化时间。其实所有时间格式都可以用strftime,只是在每个库包中引用的地方不一样而已。
dates模块中,还有一个定位器locator,可以帮助我们快速定位:

ax.xaxis.set_major_locator(mdates.MonthLocator())
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y年%m月%d日'))
ax.set_xlim(time[0],time[-1])

MonthLocator定位器,可以定位到每个月的指定日期,默认是每个月第一天。要显示的月份、日期可以随意指定,例如:

ax.xaxis.set_major_locator(mdates.MonthLocator(bymonth=[1,2,3,7,8,9], bymonthday=15))
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y年%m月%d日'))
ax.set_xlim(time[0],time[-1])

上面实现了指定月份的15日的显示。
当然,如果要显示的月份、要显示的日期完全不一样,这些定制化方法就不行了,只能手动定制。在mdates中还有许多定位器,比如SecondLocator、YearLocator、MinuteLocator、HourLocator等,可以实现不同的定位效果,读者可以自行尝试。
当然,越漂亮的图,代码必然更多,定制化代码也更多,上面仅是批量化处理时间格式一个比较方便的方法。

欢迎关注云台书使公众号获取更多咨询


气python风雨
主要发一些涉及大气科学的Python文章与个人学习备忘录
 最新文章