Python 2.7 “时变单位”;日期为%Y%m%d.%f“;在python iris中
我希望有人能帮忙。我正在使用iris在python中运行一些气候模型(NetCDF文件)。在我添加了格式不同的最后一个模型之前,一切都很顺利。在新型号中,他们用于时间变量的单位是Python 2.7 “时变单位”;日期为%Y%m%d.%f“;在python iris中,python-2.7,python-iris,Python 2.7,Python Iris,我希望有人能帮忙。我正在使用iris在python中运行一些气候模型(NetCDF文件)。在我添加了格式不同的最后一个模型之前,一切都很顺利。在新型号中,他们用于时间变量的单位是天,为%Y%m%d.%f,但在其他型号中,则是天,因为…。这意味着,当我试图约束时间变量时,会出现以下错误AttributeError:'numpy.float64'对象没有属性'year'。 我尝试使用iriscc添加年份变量。添加年(EARTH3,'time'),但这只会导致错误“单位有未定义的日历” 我想知道你是否
天,为%Y%m%d.%f
,但在其他型号中,则是天,因为…
。这意味着,当我试图约束时间变量时,会出现以下错误AttributeError:'numpy.float64'对象没有属性'year'
。
我尝试使用iriscc添加年份变量。添加年(EARTH3,'time'),但这只会导致错误“单位有未定义的日历”
我想知道你是否知道我该如何解决这个问题?我需要转换日历类型吗?还是有办法解决这个问题?我不知道该怎么做
谢谢大家!!
埃里卡
编辑:这是我的文件的完整代码模型CanESM2正在工作,但模型EARTH3没有-它是一个有趣的时间单位
import matplotlib.pyplot as plt
import iris
import iris.coord_categorisation as iriscc
import iris.plot as iplt
import iris.quickplot as qplt
import iris.analysis.cartography
import cf_units
from cf_units import Unit
import datetime
import numpy as np
def main():
#-------------------------------------------------------------------------
#bring in all the GCM models we need and give them a name
CanESM2= '/exports/csce/datastore/geos/users/s0XXXX/Climate_Modelling/GCM_data/tasmin_Amon_CanESM2_historical_r1i1p1_185001-200512.nc'
EARTH3= '/exports/csce/datastore/geos/users/s0XXXX/Climate_Modelling/GCM_data/tas_Amon_EC-EARTH_historical_r3i1p1_1850-2009.nc'
#Load exactly one cube from given file
CanESM2 = iris.load_cube(CanESM2)
EARTH3 = iris.load_cube(EARTH3)
print"CanESM2 time"
print (CanESM2.coord('time'))
print "EARTH3 time"
print (EARTH3.coord('time'))
#fix EARTH3 time units as they differ from all other models
t_coord=EARTH3.coord('time')
t_unit = t_coord.attributes['invalid_units']
timestep, _, t_fmt_str = t_unit.split(' ')
new_t_unit_str= '{} since 1850-01-01 00:00:00'.format(timestep)
new_t_unit = cf_units.Unit(new_t_unit_str, calendar=cf_units.CALENDAR_STANDARD)
new_datetimes = [datetime.datetime.strptime(str(dt), t_fmt_str) for dt in t_coord.points]
new_dt_points = [new_t_unit.date2num(new_dt) for new_dt in new_datetimes]
new_t_coord = iris.coords.DimCoord(new_dt_points, standard_name='time', units=new_t_unit)
print "EARTH3 new time"
print (EARTH3.coord('time'))
#regrid all models to have same latitude and longitude system, all regridded to model with lowest resolution
CanESM2 = CanESM2.regrid(CanESM2, iris.analysis.Linear())
EARTH3 =EARTH3.regrid(CanESM2, iris.analysis.Linear())
#we are only interested in the latitude and longitude relevant to Malawi (has to be slightly larger than country boundary to take into account resolution of GCMs)
Malawi = iris.Constraint(longitude=lambda v: 32.0 <= v <= 36., latitude=lambda v: -17. <= v <= -8.)
CanESM2 =CanESM2.extract(Malawi)
EARTH3 =EARTH3.extract(Malawi)
#time constraignt to make all series the same, for ERAINT this is 1990-2008 and for RCMs and GCMs this is 1961-2005
iris.FUTURE.cell_datetime_objects = True
t_constraint = iris.Constraint(time=lambda cell: 1961 <= cell.point.year <= 2005)
CanESM2 =CanESM2.extract(t_constraint)
EARTH3 =EARTH3.extract(t_constraint)
#Convert units to match, CORDEX data is in Kelvin but Observed data in Celsius, we would like to show all data in Celsius
CanESM2.convert_units('Celsius')
EARTH3.units = Unit('Celsius') #this fixes EARTH3 which has no units defined
EARTH3=EARTH3-273 #this converts the data manually from Kelvin to Celsius
#add year data to files
iriscc.add_year(CanESM2, 'time')
iriscc.add_year(EARTH3, 'time')
#We are interested in plotting the data by year, so we need to take a mean of all the data by year
CanESM2YR=CanESM2.aggregated_by('year', iris.analysis.MEAN)
EARTH3YR = EARTH3.aggregated_by('year', iris.analysis.MEAN)
#Returns an array of area weights, with the same dimensions as the cube
CanESM2YR_grid_areas = iris.analysis.cartography.area_weights(CanESM2YR)
EARTH3YR_grid_areas = iris.analysis.cartography.area_weights(EARTH3YR)
#We want to plot the mean for the whole region so we need a mean of all the lats and lons
CanESM2YR_mean = CanESM2YR.collapsed(['latitude', 'longitude'], iris.analysis.MEAN, weights=CanESM2YR_grid_areas)
EARTH3YR_mean = EARTH3YR.collapsed(['latitude', 'longitude'], iris.analysis.MEAN, weights=EARTH3YR_grid_areas)
#-------------------------------------------------------------------------
#PART 4: PLOT LINE GRAPH
#limit x axis
plt.xlim((1961,2005))
#assign the line colours and set x axis to 'year' rather than 'time'
qplt.plot(CanESM2YR_mean.coord('year'), CanESM2YR_mean, label='CanESM2', lw=1.5, color='blue')
qplt.plot(EARTH3YR_mean.coord('year'), EARTH3YR_mean, label='EC-EARTH (r3i1p1', lw=1.5, color='magenta')
#set a title for the y axis
plt.ylabel('Near-Surface Temperature (degrees Celsius)')
#create a legend and set its location to under the graph
plt.legend(loc="upper center", bbox_to_anchor=(0.5,-0.05), fancybox=True, shadow=True, ncol=2)
#create a title
plt.title('Tas for Malawi 1961-2005', fontsize=11)
#add grid lines
plt.grid()
#show the graph in the console
iplt.show()
if __name__ == '__main__':
main()
导入matplotlib.pyplot作为plt
进口虹膜
导入iris.coord_分类为iriscc
将iris.plot导入为iplt
将iris.quickplot导入为qplt
导入iris.analysis.Maptography
导入CFU单元
从cf_单元导入单元
导入日期时间
将numpy作为np导入
def main():
#-------------------------------------------------------------------------
#带上我们需要的所有GCM模型,并给它们命名
CanESM2='/exports/csce/datastore/geos/users/s0XXXX/Climate_modeling/GCM_data/tasmin_Amon_CanESM2_history_r1p1_185001-200512.nc'
EARTH3='/exports/csce/datastore/geos/users/s0XXXX/Climate_modeling/GCM_data/tas_Amon_EC-EARTH_history_r3i1p1_1850-2009.nc'
#从给定文件中只加载一个多维数据集
CanESM2=iris.load\u多维数据集(CanESM2)
EARTH3=iris.load\u立方体(EARTH3)
打印“CanESM2次”
打印(CanESM2.coord('time'))
打印“地球3次”
打印(EARTH3.coord(“时间”))
#固定EARTH3时间单位,因为它们不同于所有其他型号
t_coord=EARTH3.coord(‘时间’)
t_单位=t_坐标属性['invalid_单位']
timestep,u,t_fmt_str=t_unit.split(“”)
自1850-01-01 00:00:00以来的新单位{}。格式(时间步)
新单位=cf单位。单位(新单位,日历=cf单位。日历标准)
new_datetimes=[datetime.datetime.strtime(str(dt),t_fmt_str)表示t_坐标点中的dt]
new_dt_points=[new_t_unit.date2num(new_dt)表示new_dt在new_datetimes中]
新的坐标=iris.coords.DimCoord(新的坐标点,标准的时间,单位=新的单位)
打印“地球3新时间”
打印(EARTH3.coord(“时间”))
#将所有模型重新划分为具有相同的纬度和经度系统,所有模型重新划分为具有最低分辨率的模型
CanESM2=CanESM2.reglid(CanESM2,iris.analysis.Linear())
EARTH3=EARTH3.regrid(CanESM2,iris.analysis.Linear())
#我们只对与马拉维相关的纬度和经度感兴趣(考虑到GCMs的分辨率,必须略大于国家边界)
马拉维=iris.Constraint(经度=lambda v:32.0在iris中,时间坐标的单位字符串必须以格式指定,因为
是时间的度量单位,例如“天”或“年”。iris库使用此格式提供有效单位并执行单位转换
在这种情况下,时间坐标没有遵循此格式的单位,这意味着时间坐标将没有完整的时间坐标功能(这部分解释了问题中的属性错误)。要解决此问题,我们需要基于现有时间坐标的值和元数据构建新的时间坐标,然后用新的时间坐标替换多维数据集的现有时间坐标
为此,我们需要:
基于现有时间单位中包含的元数据构造新的时间单位
使用现有时间单位中指定的格式字符串,获取现有时间坐标的点值并将其格式化为datetime对象
使用(1)中构造的新时间单位将datetime对象从(2)转换为浮点数数组
根据(3)中构造的数组和(1)中生成的新时间单位创建新的时间坐标
从多维数据集中删除旧的时间坐标,然后添加新的时间坐标
下面是执行此操作的代码
import datetime
import cf_units
import iris
import numpy as np
t_coord = EARTH3.coord('time')
t_unit = t_coord.attributes['invalid_units']
timestep, _, t_fmt_str = t_unit.split(' ')
new_t_unit_str = '{} since 1850-01-01 00:00:00'.format(timestep)
new_t_unit = cf_units.Unit(new_t_unit_str, calendar=cf_units.CALENDAR_STANDARD)
new_datetimes = [datetime.datetime.strptime(str(dt), t_fmt_str) for dt in t_coord.points]
new_dt_points = [new_t_unit.date2num(new_dt) for new_dt in new_datetimes]
new_t_coord = iris.coords.DimCoord(new_dt_points, standard_name='time', units=new_t_unit)
t_coord_dim = cube.coord_dims('time')
cube.remove_coord('time')
cube.add_dim_coord(new_t_coord, t_coord_dim)
我已经为您的时间数据做了一个关于最佳纪元的假设。我也对最能描述您的数据的日历做了一个假设,但是您应该能够(在构建新的\u\u单位
时)将我选择的标准日历替换为任何其他有效的cf\u单位
日历
最后一点,实际上不可能更改日历类型。这是因为不同的日历类型包含和排除不同的日期。例如,360天的日历有2月30日,但没有5月31日(因为它假设12个理想化的30天长的月)。如果您尝试将360天日历转换为标准日历,您遇到的问题包括如何处理2月29日和30日的数据,以及如何填充360天日历中不存在的五天。由于这些原因,通常无法转换日历(Iris不允许此类操作)
希望这能有所帮助!也许答案没有多大用处,但我在这里写了一个函数,该函数是我为了转换datetime数组中%Y%m%d.%f的数据而创建的
函数创建一个完美的datetime数组,没有丢失的值,可以修改它以考虑是否有丢失的时间,但是气候模型不应该有丢失的数据
def fromEARTHtime2Datetime(dt,timeVecEARTH):
"""
This function returns the perfect array from the EARTH %Y%m%d.%f time
format and convert it to a more useful time, such as the time array
from the datetime of pyhton, this is WHTOUT any missing data!
Parameters
----------
dt : string
This is the time discretization, it can be 1h or 6h, but always it
needs to be hours, example dt = '6h'.
timeVecEARTH : array of float
Vector of the time to be converted. For example the time of the
EARTH is day as %Y%m%d.%f.
And only this format can be converted to datetime, for example:
20490128.0,20490128.25,20490128.5,20490128.75 this will be converted
in datetime: '2049-01-28 00:00:00', '2049-01-28 60:00:00',
'2049-01-28 12:00:00','2049-01-28 18:00:00'
Returns
-------
timeArrNew : datetime
This is the perfect and WITHOUT any missing data datatime array,
for example: DatetimeIndex(['2049-01-28 00:00:00', '2049-01-28 06:00:00',
...
'2049-02-28 18:00:00', '2049-03-01 00:00:00'],
dtype='datetime64[ns]', length=129, freq='6H')
"""
dtDay = 24/np.float(dt[:-1])
partOfDay = np.arange(0,1,1/dtDay)
hDay = []
for ip in partOfDay:
hDay.append('%02.f:00:00' %(24*ip))
dictHours = dict(zip(partOfDay,hDay))
t0Str = str(timeVecEARTH[0])
timeAux0 = t0Str.split('.')
timeAux0 = timeAux0[0][0:4] +'-' + timeAux0[0][4:6] +'-' + timeAux0[0][6:] + ' ' + dictHours[float(timeAux0[1])]
tendStr = str(timeVecEARTH[-1])
timeAuxEnd = tendStr.split('.')
timeAuxEnd = timeAuxEnd[0][0:4] +'-' + timeAuxEnd[0][4:6] +'-' + timeAuxEnd[0][6:] + ' ' + dictHours[float(timeAuxEnd[1])]
timeArrNew = pd.date_range(timeAux0,timeAuxEnd, freq=dt)
return timeArrNew
您好@ErikaAWT–这是一个非常有趣的问题!我想我有一个解决方案,我将在近期发布,但为了帮助我使解决方案尽可能准确,您能用打印出的多维数据集的时间坐标更新您的问题吗?