Note
Go to the end to download the full example code. or to run this example in your browser via Binder
Axis¶
These objects manipulate axes as they can be found in NetCDF files:
float lat(lat) ;
lat:long_name = "latitude" ;
lat:units = "degrees_north" ;
lat:standard_name = "latitude" ;
float lon(lon) ;
lon:long_name = "longitude" ;
lon:units = "degrees_east" ;
lon:standard_name = "longitude" ;
Regular axis¶
For example, let’s construct an axis representing a regular axis.
import numpy
import pyinterp
axis = pyinterp.Axis(numpy.arange(-90, 90, 0.25))
print(axis)
<pyinterp.core.Axis>
min_value: -90
max_value: 89.75
step : 0.25
is_circle: false
This object can be queried to obtain its properties.
print(f'is ascending ? {axis.is_ascending()}')
print(f'is regular ? {axis.is_regular()}')
print(f'is circle ? {axis.is_circle}')
is ascending ? True
is regular ? True
is circle ? False
The most useful interfaces allow you to search for the index of the closest value.
axis.find_index([1e-3])
array([360])
It is also possible to find the indices around a value.
axis.find_indexes([1e-3])
array([[360, 361]])
The list of available methods is described in the online help
.
Irregular axis¶
When the axis is regular, the pitch is constant between each element of the axis, the search is performed using a simple calculation and therefore very fast. When the pitch is not constant between two successive elements of the axis, the search is performed by a binary search. Even these two operating modes are managed by the same object. So let’s build an irregular axis:
MERCATOR_LATITUDES = numpy.array([
-89.000000, -88.908818, -88.809323, -88.700757, -88.582294, -88.453032,
-88.311987, -88.158087, -87.990161, -87.806932, -87.607008, -87.388869,
-87.150861, -86.891178, -86.607851, -86.298736, -85.961495, -85.593582,
-85.192224, -84.754402, -84.276831, -83.755939, -83.187844, -82.568330,
-81.892820, -81.156357, -80.353575, -79.478674, -78.525397, -77.487013,
-76.356296, -75.125518, -73.786444, -72.330344, -70.748017, -69.029837,
-67.165823, -65.145744, -62.959262, -60.596124, -58.046413, -55.300856,
-52.351206, -49.190700, -45.814573, -42.220632, -38.409866, -34.387043,
-30.161252, -25.746331, -21.161107, -16.429384, -11.579629, -6.644331,
-1.659041, 3.338836, 8.311423, 13.221792, 18.035297, 22.720709, 27.251074,
31.604243, 35.763079, 39.715378, 43.453560, 46.974192, 50.277423,
53.366377, 56.246554, 58.925270, 61.411164, 63.713764, 65.843134,
67.809578, 69.623418, 71.294813, 72.833637, 74.249378, 75.551083,
76.747318, 77.846146, 78.855128, 79.781321, 80.631294, 81.411149,
82.126535, 82.782681, 83.384411, 83.936179, 84.442084, 84.905904,
85.331111, 85.720897, 86.078198, 86.405707, 86.705898, 86.981044,
87.233227, 87.464359, 87.676195, 87.870342, 88.048275, 88.211348,
88.360799, 88.497766, 88.623291, 88.738328, 88.843755, 88.940374
])
axis = pyinterp.Axis(MERCATOR_LATITUDES)
print(axis)
<pyinterp.core.Axis>
values : [-89. -88.908818 -88.809323 -88.700757 -88.582294 -88.453032
-88.311987 -88.158087 -87.990161 -87.806932 -87.607008 -87.388869
-87.150861 -86.891178 -86.607851 -86.298736 -85.961495 -85.593582
-85.192224 -84.754402 -84.276831 -83.755939 -83.187844 -82.56833
-81.89282 -81.156357 -80.353575 -79.478674 -78.525397 -77.487013
-76.356296 -75.125518 -73.786444 -72.330344 -70.748017 -69.029837
-67.165823 -65.145744 -62.959262 -60.596124 -58.046413 -55.300856
-52.351206 -49.1907 -45.814573 -42.220632 -38.409866 -34.387043
-30.161252 -25.746331 -21.161107 -16.429384 -11.579629 -6.644331
-1.659041 3.338836 8.311423 13.221792 18.035297 22.720709
27.251074 31.604243 35.763079 39.715378 43.45356 46.974192
50.277423 53.366377 56.246554 58.92527 61.411164 63.713764
65.843134 67.809578 69.623418 71.294813 72.833637 74.249378
75.551083 76.747318 77.846146 78.855128 79.781321 80.631294
81.411149 82.126535 82.782681 83.384411 83.936179 84.442084
84.905904 85.331111 85.720897 86.078198 86.405707 86.705898
86.981044 87.233227 87.464359 87.676195 87.870342 88.048275
88.211348 88.360799 88.497766 88.623291 88.738328 88.843755
88.940374]
is_circle: false
Let’s display its properties.
print(f'is ascending ? {axis.is_ascending()}')
print(f'is regular ? {axis.is_regular()}')
print(f'is circle ? {axis.is_circle}')
is ascending ? True
is regular ? False
is circle ? False
It is possible to query this axis as before.
axis.find_index([1e-3])
array([54])
Longitude¶
It is also possible to represent longitudes going around the earth, i.e. making a circle.
axis = pyinterp.Axis(numpy.arange(0, 360, 1), is_circle=True)
print(axis)
<pyinterp.core.Axis>
min_value: 0
max_value: 359
step : 1
is_circle: true
In this case, you don’t have to worry about the bounds of the axis.
axis.find_index([-180]), axis.find_index([180])
(array([180]), array([180]))
TemporalAxis¶
Time axes allow for manipulating axes representing dates or time differences. These objects are specialized to handle the 64-bit integers used by numpy to describe dates without losing information during calculations. In a netCDF file these axes are described as follows:
double time(time) ;
time:long_name = "time" ;
time:units = "days since 1990-1-1 0:0:0" ;
Note
These axes can be regular or irregular as before.
dates = numpy.datetime64('2020-01-01') + numpy.arange(
10**6, step=500).astype('timedelta64[ms]')
axis = pyinterp.TemporalAxis(dates)
print(axis)
<pyinterp.core.TemporalAxis>
min_value: 2020-01-01T00:00:00.000
max_value: 2020-01-01T00:16:39.500
step : 500 milliseconds
It is possible to search for a date in this axis.
axis.find_index(numpy.array([numpy.datetime64('2020-01-01T00:10:34.000')]))
array([1268])
You can pass any date unit to the axis.
axis.find_index(numpy.array([numpy.datetime64('2020-01-01')]))
array([0])
This object also makes it possible to manipulate timedeltas.
axis = pyinterp.TemporalAxis(dates - numpy.datetime64('2020-01-01'))
print(axis)
<pyinterp.core.TemporalAxis>
min_value: 0 milliseconds
max_value: 999500 milliseconds
step : 500 milliseconds
Total running time of the script: (0 minutes 0.003 seconds)