使用时间戳超过 2263 年的 xarray 创建 netcdf
create netcdf using xarray with time stamp beyond year 2263
有没有办法使用 xarray 创建时间维度超过 2263 年的 netCDF 文件?
以下是创建 netCDF 玩具数据集的方法 http://xarray.pydata.org/en/stable/time-series.html
但是时间维度具有 pandas 日期时间索引类型,并且不会超出 2263,如下所示:
https://github.com/pandas-dev/pandas/issues/13346
问题可能是 xarray 在 datetime.datetime 范围之外的时间选择性地使用 netcdftime,但 pandas 没有。所以,即使安装了 netcdftime,像这个例子这样的东西也行不通
import numpy as np
import pandas as pd
import xarray as xr
data = np.random.rand(4, 3)
locs = ['IA', 'IL', 'IN']
times = pd.date_range('2318-04-25', periods=4)
da = xr.DataArray(data, coords=[times, locs], dims=['time', 'space'])
当您尝试创建 pandas date_range 时,这将失败。即使提供 netcdftime.datetime 作为 pd.date_range() 的第一个参数也不起作用,因为 pandas 想要转换为它自己的有限日期时间类型。
相反,您需要直接向 xarray 指定时间。不幸的是,这是我对 netcdf 的了解让我失望的地方,但我可以给你大纲,也许你可以从这里得到它。
有多种方法可以在 DataArray 参数中指定日期。您需要使用 netcdftime.datetime 类型作为基础来创建自己的日期范围。您可以使用 netcdftime.date2index() 创建日期索引,并使用它代替上面示例中的 pandas DateIndex。
您可能应该 post 显示问题的示例代码。我假设您正在尝试创建 DataArray,但也许这不是您遇到的问题。
将来,您可以通过使用 cftime
对象创建日期轴来实现此目的,但就目前而言,有一个 outstanding issue in xarray
不允许您编写 netCDF包含此类对象的文件。
但是,即使您可以保存此类对象,最简单、最简洁的方法仍然是手动将该轴定义为具有某些单位的整数数组。
import numpy as np
import xarray as xr
days = np.asarray(range(100*365))
ds = xr.Dataset(
{'time': (['time'], days, {'units': 'days since 2200-01-01 0:0:0'})}
)
print(ds['time'][-1]
ds.to_netcdf('test.nc')
ds = xr.open_dataset('test.nc')
print(ds['time'][-1])
给出输出
<xarray.DataArray 'time' ()>
array(36499)
Coordinates:
time int64 36499
Attributes:
units: days since 2200-01-01 0:0:0
接着是
<xarray.DataArray 'time' ()>
array(datetime.datetime(2299, 12, 7, 0, 0), dtype=object)
Coordinates:
time object 2299-12-07
请注意,当您重新打开数据集时,xarray 会自动对其进行解码。
您使用的 'units' 属性应该在时间坐标的 CF conventions 之后。您可以根据需要将 'days' 替换为 'hours'、'minutes' 或 'seconds'。
这确实需要您手动计算所需的整数,如果您的时间轴以年为单位,这主要是困难的(因为 "year" 不是定义的时间度量单位,它的长度因闰年而异-年)。如果是这种情况,您可以使用如下内容:
import cftime
# replace this to use a different calendar
Datetime = cftime.DatetimeProlepticGregorian
# make your list of Datetime objects
time_list = []
month = day = 1
hour = minute = second = 0
for year in range(2200, 2300, 1):
time_list.append(Datetime(year, month, day, hour, minute, second))
# this will convert them into a time axis, here in units of
# 'days since 2200-01-01 0:0:0'
seconds_in_day = 60*60*24
day_list = []
for dt in time_list:
time_since_2200 = dt - Datetime(2200, month, day, hour, minute, second)
day_list.append(int(time_since_2200.total_seconds() / seconds_in_day))
您可以使用不同的 cftime
class(例如 cftime.DatetimeJulian
或 cftime.DatetimeNoLeap
)来使用不同的日历。应修改此代码以提供正确的 time_list
供您使用。您还可以在其他时间单位中关闭 seconds_in_day
秒(并将该单位提供给 xr.Dataset
调用)。
有没有办法使用 xarray 创建时间维度超过 2263 年的 netCDF 文件?
以下是创建 netCDF 玩具数据集的方法 http://xarray.pydata.org/en/stable/time-series.html
但是时间维度具有 pandas 日期时间索引类型,并且不会超出 2263,如下所示: https://github.com/pandas-dev/pandas/issues/13346
问题可能是 xarray 在 datetime.datetime 范围之外的时间选择性地使用 netcdftime,但 pandas 没有。所以,即使安装了 netcdftime,像这个例子这样的东西也行不通
import numpy as np
import pandas as pd
import xarray as xr
data = np.random.rand(4, 3)
locs = ['IA', 'IL', 'IN']
times = pd.date_range('2318-04-25', periods=4)
da = xr.DataArray(data, coords=[times, locs], dims=['time', 'space'])
当您尝试创建 pandas date_range 时,这将失败。即使提供 netcdftime.datetime 作为 pd.date_range() 的第一个参数也不起作用,因为 pandas 想要转换为它自己的有限日期时间类型。
相反,您需要直接向 xarray 指定时间。不幸的是,这是我对 netcdf 的了解让我失望的地方,但我可以给你大纲,也许你可以从这里得到它。
有多种方法可以在 DataArray 参数中指定日期。您需要使用 netcdftime.datetime 类型作为基础来创建自己的日期范围。您可以使用 netcdftime.date2index() 创建日期索引,并使用它代替上面示例中的 pandas DateIndex。
您可能应该 post 显示问题的示例代码。我假设您正在尝试创建 DataArray,但也许这不是您遇到的问题。
将来,您可以通过使用 cftime
对象创建日期轴来实现此目的,但就目前而言,有一个 outstanding issue in xarray
不允许您编写 netCDF包含此类对象的文件。
但是,即使您可以保存此类对象,最简单、最简洁的方法仍然是手动将该轴定义为具有某些单位的整数数组。
import numpy as np
import xarray as xr
days = np.asarray(range(100*365))
ds = xr.Dataset(
{'time': (['time'], days, {'units': 'days since 2200-01-01 0:0:0'})}
)
print(ds['time'][-1]
ds.to_netcdf('test.nc')
ds = xr.open_dataset('test.nc')
print(ds['time'][-1])
给出输出
<xarray.DataArray 'time' ()>
array(36499)
Coordinates:
time int64 36499
Attributes:
units: days since 2200-01-01 0:0:0
接着是
<xarray.DataArray 'time' ()>
array(datetime.datetime(2299, 12, 7, 0, 0), dtype=object)
Coordinates:
time object 2299-12-07
请注意,当您重新打开数据集时,xarray 会自动对其进行解码。
您使用的 'units' 属性应该在时间坐标的 CF conventions 之后。您可以根据需要将 'days' 替换为 'hours'、'minutes' 或 'seconds'。
这确实需要您手动计算所需的整数,如果您的时间轴以年为单位,这主要是困难的(因为 "year" 不是定义的时间度量单位,它的长度因闰年而异-年)。如果是这种情况,您可以使用如下内容:
import cftime
# replace this to use a different calendar
Datetime = cftime.DatetimeProlepticGregorian
# make your list of Datetime objects
time_list = []
month = day = 1
hour = minute = second = 0
for year in range(2200, 2300, 1):
time_list.append(Datetime(year, month, day, hour, minute, second))
# this will convert them into a time axis, here in units of
# 'days since 2200-01-01 0:0:0'
seconds_in_day = 60*60*24
day_list = []
for dt in time_list:
time_since_2200 = dt - Datetime(2200, month, day, hour, minute, second)
day_list.append(int(time_since_2200.total_seconds() / seconds_in_day))
您可以使用不同的 cftime
class(例如 cftime.DatetimeJulian
或 cftime.DatetimeNoLeap
)来使用不同的日历。应修改此代码以提供正确的 time_list
供您使用。您还可以在其他时间单位中关闭 seconds_in_day
秒(并将该单位提供给 xr.Dataset
调用)。