timelined_array 0.0.3__tar.gz → 0.0.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {timelined_array-0.0.3 → timelined_array-0.0.4}/PKG-INFO +1 -1
- {timelined_array-0.0.3 → timelined_array-0.0.4}/pyproject.toml +1 -1
- timelined_array-0.0.4/src/timelined_array/__init__.py +3 -0
- {timelined_array-0.0.3 → timelined_array-0.0.4}/src/timelined_array/time.py +553 -13
- timelined_array-0.0.3/src/timelined_array/__init__.py +0 -3
- {timelined_array-0.0.3 → timelined_array-0.0.4}/LICENSE +0 -0
- {timelined_array-0.0.3 → timelined_array-0.0.4}/README.md +0 -0
- {timelined_array-0.0.3 → timelined_array-0.0.4}/tests/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: timelined_array
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.4
|
|
4
4
|
Summary: Manage easily 1 or multidimensionnal samples numpy arrays that are time related. Extends numpy without removing any of it's abilities on such arrays.
|
|
5
5
|
Author-Email: Timothe Jost <timothe.jost@wanadoo.fr>
|
|
6
6
|
License: MIT
|
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
import numpy as np
|
|
4
4
|
from logging import getLogger
|
|
5
5
|
from typing import Tuple, List, Protocol, Type
|
|
6
|
+
from enum import Enum
|
|
7
|
+
import operator
|
|
6
8
|
|
|
9
|
+
# class syntax
|
|
7
10
|
|
|
8
11
|
logger = getLogger("timelined_array")
|
|
9
12
|
|
|
@@ -34,7 +37,20 @@ class TimeCompatibleProtocol(Protocol):
|
|
|
34
37
|
|
|
35
38
|
|
|
36
39
|
class Timeline(np.ndarray):
|
|
40
|
+
_step = None
|
|
41
|
+
_max_step = None
|
|
42
|
+
max_step_mult = 2
|
|
43
|
+
|
|
37
44
|
def __new__(cls, input_array, uniform_space=False):
|
|
45
|
+
"""Create a new instance of the Timeline class.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
input_array: The input array to create the Timeline object from.
|
|
49
|
+
uniform_space (bool): Flag to indicate if a uniformly spaced timeline is desired.
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
Timeline: A new instance of the Timeline class.
|
|
53
|
+
"""
|
|
38
54
|
|
|
39
55
|
if uniform_space:
|
|
40
56
|
# if we want a uniformly spaced timeline from start to stop of the current timeline.
|
|
@@ -47,79 +63,241 @@ class Timeline(np.ndarray):
|
|
|
47
63
|
return obj
|
|
48
64
|
|
|
49
65
|
def __array_finalize__(self, obj):
|
|
66
|
+
"""Finalize the array when subclassing a numpy array.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
self: The subclassed array.
|
|
70
|
+
obj: The original array object being subclassed.
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
None
|
|
74
|
+
"""
|
|
75
|
+
|
|
50
76
|
pass
|
|
51
77
|
|
|
52
78
|
def __setstate__(self, state):
|
|
79
|
+
"""Set the state of the object.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
state: The state to set for the object.
|
|
83
|
+
"""
|
|
84
|
+
|
|
53
85
|
# try:
|
|
54
86
|
# super().__setstate__(state[0:-2]) # old deserializer
|
|
55
87
|
# except TypeError:
|
|
56
88
|
super().__setstate__(state) # new one
|
|
57
89
|
|
|
58
90
|
def __contains__(self, time_value):
|
|
91
|
+
"""Check if the time_value is within the range of the TimeRange object."""
|
|
92
|
+
|
|
59
93
|
return self.min() <= time_value <= self.max()
|
|
60
94
|
|
|
61
95
|
def max(self):
|
|
96
|
+
"""Return the maximum value in the iterable."""
|
|
97
|
+
|
|
62
98
|
return super().max().item()
|
|
63
99
|
|
|
64
100
|
def min(self):
|
|
101
|
+
"""Return the minimum value in the tensor."""
|
|
102
|
+
|
|
65
103
|
return super().min().item()
|
|
66
104
|
|
|
67
105
|
@classmethod
|
|
68
106
|
def _uniformize(cls, timeline):
|
|
107
|
+
"""Uniformize the given timeline data.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
cls: The class instance.
|
|
111
|
+
timeline: The timeline data to be uniformized.
|
|
112
|
+
|
|
113
|
+
Raises:
|
|
114
|
+
NotImplementedError: This function is not yet implemented.
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
None
|
|
118
|
+
"""
|
|
119
|
+
|
|
69
120
|
raise NotImplementedError("Upcoming function")
|
|
70
121
|
# obj = np.linspace(input_array[0], input_array[1], len(input_array)).view(cls)
|
|
71
122
|
# TODO : do numpy.interp(np.arange(0, len(a), 1.5), np.arange(0, len(a)), a)
|
|
72
123
|
# interp to get a fixed number of points ?
|
|
73
124
|
|
|
74
125
|
def uniformize(self):
|
|
126
|
+
"""Uniformize the elements of the list using the _uniformize method."""
|
|
127
|
+
|
|
75
128
|
self[:] = self._uniformize(self)
|
|
76
129
|
|
|
130
|
+
@property
|
|
131
|
+
def step(self):
|
|
132
|
+
"""Mean time between two timeline points. Must be strictly decreasing or increasing to be calculated"""
|
|
133
|
+
if self._step is None:
|
|
134
|
+
diff = np.diff(self)
|
|
135
|
+
# make sure it is continuously rising or decreasing
|
|
136
|
+
if np.all(diff >= 0) or np.all(diff <= 0):
|
|
137
|
+
self._step = np.mean(diff)
|
|
138
|
+
else:
|
|
139
|
+
raise ValueError(
|
|
140
|
+
"Cannot determine the step value of the timeline. "
|
|
141
|
+
"It must be strictly increasing or strictly decreasing."
|
|
142
|
+
)
|
|
143
|
+
return self._step
|
|
144
|
+
|
|
145
|
+
@property
|
|
146
|
+
def max_step(self):
|
|
147
|
+
"""Largest time between two timeline points, multiplied by max_step_mult"""
|
|
148
|
+
if self._max_step is None:
|
|
149
|
+
diff = np.diff(self)
|
|
150
|
+
self._max_step = diff[np.argmax(np.absolute(diff))]
|
|
151
|
+
return self._max_step * self.max_step_mult
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class Boundary(Enum):
|
|
155
|
+
inclusive = 0
|
|
156
|
+
exclusive = 1
|
|
157
|
+
inc = 0
|
|
158
|
+
exc = 1
|
|
159
|
+
|
|
160
|
+
@staticmethod
|
|
161
|
+
def get_operation(boundary, setting):
|
|
162
|
+
"""Return the appropriate comparison operator based on the boundary and setting.
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
boundary (str): The boundary type, either "start" or "stop".
|
|
166
|
+
setting (Boundary): The setting for the boundary, either inclusive or exclusive.
|
|
167
|
+
|
|
168
|
+
Returns:
|
|
169
|
+
function: The comparison operator based on the boundary and setting.
|
|
170
|
+
|
|
171
|
+
Raises:
|
|
172
|
+
ValueError: If the boundary or setting is invalid.
|
|
173
|
+
"""
|
|
174
|
+
|
|
175
|
+
if boundary == "start":
|
|
176
|
+
if setting == Boundary.inclusive:
|
|
177
|
+
return operator.ge
|
|
178
|
+
elif setting == Boundary.exclusive:
|
|
179
|
+
return operator.gt
|
|
180
|
+
else:
|
|
181
|
+
raise ValueError
|
|
182
|
+
elif boundary == "stop":
|
|
183
|
+
if setting == Boundary.inclusive:
|
|
184
|
+
return operator.le
|
|
185
|
+
elif setting == Boundary.exclusive:
|
|
186
|
+
return operator.lt
|
|
187
|
+
else:
|
|
188
|
+
raise ValueError
|
|
189
|
+
else:
|
|
190
|
+
raise ValueError
|
|
191
|
+
|
|
77
192
|
|
|
78
193
|
class TimeIndexer:
|
|
79
194
|
"""The time indexer indexes by default from >= to the time start, and strictly < to time stop"""
|
|
80
195
|
|
|
196
|
+
start_mode = Boundary.inclusive
|
|
197
|
+
stop_mode = Boundary.exclusive
|
|
198
|
+
|
|
199
|
+
_start_operation = Boundary.get_operation("start", start_mode)
|
|
200
|
+
_stop_operation = Boundary.get_operation("stop", stop_mode)
|
|
201
|
+
|
|
81
202
|
def __init__(self, array: TimeCompatibleProtocol):
|
|
82
203
|
self.array = array
|
|
83
204
|
|
|
84
|
-
def
|
|
205
|
+
def time_to_index(
|
|
206
|
+
self, time: float | int | slice | Tuple[int | float] | List[float | int | slice | Tuple[int | float]]
|
|
207
|
+
):
|
|
208
|
+
"""Converts time to index based on different input types.
|
|
209
|
+
|
|
210
|
+
Args:
|
|
211
|
+
time (float | int | slice | Tuple[int | float] | List[float | int | slice | Tuple[int | float]]):
|
|
212
|
+
The time value or range to be converted to index.
|
|
213
|
+
|
|
214
|
+
Returns:
|
|
215
|
+
int: The index corresponding to the input time value or range.
|
|
216
|
+
|
|
217
|
+
Raises:
|
|
218
|
+
ValueError: If the input time type is not supported.
|
|
219
|
+
"""
|
|
85
220
|
# argument index may be a slice or a scalar. Units of index should be in second. Returns a slice as index
|
|
86
221
|
# this is sort of a wrapper for get_iindex that does the heavy lifting.
|
|
87
222
|
# this function just makes sure to pass arguments to it corectly depending
|
|
88
223
|
# on if the time index is a single value or a slice.
|
|
89
|
-
|
|
90
|
-
|
|
224
|
+
|
|
225
|
+
if isinstance(time, slice):
|
|
226
|
+
return self.get_iindex(time.start, time.stop, time.step)
|
|
227
|
+
elif isinstance(time, list):
|
|
228
|
+
return np.array([self.time_to_index(t) for t in time])
|
|
229
|
+
elif isinstance(time, tuple):
|
|
230
|
+
return self.get_iindex(*[time[i] if len(time) > i else None for i in range(3)])
|
|
231
|
+
elif isinstance(time, (int, float)):
|
|
232
|
+
return self.get_iindex(sec_start=time).start
|
|
91
233
|
else:
|
|
92
|
-
|
|
234
|
+
raise ValueError("Cannot process time to index ")
|
|
235
|
+
|
|
236
|
+
seconds_to_index = time_to_index
|
|
93
237
|
|
|
94
238
|
def _insert_time_index(self, time_index):
|
|
239
|
+
"""Inserts a time index into the full index.
|
|
240
|
+
|
|
241
|
+
Args:
|
|
242
|
+
time_index: The index to be inserted into the full index.
|
|
243
|
+
|
|
244
|
+
Returns:
|
|
245
|
+
tuple: The full index with the time index inserted.
|
|
246
|
+
"""
|
|
95
247
|
# put the integer value at the position of time index at the right position
|
|
96
248
|
# (time_dimension) in the tuple of all sliced dimensions
|
|
249
|
+
|
|
97
250
|
full_index = [slice(None)] * len(self.array.shape)
|
|
98
251
|
full_index[self.array.time_dimension] = time_index
|
|
99
252
|
|
|
100
253
|
return tuple(full_index)
|
|
101
254
|
|
|
102
255
|
def __getitem__(self, index) -> "TimelinedArray | MaskedTimelinedArray | np.ndarray":
|
|
256
|
+
"""Get item from TimelinedArray, MaskedTimelinedArray, or np.ndarray based on the given index.
|
|
257
|
+
|
|
258
|
+
Args:
|
|
259
|
+
index: int, float, slice, np.integer, np.floating
|
|
260
|
+
The index to retrieve the item from the array.
|
|
261
|
+
|
|
262
|
+
Returns:
|
|
263
|
+
TimelinedArray | MaskedTimelinedArray | np.ndarray
|
|
264
|
+
The item at the specified index.
|
|
265
|
+
|
|
266
|
+
Raises:
|
|
267
|
+
ValueError: If the index is iterable and not a valid type for indexing on the time dimension.
|
|
268
|
+
"""
|
|
269
|
+
|
|
103
270
|
if hasattr(index, "__iter__"):
|
|
104
271
|
# if not isinstance(index,(int,float,slice,np.integer,np.floating)):
|
|
105
272
|
raise ValueError(
|
|
106
273
|
"Isec allow only indexing on time dimension. Index must be either int, float or slice, not iterable"
|
|
107
274
|
)
|
|
108
275
|
|
|
109
|
-
iindex_time = self.
|
|
276
|
+
iindex_time = self.time_to_index(index)
|
|
110
277
|
full_iindex = self._insert_time_index(iindex_time)
|
|
111
278
|
# print("new full index : ",iindex_time)
|
|
112
279
|
logger.debug(f"About to index over time with iindex_time {iindex_time} and full_iindex {full_iindex}")
|
|
113
280
|
return self.array[full_iindex]
|
|
114
281
|
|
|
115
|
-
def get_iindex(self, sec_start=None, sec_stop=None, sec_step=None):
|
|
282
|
+
def get_iindex(self, sec_start=None, sec_stop=None, sec_step=None):
|
|
283
|
+
"""Get the index range based on the given start, stop, and step values in seconds.
|
|
284
|
+
|
|
285
|
+
Args:
|
|
286
|
+
sec_start (float): The start time in seconds. If None, start index will be 0.
|
|
287
|
+
sec_stop (float): The stop time in seconds. If None, stop index will be the length of the timeline.
|
|
288
|
+
sec_step (float): The step size in seconds. If None, step size will be 1.
|
|
289
|
+
|
|
290
|
+
Returns:
|
|
291
|
+
slice: A slice object representing the index range based on the given start, stop, and step values.
|
|
292
|
+
"""
|
|
116
293
|
# converts a time index (follows a slice syntax, but in time units) to integer units
|
|
117
|
-
|
|
294
|
+
|
|
295
|
+
timeline_max_step = abs(self.array.timeline.max_step)
|
|
118
296
|
|
|
119
297
|
if sec_start is None:
|
|
120
298
|
start = 0
|
|
121
299
|
else:
|
|
122
|
-
if sec_start
|
|
300
|
+
if self._start_operation(sec_start, self.array.timeline[0]):
|
|
123
301
|
start = np.argmax(self.array.timeline >= sec_start)
|
|
124
302
|
else:
|
|
125
303
|
start = 0
|
|
@@ -137,7 +315,7 @@ class TimeIndexer:
|
|
|
137
315
|
# , i removed this posibility
|
|
138
316
|
# stop = np.argmin(self.array.timeline<self.array.timeline[-1]+sec_stop)
|
|
139
317
|
else:
|
|
140
|
-
if sec_stop
|
|
318
|
+
if self._stop_operation(sec_stop, self.array.timeline[-1]):
|
|
141
319
|
stop = np.argmin(self.array.timeline < sec_stop)
|
|
142
320
|
else:
|
|
143
321
|
stop = len(self.array.timeline) - 1
|
|
@@ -157,6 +335,12 @@ class TimeIndexer:
|
|
|
157
335
|
step = 1
|
|
158
336
|
return slice(start, stop, step)
|
|
159
337
|
|
|
338
|
+
def __call__(self, start=None, stop=None):
|
|
339
|
+
if start is not None:
|
|
340
|
+
self._start_operation = Boundary.get_operation("start", start)
|
|
341
|
+
if stop is not None:
|
|
342
|
+
self._stop_operation = Boundary.get_operation("stop", stop)
|
|
343
|
+
|
|
160
344
|
|
|
161
345
|
class TimeMixin:
|
|
162
346
|
|
|
@@ -164,6 +348,15 @@ class TimeMixin:
|
|
|
164
348
|
timeline: Timeline
|
|
165
349
|
|
|
166
350
|
def _time_dimension_in_axis(self, axis: int | Tuple[int] | None) -> bool:
|
|
351
|
+
"""Check if the time dimension is present in the specified axis.
|
|
352
|
+
|
|
353
|
+
Args:
|
|
354
|
+
axis (int | Tuple[int] | None): The axis to check for the time dimension.
|
|
355
|
+
|
|
356
|
+
Returns:
|
|
357
|
+
bool: True if the time dimension is present in the axis, False otherwise.
|
|
358
|
+
"""
|
|
359
|
+
|
|
167
360
|
if (
|
|
168
361
|
axis is None
|
|
169
362
|
or axis == self.time_dimension
|
|
@@ -173,6 +366,18 @@ class TimeMixin:
|
|
|
173
366
|
return False
|
|
174
367
|
|
|
175
368
|
def _get_time_dimension_after_axis_removal(self, axis_removed) -> int:
|
|
369
|
+
"""Return the time dimension after removing specified axis.
|
|
370
|
+
|
|
371
|
+
Args:
|
|
372
|
+
axis_removed (int or tuple): The axis or axes to be removed.
|
|
373
|
+
|
|
374
|
+
Returns:
|
|
375
|
+
int: The time dimension after removing the specified axis or axes.
|
|
376
|
+
|
|
377
|
+
Raises:
|
|
378
|
+
ValueError: If the time dimension would be discarded after axis removal.
|
|
379
|
+
"""
|
|
380
|
+
|
|
176
381
|
if not isinstance(axis_removed, tuple):
|
|
177
382
|
axis_removed = (axis_removed,)
|
|
178
383
|
axis_removed = sorted(axis_removed)
|
|
@@ -187,6 +392,14 @@ class TimeMixin:
|
|
|
187
392
|
return final_time_dimension
|
|
188
393
|
|
|
189
394
|
def _get_advanced_indexed_times(self, index):
|
|
395
|
+
"""Get advanced indexed times based on the provided index.
|
|
396
|
+
|
|
397
|
+
Args:
|
|
398
|
+
index (np.ndarray): The index to be used for advanced indexing.
|
|
399
|
+
|
|
400
|
+
Returns:
|
|
401
|
+
tuple: A tuple containing the filtered index, timeline, and time dimension.
|
|
402
|
+
"""
|
|
190
403
|
|
|
191
404
|
index = np.asarray(index)
|
|
192
405
|
|
|
@@ -229,6 +442,14 @@ class TimeMixin:
|
|
|
229
442
|
)
|
|
230
443
|
|
|
231
444
|
def _get_slice_indexed_times(self, index):
|
|
445
|
+
"""Get the indexed times based on the provided index.
|
|
446
|
+
|
|
447
|
+
Args:
|
|
448
|
+
index: Index to be used for slicing the time dimension.
|
|
449
|
+
|
|
450
|
+
Returns:
|
|
451
|
+
Tuple containing the modified index, final timeline, and the new time dimension.
|
|
452
|
+
"""
|
|
232
453
|
|
|
233
454
|
# this will store the new time_dimension axis in the newly formed array
|
|
234
455
|
final_time_dimension = self.time_dimension
|
|
@@ -282,6 +503,14 @@ class TimeMixin:
|
|
|
282
503
|
return index, final_timeline, final_time_dimension
|
|
283
504
|
|
|
284
505
|
def _get_indexed_times(self, index: int | Tuple[int] | slice | Tuple[slice] | List | np.ndarray):
|
|
506
|
+
"""Get indexed times based on the provided index.
|
|
507
|
+
|
|
508
|
+
Args:
|
|
509
|
+
index (int | Tuple[int] | slice | Tuple[slice] | List | np.ndarray): The index to retrieve times from.
|
|
510
|
+
|
|
511
|
+
Returns:
|
|
512
|
+
np.ndarray: The indexed times based on the provided index.
|
|
513
|
+
"""
|
|
285
514
|
|
|
286
515
|
# if index is an array or a list, we do advanced indexing.
|
|
287
516
|
if isinstance(index, (np.ndarray, list)):
|
|
@@ -291,9 +520,28 @@ class TimeMixin:
|
|
|
291
520
|
|
|
292
521
|
@staticmethod
|
|
293
522
|
def _is_single_element(obj):
|
|
523
|
+
"""Check if the input object is a single element.
|
|
524
|
+
|
|
525
|
+
Args:
|
|
526
|
+
obj: Input object to be checked.
|
|
527
|
+
|
|
528
|
+
Returns:
|
|
529
|
+
bool: True if the input object is a single element, False otherwise.
|
|
530
|
+
"""
|
|
531
|
+
|
|
294
532
|
return obj.shape == ()
|
|
295
533
|
|
|
296
534
|
def _finish_axis_removing_operation(self, result: TimeCompatibleProtocol, axis: int | Tuple[int] | None):
|
|
535
|
+
"""Finish axis removing operation.
|
|
536
|
+
|
|
537
|
+
Args:
|
|
538
|
+
result (TimeCompatibleProtocol): The result of the operation.
|
|
539
|
+
axis (int | Tuple[int] | None): The axis or axes to remove.
|
|
540
|
+
|
|
541
|
+
Returns:
|
|
542
|
+
TimeCompatibleProtocol: The result after finishing the axis removing operation.
|
|
543
|
+
"""
|
|
544
|
+
|
|
297
545
|
if not isinstance(result, np.ndarray):
|
|
298
546
|
return result
|
|
299
547
|
if not self._is_single_element(result):
|
|
@@ -306,6 +554,9 @@ class TimeMixin:
|
|
|
306
554
|
# # REDUCE and SETSTATE are used to instanciate the array from and to a pickled serialized object.
|
|
307
555
|
# # We only need to store and retrieve time_dimension and timeline on top of the array's data
|
|
308
556
|
def __reduce__(self):
|
|
557
|
+
"""Return a tuple to be used for pickling and unpickling the
|
|
558
|
+
object with additional attributes 'timeline' and 'time_dimension'."""
|
|
559
|
+
|
|
309
560
|
# Get the parent's __reduce__ tuple
|
|
310
561
|
pickled_state = super().__reduce__()
|
|
311
562
|
# Create our own tuple to pass to __setstate__
|
|
@@ -316,6 +567,16 @@ class TimeMixin:
|
|
|
316
567
|
return (pickled_state[0], pickled_state[1], new_state)
|
|
317
568
|
|
|
318
569
|
def __setstate__(self: TimeCompatibleProtocol, state):
|
|
570
|
+
"""Set the state of the object using the provided state tuple.
|
|
571
|
+
|
|
572
|
+
Args:
|
|
573
|
+
self (TimeCompatibleProtocol): The TimeCompatibleProtocol object.
|
|
574
|
+
state: The state tuple containing information to set the object's attributes.
|
|
575
|
+
|
|
576
|
+
Returns:
|
|
577
|
+
None
|
|
578
|
+
"""
|
|
579
|
+
|
|
319
580
|
self.timeline = state[-2] # Set the info attribute
|
|
320
581
|
self.time_dimension = state[-1]
|
|
321
582
|
|
|
@@ -323,9 +584,21 @@ class TimeMixin:
|
|
|
323
584
|
super().__setstate__(state[0:-2])
|
|
324
585
|
|
|
325
586
|
def __hash__(self):
|
|
587
|
+
"""Return the hash value of the object based on the array and timeline attributes.
|
|
588
|
+
|
|
589
|
+
Returns:
|
|
590
|
+
int: Hash value of the object.
|
|
591
|
+
"""
|
|
592
|
+
|
|
326
593
|
return hash((self.__array__(), self.timeline)) # type: ignore
|
|
327
594
|
|
|
328
595
|
def _get_array_cls(self) -> TimeCompatibleProtocol:
|
|
596
|
+
"""Return the class of the array that is compatible with time operations.
|
|
597
|
+
|
|
598
|
+
Returns:
|
|
599
|
+
TimeCompatibleProtocol: The class of the array that is compatible with time operations.
|
|
600
|
+
"""
|
|
601
|
+
|
|
329
602
|
valid_types = [TimelinedArray, TimelinedArray]
|
|
330
603
|
for vtype in valid_types:
|
|
331
604
|
if isinstance(self, vtype):
|
|
@@ -334,6 +607,12 @@ class TimeMixin:
|
|
|
334
607
|
|
|
335
608
|
@property
|
|
336
609
|
def array_info(self: TimeCompatibleProtocol):
|
|
610
|
+
"""Return information about the array.
|
|
611
|
+
|
|
612
|
+
Returns:
|
|
613
|
+
str: A string containing the type of the array, its shape, time dimension, and timeline shape.
|
|
614
|
+
"""
|
|
615
|
+
|
|
337
616
|
return (
|
|
338
617
|
f"{type(self).__name__} of shape {self.shape}, time_dimension {self.time_dimension} "
|
|
339
618
|
f"and timeline shape {self.timeline.shape}"
|
|
@@ -341,11 +620,11 @@ class TimeMixin:
|
|
|
341
620
|
|
|
342
621
|
@property
|
|
343
622
|
def itime(self: TimeCompatibleProtocol):
|
|
623
|
+
"""Return a TimeIndexer object based on the given TimeCompatibleProtocol object."""
|
|
624
|
+
|
|
344
625
|
return TimeIndexer(self)
|
|
345
626
|
|
|
346
|
-
|
|
347
|
-
def isec(self: TimeCompatibleProtocol):
|
|
348
|
-
return self.itime
|
|
627
|
+
isec = itime
|
|
349
628
|
|
|
350
629
|
def align_trace(self, start: float, element_nb: int):
|
|
351
630
|
"""Aligns the timelined array by making it start from a timepoint in time-units (synchronizing)
|
|
@@ -363,6 +642,16 @@ class TimeMixin:
|
|
|
363
642
|
return self.itime[start:][:element_nb] # type: ignore
|
|
364
643
|
|
|
365
644
|
def swapaxes(self: TimeCompatibleProtocol, axis1: int, axis2: int):
|
|
645
|
+
"""Swap the two specified axes of the TimelinedArray.
|
|
646
|
+
|
|
647
|
+
Args:
|
|
648
|
+
axis1 (int): The first axis to be swapped.
|
|
649
|
+
axis2 (int): The second axis to be swapped.
|
|
650
|
+
|
|
651
|
+
Returns:
|
|
652
|
+
TimeCompatibleProtocol: A new TimelinedArray with the specified axes swapped.
|
|
653
|
+
"""
|
|
654
|
+
|
|
366
655
|
# we re-instanciate a TimelinedArray with view instead of the full constructor : faster
|
|
367
656
|
cls = self._get_array_cls()
|
|
368
657
|
|
|
@@ -380,6 +669,15 @@ class TimeMixin:
|
|
|
380
669
|
return swapped_array
|
|
381
670
|
|
|
382
671
|
def transpose(self: TimeCompatibleProtocol, *axes):
|
|
672
|
+
"""Transpose the array along the specified axes.
|
|
673
|
+
|
|
674
|
+
Args:
|
|
675
|
+
*axes: The axes to transpose the array along. If not provided, transposes the array in reverse order.
|
|
676
|
+
|
|
677
|
+
Returns:
|
|
678
|
+
TimeCompatibleProtocol: The transposed array with updated timeline and time dimension.
|
|
679
|
+
"""
|
|
680
|
+
|
|
383
681
|
if not axes:
|
|
384
682
|
axes = tuple(range(self.ndim))[::-1]
|
|
385
683
|
|
|
@@ -399,9 +697,25 @@ class TimeMixin:
|
|
|
399
697
|
|
|
400
698
|
@property
|
|
401
699
|
def T(self: TimeCompatibleProtocol):
|
|
700
|
+
"""Transposes the object using the transpose method."""
|
|
701
|
+
|
|
402
702
|
return self.transpose()
|
|
403
703
|
|
|
404
704
|
def moveaxis(self: TimeCompatibleProtocol, source: int | Tuple[int], destination: int | Tuple[int]):
|
|
705
|
+
"""Move the axis of the array to new positions.
|
|
706
|
+
|
|
707
|
+
Args:
|
|
708
|
+
source (int or Tuple[int]): The source position(s) of the axis to move.
|
|
709
|
+
destination (int or Tuple[int]): The destination position(s) to move the axis to.
|
|
710
|
+
|
|
711
|
+
Returns:
|
|
712
|
+
TimeCompatibleProtocol: A new array with the axis moved to the specified destination.
|
|
713
|
+
|
|
714
|
+
Note:
|
|
715
|
+
This method re-instantiates a TimelinedArray with a view instead of the full
|
|
716
|
+
constructor for faster performance.
|
|
717
|
+
"""
|
|
718
|
+
|
|
405
719
|
if isinstance(source, int):
|
|
406
720
|
source = (source,)
|
|
407
721
|
if isinstance(destination, int):
|
|
@@ -430,6 +744,16 @@ class TimeMixin:
|
|
|
430
744
|
return moved_array
|
|
431
745
|
|
|
432
746
|
def rollaxis(self: TimeCompatibleProtocol, axis: int, start: int = 0):
|
|
747
|
+
"""Roll the axis of the TimelinedArray.
|
|
748
|
+
|
|
749
|
+
Args:
|
|
750
|
+
axis (int): The axis to roll.
|
|
751
|
+
start (int, optional): The position where the axis is placed. Defaults to 0.
|
|
752
|
+
|
|
753
|
+
Returns:
|
|
754
|
+
TimeCompatibleProtocol: A TimelinedArray with the rolled axis.
|
|
755
|
+
"""
|
|
756
|
+
|
|
433
757
|
# we re-instanciate a TimelinedArray with view instead of the full constructor : faster
|
|
434
758
|
cls = self._get_array_cls()
|
|
435
759
|
|
|
@@ -454,33 +778,120 @@ class TimeMixin:
|
|
|
454
778
|
return rolled_array
|
|
455
779
|
|
|
456
780
|
def mean(self: TimeCompatibleProtocol, axis: int | Tuple[int] | None = None, dtype=None, out=None, keepdims=False):
|
|
781
|
+
"""Calculates the mean along the specified axis.
|
|
782
|
+
|
|
783
|
+
Args:
|
|
784
|
+
axis (int | Tuple[int] | None): Axis or axes along which to perform the mean operation. Default is None.
|
|
785
|
+
dtype: Data-type to use in the computation.
|
|
786
|
+
out: Output array where the result is stored.
|
|
787
|
+
keepdims (bool): If True, the reduced dimensions are retained in the output array.
|
|
788
|
+
|
|
789
|
+
Returns:
|
|
790
|
+
ndarray: Mean of the input array along the specified axis.
|
|
791
|
+
"""
|
|
792
|
+
|
|
457
793
|
result = super().mean(axis=axis, dtype=dtype, out=out, keepdims=keepdims)
|
|
458
794
|
return self._finish_axis_removing_operation(result, axis)
|
|
459
795
|
|
|
460
796
|
# Override other reduction methods similarly if needed
|
|
461
797
|
def sum(self: TimeCompatibleProtocol, axis: int | Tuple[int] | None = None, dtype=None, out=None, keepdims=False):
|
|
798
|
+
"""Calculate the sum along the specified axis.
|
|
799
|
+
|
|
800
|
+
Args:
|
|
801
|
+
axis (int | Tuple[int] | None): Axis or axes along which a sum is performed.
|
|
802
|
+
The default is to sum over all the dimensions of the input array.
|
|
803
|
+
dtype: The type of the returned array and of the accumulator in which the elements are summed.
|
|
804
|
+
If dtype is not specified, it defaults to the dtype of a, unless a has an integer dtype
|
|
805
|
+
with a precision less than that of the default platform integer.
|
|
806
|
+
In that case, the default platform integer is used.
|
|
807
|
+
out: Alternative output array in which to place the result. It must have the same shape
|
|
808
|
+
as the expected output, but the type of the output values will be cast if necessary.
|
|
809
|
+
keepdims (bool): If this is set to True, the axes which are reduced are left
|
|
810
|
+
in the result as dimensions with size one.
|
|
811
|
+
With this option, the result will broadcast correctly against the input array.
|
|
812
|
+
|
|
813
|
+
Returns:
|
|
814
|
+
The sum of the input array along the specified axis.
|
|
815
|
+
"""
|
|
816
|
+
|
|
462
817
|
result = super().sum(axis=axis, dtype=dtype, out=out, keepdims=keepdims)
|
|
463
818
|
return self._finish_axis_removing_operation(result, axis)
|
|
464
819
|
|
|
465
820
|
def std(
|
|
466
821
|
self: TimeCompatibleProtocol, axis: int | Tuple[int] | None = None, dtype=None, out=None, ddof=0, keepdims=False
|
|
467
822
|
):
|
|
823
|
+
"""Calculate the standard deviation along the specified axis.
|
|
824
|
+
|
|
825
|
+
Args:
|
|
826
|
+
axis (int or Tuple[int] or None): Axis or axes along which the standard deviation is computed.
|
|
827
|
+
The default is to compute the standard deviation of the flattened array.
|
|
828
|
+
dtype: Data-type of the result. If not provided, the data-type of the input is used.
|
|
829
|
+
out: Output array with the same shape as input array, placed with the result.
|
|
830
|
+
ddof (int): Delta degrees of freedom. The divisor used in calculations is N - ddof,
|
|
831
|
+
where N represents the number of elements along the specified axis.
|
|
832
|
+
keepdims (bool): If this is set to True, the axes which are reduced
|
|
833
|
+
are left in the result as dimensions with size one.
|
|
834
|
+
|
|
835
|
+
Returns:
|
|
836
|
+
ndarray: A new array containing the standard deviation
|
|
837
|
+
of elements along the specified axis after removing the axis.
|
|
838
|
+
"""
|
|
839
|
+
|
|
468
840
|
result = super().std(axis=axis, dtype=dtype, out=out, ddof=ddof, keepdims=keepdims)
|
|
469
841
|
return self._finish_axis_removing_operation(result, axis)
|
|
470
842
|
|
|
471
843
|
def var(
|
|
472
844
|
self: TimeCompatibleProtocol, axis: int | Tuple[int] | None = None, dtype=None, out=None, ddof=0, keepdims=False
|
|
473
845
|
):
|
|
846
|
+
"""Calculate the variance along the specified axis.
|
|
847
|
+
|
|
848
|
+
Args:
|
|
849
|
+
self (TimeCompatibleProtocol): The input data.
|
|
850
|
+
axis (int | Tuple[int] | None): Axis or axes along which the variance is computed.
|
|
851
|
+
The default is to compute the variance of the flattened array.
|
|
852
|
+
dtype: Data-type of the result. If not provided, the data-type of the input is used.
|
|
853
|
+
out: Alternative output array in which to place the result.
|
|
854
|
+
It must have the same shape as the expected output but the type will be cast if necessary.
|
|
855
|
+
ddof (int): Delta degrees of freedom. The divisor used in calculations is N - ddof,
|
|
856
|
+
where N represents the number of elements along the specified axis.
|
|
857
|
+
keepdims (bool): If this is set to True, the axes which are reduced
|
|
858
|
+
are left in the result as dimensions with size one.
|
|
859
|
+
|
|
860
|
+
Returns:
|
|
861
|
+
ndarray: A new array containing the variance of the input array along the specified axis.
|
|
862
|
+
"""
|
|
863
|
+
|
|
474
864
|
result = super().var(axis=axis, dtype=dtype, out=out, ddof=ddof, keepdims=keepdims)
|
|
475
865
|
return self._finish_axis_removing_operation(result, axis)
|
|
476
866
|
|
|
477
867
|
def rebase_timeline(self, at=0):
|
|
868
|
+
"""Rebases the timeline of the array.
|
|
869
|
+
|
|
870
|
+
Args:
|
|
871
|
+
at (int): The index of the element to set as time zero. Defaults to 0.
|
|
872
|
+
|
|
873
|
+
Returns:
|
|
874
|
+
array: A modified version of the array with the timeline adjusted.
|
|
875
|
+
"""
|
|
876
|
+
|
|
478
877
|
# returns a modified version of the array, with the first element of the array to time zero,
|
|
479
878
|
# and shift the rest accordingly
|
|
480
879
|
cls = self._get_array_cls()
|
|
481
880
|
return cls(self, timeline=self.timeline - self.timeline[at]) # type: ignore
|
|
482
881
|
|
|
483
882
|
def offset_timeline(self, offset):
|
|
883
|
+
"""Returns a modified version of the array with time offset.
|
|
884
|
+
|
|
885
|
+
Args:
|
|
886
|
+
offset: A fixed offset value to set time of all elements in the array relative to their current value.
|
|
887
|
+
|
|
888
|
+
Returns:
|
|
889
|
+
An array with time offset applied.
|
|
890
|
+
|
|
891
|
+
Raises:
|
|
892
|
+
None
|
|
893
|
+
"""
|
|
894
|
+
|
|
484
895
|
# returns a modified version of the array, where we set time of all elements
|
|
485
896
|
# in array at a fix offset relative to their current value.
|
|
486
897
|
cls = self._get_array_cls()
|
|
@@ -488,18 +899,37 @@ class TimeMixin:
|
|
|
488
899
|
|
|
489
900
|
@property
|
|
490
901
|
def pack(self):
|
|
902
|
+
"""Returns a TimePacker object initialized with the current instance."""
|
|
903
|
+
|
|
491
904
|
return TimePacker(self)
|
|
492
905
|
|
|
493
906
|
def sec_max(self):
|
|
907
|
+
"""Return the second maximum time from the timeline."""
|
|
908
|
+
|
|
494
909
|
# get maximum time
|
|
495
910
|
return self.timeline.max()
|
|
496
911
|
|
|
497
912
|
def sec_min(self):
|
|
913
|
+
"""Get the minimum time from the timeline."""
|
|
914
|
+
|
|
498
915
|
# get minimum time
|
|
499
916
|
return self.timeline.min()
|
|
500
917
|
|
|
501
918
|
@staticmethod
|
|
502
919
|
def extract_time_from_data(data, timeline=None, time_dimension=None, uniform_space=False):
|
|
920
|
+
"""Extracts time-related information from the input data.
|
|
921
|
+
|
|
922
|
+
Args:
|
|
923
|
+
data: The input data from which to extract time-related information.
|
|
924
|
+
timeline: The timeline associated with the data. If not provided, it will be extracted from the input data.
|
|
925
|
+
time_dimension: The dimension representing time in the data. If not provided,
|
|
926
|
+
it will be inferred from the input data.
|
|
927
|
+
uniform_space: A boolean indicating whether the data is uniformly spaced in time.
|
|
928
|
+
|
|
929
|
+
Returns:
|
|
930
|
+
A tuple containing the processed data, timeline, and time dimension.
|
|
931
|
+
"""
|
|
932
|
+
|
|
503
933
|
_unpacking = False
|
|
504
934
|
# if timeline not explicitely passed as arg, we try to pick up the timeline of the input_array.
|
|
505
935
|
# will rise after if input_array is not a timelined_array
|
|
@@ -555,6 +985,8 @@ class TimePacker:
|
|
|
555
985
|
self.array = array
|
|
556
986
|
|
|
557
987
|
def __iter__(self):
|
|
988
|
+
"""Returns an iterator object that contains the timeline and the array."""
|
|
989
|
+
|
|
558
990
|
return iter((self.array.timeline, self.array.__array__()))
|
|
559
991
|
|
|
560
992
|
|
|
@@ -571,7 +1003,7 @@ class TimelinedArray(TimeMixin, np.ndarray, TimeCompatibleProtocol):
|
|
|
571
1003
|
timeline_step: This method returns the average time difference between each consecutive value in the timeline.
|
|
572
1004
|
|
|
573
1005
|
TimelinedArrayIndexer class, which has several methods, including:
|
|
574
|
-
|
|
1006
|
+
time_to_index: This method converts time in seconds to index value.
|
|
575
1007
|
get_iindex: This method converts time in seconds to a slice object representing time.
|
|
576
1008
|
|
|
577
1009
|
__new__ : This method is used to creates a new instance of the TimelinedArray class. It takes several optional
|
|
@@ -590,7 +1022,20 @@ class TimelinedArray(TimeMixin, np.ndarray, TimeCompatibleProtocol):
|
|
|
590
1022
|
|
|
591
1023
|
"""
|
|
592
1024
|
|
|
1025
|
+
TA_Timeline = Timeline
|
|
1026
|
+
|
|
593
1027
|
def __new__(cls, data, timeline=None, time_dimension: int | None = None, uniform_space=False) -> "TimelinedArray":
|
|
1028
|
+
"""Create a new TimelinedArray object from the input data.
|
|
1029
|
+
|
|
1030
|
+
Args:
|
|
1031
|
+
data: The input data to be stored in the TimelinedArray.
|
|
1032
|
+
timeline: The timeline associated with the data (default is None).
|
|
1033
|
+
time_dimension: The dimension representing time in the data (default is None).
|
|
1034
|
+
uniform_space: A boolean flag indicating if the space is uniform (default is False).
|
|
1035
|
+
|
|
1036
|
+
Returns:
|
|
1037
|
+
TimelinedArray: A new TimelinedArray object.
|
|
1038
|
+
"""
|
|
594
1039
|
|
|
595
1040
|
data, timeline, time_dimension = TimeMixin.extract_time_from_data(
|
|
596
1041
|
data, timeline=timeline, time_dimension=time_dimension, uniform_space=uniform_space
|
|
@@ -614,6 +1059,15 @@ class TimelinedArray(TimeMixin, np.ndarray, TimeCompatibleProtocol):
|
|
|
614
1059
|
return obj
|
|
615
1060
|
|
|
616
1061
|
def __array_finalize__(self, obj):
|
|
1062
|
+
"""Finalize the array with additional attributes.
|
|
1063
|
+
|
|
1064
|
+
Args:
|
|
1065
|
+
obj: Another array to finalize.
|
|
1066
|
+
|
|
1067
|
+
Returns:
|
|
1068
|
+
None
|
|
1069
|
+
"""
|
|
1070
|
+
|
|
617
1071
|
super().__array_finalize__(obj)
|
|
618
1072
|
if obj is None:
|
|
619
1073
|
return
|
|
@@ -621,6 +1075,20 @@ class TimelinedArray(TimeMixin, np.ndarray, TimeCompatibleProtocol):
|
|
|
621
1075
|
self.time_dimension = getattr(obj, "time_dimension", 0)
|
|
622
1076
|
|
|
623
1077
|
def __array_wrap__(self, out_arr, context=None):
|
|
1078
|
+
"""Wrap the output array after a ufunc operation.
|
|
1079
|
+
|
|
1080
|
+
Args:
|
|
1081
|
+
out_arr: The output array to be wrapped.
|
|
1082
|
+
context: Additional context information (default is None).
|
|
1083
|
+
|
|
1084
|
+
Returns:
|
|
1085
|
+
The wrapped output array.
|
|
1086
|
+
|
|
1087
|
+
Example:
|
|
1088
|
+
If context is provided, it logs the ufunc operation name.
|
|
1089
|
+
If the shape of the output array is reduced, it logs the shape changes.
|
|
1090
|
+
"""
|
|
1091
|
+
|
|
624
1092
|
if context is not None:
|
|
625
1093
|
logger.debug(f"wrapping array after ufunc {context[0].__name__}")
|
|
626
1094
|
output = super().__array_wrap__(out_arr, context)
|
|
@@ -629,12 +1097,33 @@ class TimelinedArray(TimeMixin, np.ndarray, TimeCompatibleProtocol):
|
|
|
629
1097
|
return output
|
|
630
1098
|
|
|
631
1099
|
def __array_function__(self, func, types, args, kwargs):
|
|
1100
|
+
"""Intercepts array before calling a function.
|
|
1101
|
+
|
|
1102
|
+
Args:
|
|
1103
|
+
self: The array object.
|
|
1104
|
+
func: The function being called.
|
|
1105
|
+
types: The types of the arguments.
|
|
1106
|
+
args: The arguments passed to the function.
|
|
1107
|
+
kwargs: The keyword arguments passed to the function.
|
|
1108
|
+
|
|
1109
|
+
Returns:
|
|
1110
|
+
The result of calling the function on the array.
|
|
1111
|
+
"""
|
|
1112
|
+
|
|
632
1113
|
logger.debug(f"intercepting array before function {func.__name__}")
|
|
633
1114
|
return super().__array_function__(func, types, args, kwargs)
|
|
634
1115
|
|
|
635
1116
|
def __getitem__(
|
|
636
1117
|
self, index: int | Tuple[int] | slice | Tuple[slice] | List | np.ndarray
|
|
637
1118
|
) -> "TimelinedArray | np.ndarray":
|
|
1119
|
+
"""Get item from TimelinedArray based on index or slice.
|
|
1120
|
+
|
|
1121
|
+
Args:
|
|
1122
|
+
index (int | Tuple[int] | slice | Tuple[slice] | List | np.ndarray): Index or slice to retrieve item.
|
|
1123
|
+
|
|
1124
|
+
Returns:
|
|
1125
|
+
TimelinedArray | np.ndarray: Indexed result based on the provided index.
|
|
1126
|
+
"""
|
|
638
1127
|
|
|
639
1128
|
index, final_timeline, final_time_dimension = self._get_indexed_times(index)
|
|
640
1129
|
|
|
@@ -654,13 +1143,27 @@ class TimelinedArray(TimeMixin, np.ndarray, TimeCompatibleProtocol):
|
|
|
654
1143
|
# __repr__ and __str__ ARE OVERRIDEN TO AVOID HORRIBLE PERFORMANCE WHEN PRINTING
|
|
655
1144
|
# DUE TO CUSTOM __GETITEM__ PRE-CHECKS WITH RECURSIVE NATIVE NUMPY REPR
|
|
656
1145
|
def __repr__(self):
|
|
1146
|
+
"""Return a string representation of the object with the class name and the array representation."""
|
|
1147
|
+
|
|
657
1148
|
return type(self).__name__ + np.array(self).__repr__()[5:]
|
|
658
1149
|
|
|
659
1150
|
def __str__(self):
|
|
1151
|
+
"""Return a string representation of the object by concatenating the class name with the string
|
|
1152
|
+
representation of the object as a NumPy array."""
|
|
1153
|
+
|
|
660
1154
|
return type(self).__name__ + np.array(self).__str__()
|
|
661
1155
|
|
|
662
1156
|
@staticmethod
|
|
663
1157
|
def align_from_iterable(iterable) -> "TimelinedArray":
|
|
1158
|
+
"""Aligns arrays from an iterable based on their timelines.
|
|
1159
|
+
|
|
1160
|
+
Args:
|
|
1161
|
+
iterable: An iterable containing TimelinedArray objects to align.
|
|
1162
|
+
|
|
1163
|
+
Returns:
|
|
1164
|
+
TimelinedArray: A new TimelinedArray object containing aligned arrays.
|
|
1165
|
+
"""
|
|
1166
|
+
|
|
664
1167
|
start = min([item.timeline.min() for item in iterable])
|
|
665
1168
|
maxlen = min([len(item.isec[start:]) for item in iterable])
|
|
666
1169
|
|
|
@@ -687,6 +1190,26 @@ class MaskedTimelinedArray(TimeMixin, np.ma.MaskedArray, TimeCompatibleProtocol)
|
|
|
687
1190
|
uniform_space=False,
|
|
688
1191
|
**kwargs,
|
|
689
1192
|
):
|
|
1193
|
+
"""Create a new instance of the class with the specified parameters.
|
|
1194
|
+
|
|
1195
|
+
Args:
|
|
1196
|
+
cls: The class.
|
|
1197
|
+
data: The data to be used.
|
|
1198
|
+
mask: The mask for the data (default is np.ma.nomask).
|
|
1199
|
+
dtype: The data type (default is None).
|
|
1200
|
+
copy: Whether to copy the data (default is False).
|
|
1201
|
+
fill_value: The fill value for the data (default is None).
|
|
1202
|
+
keep_mask: Whether to keep the mask (default is True).
|
|
1203
|
+
hard_mask: Whether to use a hard mask (default is False).
|
|
1204
|
+
shrink: Whether to shrink the data (default is True).
|
|
1205
|
+
timeline: The timeline for the data.
|
|
1206
|
+
time_dimension: The time dimension for the data.
|
|
1207
|
+
uniform_space: Whether the space is uniform (default is False).
|
|
1208
|
+
**kwargs: Additional keyword arguments.
|
|
1209
|
+
|
|
1210
|
+
Returns:
|
|
1211
|
+
An instance of the class with the specified parameters.
|
|
1212
|
+
"""
|
|
690
1213
|
|
|
691
1214
|
_, timeline, time_dimension = TimeMixin.extract_time_from_data(
|
|
692
1215
|
data, timeline=timeline, time_dimension=time_dimension, uniform_space=uniform_space
|
|
@@ -710,6 +1233,15 @@ class MaskedTimelinedArray(TimeMixin, np.ma.MaskedArray, TimeCompatibleProtocol)
|
|
|
710
1233
|
return obj
|
|
711
1234
|
|
|
712
1235
|
def __array_finalize__(self, obj):
|
|
1236
|
+
"""Finalize the array with additional attributes.
|
|
1237
|
+
|
|
1238
|
+
Args:
|
|
1239
|
+
obj: Another array to finalize.
|
|
1240
|
+
|
|
1241
|
+
Returns:
|
|
1242
|
+
None
|
|
1243
|
+
"""
|
|
1244
|
+
|
|
713
1245
|
super().__array_finalize__(obj)
|
|
714
1246
|
if obj is None:
|
|
715
1247
|
return
|
|
@@ -719,6 +1251,14 @@ class MaskedTimelinedArray(TimeMixin, np.ma.MaskedArray, TimeCompatibleProtocol)
|
|
|
719
1251
|
def __getitem__(
|
|
720
1252
|
self, index: int | Tuple[int] | slice | Tuple[slice] | List | np.ndarray
|
|
721
1253
|
) -> "MaskedTimelinedArray | np.ma.MaskedArray":
|
|
1254
|
+
"""Get item from the MaskedTimelinedArray based on the provided index.
|
|
1255
|
+
|
|
1256
|
+
Args:
|
|
1257
|
+
index (int | Tuple[int] | slice | Tuple[slice] | List | np.ndarray): The index or slice to retrieve.
|
|
1258
|
+
|
|
1259
|
+
Returns:
|
|
1260
|
+
MaskedTimelinedArray | np.ma.MaskedArray: The masked array or MaskedTimelinedArray based on the index.
|
|
1261
|
+
"""
|
|
722
1262
|
|
|
723
1263
|
index, final_timeline, final_time_dimension = self._get_indexed_times(index)
|
|
724
1264
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|