@@ -110,6 +110,10 @@ class Axis:
110110 """
111111 An axis with a name, low/upper bounds, a CRS, uom, resolution, coefficients.
112112
113+ A subset of the coefficients (axis coordinates) can be retrieved with the [] operator,
114+ e.g. for an irregular temporal axis: axis["2024-01-01" : "2024-01-31"].
115+ See :meth:`__getitem__` for more details.
116+
113117 :param name: Name of the axis.
114118 :param low: Lower bound of the axis.
115119 :param high: Upper bound of the axis.
@@ -155,6 +159,102 @@ def __str__(self):
155159 ret += f'{ indent } coefficients: { coefficients } '
156160 return ret
157161
162+ def is_temporal (self ) -> bool :
163+ """
164+ Returns: True if this axis is a temporal axis (e.g. ansi), False otherwise.
165+ """
166+ return isinstance (self .low , datetime )
167+
168+ def is_spatial (self ) -> bool :
169+ """
170+ Returns: True if this axis is a spatial axis (e.g. Lat, Lon, E, N), False otherwise.
171+ """
172+ return not self .is_temporal ()
173+
174+ def is_irregular (self ) -> bool :
175+ """
176+ Returns: True if this axis is an irregular axis, False otherwise.
177+ """
178+ return self .coefficients is not None and len (self .coefficients ) > 0
179+
180+ def is_regular (self ) -> bool :
181+ """
182+ Returns: True if this axis is a regular axis, False otherwise.
183+ """
184+ return self .resolution is not None
185+
186+ def __getitem__ (self , item ) -> list [BoundType ]:
187+ """
188+ - If :attr:`coefficients` is not None, then they are subsetted according to ``item``
189+ - Otherwise, a list of coefficients is generated according to the :attr:`resolution`,
190+ between the start and stop provided by the item slice.
191+
192+ :param item: must be a :class:`slice` object with a start and stop set;
193+ the step is ignored. The start and stop must be valid coordinates in the
194+ axis :attr:`crs` and within the :attr:`low` / :attr:`high` bounds of this object.
195+
196+ :raises WCSClientException:
197+ - if :attr:`coefficients` and :attr:`resolution` are both None.
198+ - if ``item`` is not a slice object
199+ - if the start / stop of ``item`` are invalid coordinates
200+ """
201+ if not isinstance (item , slice ):
202+ raise WCSClientException (f"Invalid coordinates provided for operator [] "
203+ f"on axis { self .name } , expected a slice of the form start:stop." )
204+ if item .stop is None :
205+ raise WCSClientException (f"No upper limit provided for operator [] on axis { self .name } ." )
206+
207+ temporal = self .is_temporal ()
208+ regular = self .is_regular ()
209+ irregular = self .is_irregular ()
210+
211+ if not regular and not irregular :
212+ raise WCSClientException (f"operator [] is inapplicable to axis { self .name } "
213+ f"without a resolution or coefficients." )
214+ if temporal and not irregular :
215+ raise WCSClientException (f"operator [] is inapplicable to regular "
216+ f"temporal axis { self .name } ." )
217+
218+ start = item .start
219+ stop = item .stop
220+
221+ # parse string datetime to datetimes if needed, and make sure all datetime have the same tzinfo
222+ if temporal :
223+ tz = self .coefficients [0 ].tzinfo
224+ if isinstance (start , str ):
225+ start = datetime .fromisoformat (start )
226+ elif not isinstance (start , datetime ):
227+ raise WCSClientException (f"Invalid type of start coordinate provided for operator [] "
228+ f"on axis { self .name } , expected either a string or a datetime." )
229+ if isinstance (stop , str ):
230+ stop = datetime .fromisoformat (stop ).replace (tzinfo = tz )
231+ elif not isinstance (stop , datetime ):
232+ raise WCSClientException (f"Invalid type of stop coordinate provided for operator [] "
233+ f"on axis { self .name } , expected either a string or a datetime." )
234+ start = start .replace (tzinfo = tz )
235+ stop = stop .replace (tzinfo = tz )
236+
237+ coefficients = self .get_coefficients ()
238+ return [c for c in coefficients if start <= c <= stop ]
239+
240+ def get_coefficients (self ) -> list [BoundType ]:
241+ """
242+ :return: a list of coefficients, automatically generated if this
243+ is a regular axis.
244+ """
245+ if self .is_irregular ():
246+ return self .coefficients
247+ if not self .is_regular ():
248+ raise WCSClientException (f"{ self .name } is not a regular or irregular "
249+ f"axis, cannot calculate coefficients." )
250+
251+ ret = []
252+ current = self .low
253+ while current <= self .high :
254+ ret .append (current )
255+ current += self .resolution
256+ return ret
257+
158258
159259@dataclass
160260class BoundingBox :
0 commit comments