timelined_array 0.0.12__tar.gz → 0.0.13__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.12 → timelined_array-0.0.13}/PKG-INFO +5 -1
- {timelined_array-0.0.12 → timelined_array-0.0.13}/README.md +4 -0
- {timelined_array-0.0.12 → timelined_array-0.0.13}/pyproject.toml +13 -1
- {timelined_array-0.0.12 → timelined_array-0.0.13}/src/timelined_array/__init__.py +1 -1
- {timelined_array-0.0.12 → timelined_array-0.0.13}/src/timelined_array/time.py +54 -29
- timelined_array-0.0.13/tests/__init__.py +0 -0
- timelined_array-0.0.13/tests/test_timelined_array.py +171 -0
- timelined_array-0.0.12/tests/__init__.py +0 -111
- {timelined_array-0.0.12 → timelined_array-0.0.13}/LICENSE +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.13
|
|
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
|
|
@@ -12,6 +12,10 @@ Description-Content-Type: text/markdown
|
|
|
12
12
|
|
|
13
13
|
# timelined_array
|
|
14
14
|
|
|
15
|
+

|
|
16
|
+

|
|
17
|
+
[](https://codecov.io/gh/JostTim/timelined_array)
|
|
18
|
+
|
|
15
19
|
## Overview
|
|
16
20
|
The TimelinedArray package provides a set of classes and utilities for working with time-indexed arrays. It extends the functionality of NumPy arrays to include time-based indexing and operations, making it easier to work with time-series data.
|
|
17
21
|
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# timelined_array
|
|
2
2
|
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+
[](https://codecov.io/gh/JostTim/timelined_array)
|
|
6
|
+
|
|
3
7
|
## Overview
|
|
4
8
|
The TimelinedArray package provides a set of classes and utilities for working with time-indexed arrays. It extends the functionality of NumPy arrays to include time-based indexing and operations, making it easier to work with time-series data.
|
|
5
9
|
|
|
@@ -10,7 +10,7 @@ dependencies = [
|
|
|
10
10
|
requires-python = ">=3.11"
|
|
11
11
|
readme = "README.md"
|
|
12
12
|
dynamic = []
|
|
13
|
-
version = "0.0.
|
|
13
|
+
version = "0.0.13"
|
|
14
14
|
|
|
15
15
|
[project.license]
|
|
16
16
|
text = "MIT"
|
|
@@ -31,3 +31,15 @@ distribution = true
|
|
|
31
31
|
[tool.pdm.version]
|
|
32
32
|
source = "file"
|
|
33
33
|
path = "src/timelined_array/__init__.py"
|
|
34
|
+
|
|
35
|
+
[tool.pdm.dev-dependencies]
|
|
36
|
+
dev = [
|
|
37
|
+
"pytest>=8.3.2",
|
|
38
|
+
"pytest-cov>=5.0.0",
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
[tool.pytest.ini_options]
|
|
42
|
+
addopts = "--pdbcls=IPython.terminal.debugger:TerminalPdb --cov-report html --cov --junitxml=pytest_results.xml"
|
|
43
|
+
testpaths = [
|
|
44
|
+
"tests",
|
|
45
|
+
]
|
|
@@ -260,7 +260,8 @@ class TimeIndexer:
|
|
|
260
260
|
iindex_time = self.time_to_index(index)
|
|
261
261
|
full_iindex = self._insert_time_index(iindex_time)
|
|
262
262
|
# print("new full index : ",iindex_time)
|
|
263
|
-
logger.debug(
|
|
263
|
+
logger.debug(
|
|
264
|
+
f"About to index over time with iindex_time {iindex_time} and full_iindex {full_iindex}")
|
|
264
265
|
return self.array[full_iindex]
|
|
265
266
|
|
|
266
267
|
def get_iindex(self, sec_start=None, sec_stop=None, sec_step=None):
|
|
@@ -370,7 +371,8 @@ class TimeMixin:
|
|
|
370
371
|
if axis < self.time_dimension:
|
|
371
372
|
final_time_dimension -= 1
|
|
372
373
|
elif axis == self.time_dimension:
|
|
373
|
-
raise ValueError(
|
|
374
|
+
raise ValueError(
|
|
375
|
+
"The time dimension would simply be discarded after axis removal")
|
|
374
376
|
|
|
375
377
|
return final_time_dimension
|
|
376
378
|
|
|
@@ -480,7 +482,8 @@ class TimeMixin:
|
|
|
480
482
|
# we apply this reshaping to timeline too.
|
|
481
483
|
|
|
482
484
|
final_timeline = (
|
|
483
|
-
self.timeline[index[time_dimension_in_index]] if len(
|
|
485
|
+
self.timeline[index[time_dimension_in_index]] if len(
|
|
486
|
+
index) > time_dimension_in_index else self.timeline
|
|
484
487
|
)
|
|
485
488
|
|
|
486
489
|
return index, final_timeline, final_time_dimension
|
|
@@ -533,7 +536,8 @@ class TimeMixin:
|
|
|
533
536
|
return result.item()
|
|
534
537
|
if self._time_dimension_in_axis(axis):
|
|
535
538
|
return np.asarray(result)
|
|
536
|
-
result.time_dimension = self._get_time_dimension_after_axis_removal(
|
|
539
|
+
result.time_dimension = self._get_time_dimension_after_axis_removal(
|
|
540
|
+
axis)
|
|
537
541
|
return result
|
|
538
542
|
|
|
539
543
|
# # REDUCE and SETSTATE are used to instanciate the array from and to a pickled serialized object.
|
|
@@ -545,7 +549,8 @@ class TimeMixin:
|
|
|
545
549
|
# Get the parent's __reduce__ tuple
|
|
546
550
|
pickled_state = super().__reduce__()
|
|
547
551
|
# Create our own tuple to pass to __setstate__
|
|
548
|
-
|
|
552
|
+
# type: ignore
|
|
553
|
+
new_state = pickled_state[2] + (self.timeline, self.time_dimension)
|
|
549
554
|
|
|
550
555
|
# self.logger.debug(f"Reduced to : time_dimension={self.time_dimension}. Array shape is : {new_state}")
|
|
551
556
|
# Return a tuple that replaces the parent's __setstate__ tuple with our own
|
|
@@ -656,7 +661,8 @@ class TimeMixin:
|
|
|
656
661
|
indexer.append(slice(None))
|
|
657
662
|
indexer = tuple(indexer)
|
|
658
663
|
|
|
659
|
-
shift_area = self.itime.__getitem__(
|
|
664
|
+
shift_area = self.itime.__getitem__(
|
|
665
|
+
period) if time_period else self.__getitem__(period)
|
|
660
666
|
|
|
661
667
|
# if not this : we lost a dimension because we sliced one axis to a single element, no need to no .mean
|
|
662
668
|
if not len(shift_area.shape) < len(self.shape):
|
|
@@ -678,7 +684,8 @@ class TimeMixin:
|
|
|
678
684
|
# we re-instanciate a TimelinedArray with view instead of the full constructor : faster
|
|
679
685
|
cls = self._get_array_cls()
|
|
680
686
|
|
|
681
|
-
swapped_array: TimeCompatibleProtocol = np.swapaxes(
|
|
687
|
+
swapped_array: TimeCompatibleProtocol = np.swapaxes(
|
|
688
|
+
np.asarray(self), axis1, axis2).view(cls) # type: ignore
|
|
682
689
|
swapped_array.timeline = self.timeline
|
|
683
690
|
|
|
684
691
|
if axis1 == self.time_dimension:
|
|
@@ -707,7 +714,8 @@ class TimeMixin:
|
|
|
707
714
|
cls = self._get_array_cls()
|
|
708
715
|
|
|
709
716
|
# we re-instanciate a TimelinedArray with view instead of the full constructor : faster
|
|
710
|
-
transposed_array: TimeCompatibleProtocol = np.transpose(
|
|
717
|
+
transposed_array: TimeCompatibleProtocol = np.transpose(
|
|
718
|
+
np.asarray(self), axes).view(cls) # type: ignore
|
|
711
719
|
transposed_array.timeline = self.timeline
|
|
712
720
|
|
|
713
721
|
if self.time_dimension in axes:
|
|
@@ -780,24 +788,36 @@ class TimeMixin:
|
|
|
780
788
|
# we re-instanciate a TimelinedArray with view instead of the full constructor : faster
|
|
781
789
|
cls = self._get_array_cls()
|
|
782
790
|
|
|
783
|
-
rolled_array: TimeCompatibleProtocol = np.rollaxis(
|
|
791
|
+
rolled_array: TimeCompatibleProtocol = np.rollaxis(
|
|
792
|
+
np.asarray(self), axis, start).view(cls) # type: ignore
|
|
793
|
+
|
|
794
|
+
# reinject timeline as is
|
|
784
795
|
rolled_array.timeline = self.timeline
|
|
785
|
-
rolled_array.time_dimension = self.time_dimension
|
|
786
|
-
|
|
787
|
-
if axis < self.time_dimension:
|
|
788
|
-
if start <= axis:
|
|
789
|
-
rolled_array.time_dimension += 1
|
|
790
|
-
elif start <= self.time_dimension:
|
|
791
|
-
rolled_array.time_dimension -= 1
|
|
792
|
-
elif axis == self.time_dimension:
|
|
793
|
-
rolled_array.time_dimension = start
|
|
794
|
-
else:
|
|
795
|
-
if start <= self.time_dimension:
|
|
796
|
-
rolled_array.time_dimension -= 1
|
|
797
|
-
elif start > self.time_dimension:
|
|
798
|
-
rolled_array.time_dimension += 1
|
|
799
796
|
|
|
800
|
-
#
|
|
797
|
+
# then fix the time_position according to the rolled axis
|
|
798
|
+
|
|
799
|
+
def rollaxis_mapping(shape, axis, start=0):
|
|
800
|
+
n = len(shape)
|
|
801
|
+
if axis < 0:
|
|
802
|
+
axis += n
|
|
803
|
+
if start < 0:
|
|
804
|
+
start += n
|
|
805
|
+
if not (0 <= axis < n and 0 <= start <= n):
|
|
806
|
+
raise ValueError("axis and start must be within valid range")
|
|
807
|
+
new_order = list(range(n))
|
|
808
|
+
|
|
809
|
+
axis_value = new_order.pop(axis)
|
|
810
|
+
|
|
811
|
+
if start > axis:
|
|
812
|
+
new_order.insert(start - 1, axis_value)
|
|
813
|
+
else:
|
|
814
|
+
new_order.insert(start, axis_value)
|
|
815
|
+
mapping = {i: new_order.index(i) for i in range(n)}
|
|
816
|
+
return mapping
|
|
817
|
+
|
|
818
|
+
rolled_array.time_dimension = rollaxis_mapping(
|
|
819
|
+
self.shape, axis, start)[self.time_dimension]
|
|
820
|
+
|
|
801
821
|
return rolled_array
|
|
802
822
|
|
|
803
823
|
def mean(
|
|
@@ -915,7 +935,8 @@ class TimeMixin:
|
|
|
915
935
|
# returns a modified version of the array, with the first element of the array to time zero,
|
|
916
936
|
# and shift the rest accordingly
|
|
917
937
|
cls = self._get_array_cls()
|
|
918
|
-
|
|
938
|
+
# type: ignore
|
|
939
|
+
return cls(self, timeline=self.timeline - self.timeline[at])
|
|
919
940
|
|
|
920
941
|
def offset_timeline(self, offset):
|
|
921
942
|
"""Returns a modified version of the array with time offset.
|
|
@@ -983,7 +1004,8 @@ class TimeMixin:
|
|
|
983
1004
|
break
|
|
984
1005
|
|
|
985
1006
|
if timeline is None:
|
|
986
|
-
raise ValueError(
|
|
1007
|
+
raise ValueError(
|
|
1008
|
+
"timeline must be supplied if the input_array is not a TimelinedArray")
|
|
987
1009
|
|
|
988
1010
|
if time_dimension is None: # same thing for the time dimension.
|
|
989
1011
|
time_dimension = getattr(data, "time_dimension", None)
|
|
@@ -1134,7 +1156,8 @@ class TimelinedArray(TimeMixin, np.ndarray, TimeCompatibleProtocol):
|
|
|
1134
1156
|
logger.debug(f"wrapping array after ufunc {context[0].__name__}")
|
|
1135
1157
|
output = super().__array_wrap__(out_arr, context)
|
|
1136
1158
|
if len(output.shape) < len(self.shape):
|
|
1137
|
-
logger.debug(
|
|
1159
|
+
logger.debug(
|
|
1160
|
+
f"shape reduced from : {self.shape} to : {output.shape}. outarray was : {out_arr.shape}")
|
|
1138
1161
|
return output
|
|
1139
1162
|
|
|
1140
1163
|
def __array_function__(self, func, types, args, kwargs):
|
|
@@ -1166,7 +1189,8 @@ class TimelinedArray(TimeMixin, np.ndarray, TimeCompatibleProtocol):
|
|
|
1166
1189
|
TimelinedArray | np.ndarray: Indexed result based on the provided index.
|
|
1167
1190
|
"""
|
|
1168
1191
|
|
|
1169
|
-
index, final_timeline, final_time_dimension = self._get_indexed_times(
|
|
1192
|
+
index, final_timeline, final_time_dimension = self._get_indexed_times(
|
|
1193
|
+
index)
|
|
1170
1194
|
|
|
1171
1195
|
if final_timeline is None or final_time_dimension is None:
|
|
1172
1196
|
return np.asarray(self).__getitem__(index)
|
|
@@ -1302,7 +1326,8 @@ class MaskedTimelinedArray(TimeMixin, np.ma.MaskedArray, TimeCompatibleProtocol)
|
|
|
1302
1326
|
MaskedTimelinedArray | np.ma.MaskedArray: The masked array or MaskedTimelinedArray based on the index.
|
|
1303
1327
|
"""
|
|
1304
1328
|
|
|
1305
|
-
index, final_timeline, final_time_dimension = self._get_indexed_times(
|
|
1329
|
+
index, final_timeline, final_time_dimension = self._get_indexed_times(
|
|
1330
|
+
index)
|
|
1306
1331
|
|
|
1307
1332
|
if final_timeline is None or final_time_dimension is None:
|
|
1308
1333
|
return np.ma.MaskedArray(data=np.asarray(self), mask=self.mask, fill_value=self.fill_value).__getitem__(
|
|
File without changes
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import pytest
|
|
3
|
+
from timelined_array import TimelinedArray, MaskedTimelinedArray
|
|
4
|
+
from timelined_array.time import (Timeline,
|
|
5
|
+
StartBoundary,
|
|
6
|
+
StoptBoundary,
|
|
7
|
+
EdgePolicy,
|
|
8
|
+
TimeIndexer,
|
|
9
|
+
TimeMixin,
|
|
10
|
+
TimePacker,
|
|
11
|
+
Seconds)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@pytest.fixture
|
|
15
|
+
def timelined_array_1D():
|
|
16
|
+
return TimelinedArray(np.random.rand(50),
|
|
17
|
+
timeline=np.arange(50),
|
|
18
|
+
time_dimension=0)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@pytest.fixture
|
|
22
|
+
def timelined_array_3D():
|
|
23
|
+
return TimelinedArray(np.random.rand(25, 50, 75),
|
|
24
|
+
timeline=np.arange(50),
|
|
25
|
+
time_dimension=1)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def get_axis_parameters_3D():
|
|
29
|
+
# affected_axis, time_dimension, shape
|
|
30
|
+
# if None, we expect an AttributeError
|
|
31
|
+
return [
|
|
32
|
+
(0, 0, (50, 75)),
|
|
33
|
+
(1, None, (25, 75)),
|
|
34
|
+
(2, 1, (25, 50)),
|
|
35
|
+
((0, 2), 0, (50,)),
|
|
36
|
+
(None, None, None)
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@pytest.mark.parametrize("shape, timeline_dimension", [
|
|
41
|
+
((12,), 0),
|
|
42
|
+
((10, 30, 50), 2),
|
|
43
|
+
((29, 34, 61, 15, 4), 0)
|
|
44
|
+
])
|
|
45
|
+
def test_ta_array_shape(shape, timeline_dimension):
|
|
46
|
+
ta_array = TimelinedArray(np.random.rand(*shape),
|
|
47
|
+
timeline=np.arange(
|
|
48
|
+
shape[timeline_dimension]),
|
|
49
|
+
time_dimension=timeline_dimension)
|
|
50
|
+
|
|
51
|
+
assert ta_array.shape == shape
|
|
52
|
+
assert ta_array.timeline.shape == (shape[timeline_dimension],)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def test_timeline_creation():
|
|
56
|
+
timeline = Timeline(np.arange(10))
|
|
57
|
+
assert isinstance(timeline, Timeline)
|
|
58
|
+
assert timeline.max() == 9
|
|
59
|
+
assert timeline.min() == 0
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def test_start_boundary():
|
|
63
|
+
assert StartBoundary.inclusive.value(5, 5)
|
|
64
|
+
assert not StartBoundary.exclusive.value(5, 5)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def test_stop_boundary():
|
|
68
|
+
assert StoptBoundary.inclusive.value(5, 5)
|
|
69
|
+
assert not StoptBoundary.exclusive.value(5, 5)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def test_edge_policy():
|
|
73
|
+
assert EdgePolicy.start.value == StartBoundary
|
|
74
|
+
assert EdgePolicy.stop.value == StoptBoundary
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def test_time_indexer(timelined_array_1D):
|
|
78
|
+
indexer = TimeIndexer(timelined_array_1D)
|
|
79
|
+
assert indexer.time_to_index(5) == 5
|
|
80
|
+
assert indexer.time_to_index(slice(2, 5)) == slice(2, 5, 1)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def test_time_mixin_methods(timelined_array_1D):
|
|
84
|
+
assert timelined_array_1D.sec_max() == 49
|
|
85
|
+
assert timelined_array_1D.sec_min() == 0
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def test_ta_transpose(timelined_array_3D):
|
|
89
|
+
transposed = timelined_array_3D.transpose(2, 0, 1)
|
|
90
|
+
assert transposed.shape == (75, 25, 50)
|
|
91
|
+
assert transposed.time_dimension == 2
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def test_ta_swapaxes(timelined_array_3D):
|
|
95
|
+
swapped = timelined_array_3D.swapaxes(1, 2)
|
|
96
|
+
assert swapped.shape == (25, 75, 50)
|
|
97
|
+
assert swapped.time_dimension == 2
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@pytest.mark.parametrize("rolled_axis, end_position, expected_time_position, expected_shape", [
|
|
101
|
+
(0, 2, 0, (50, 25, 75)),
|
|
102
|
+
(2, 1, 2, (25, 75, 50)),
|
|
103
|
+
(1, 3, 2, (25, 75, 50))
|
|
104
|
+
])
|
|
105
|
+
def test_ta_rollaxis(rolled_axis,
|
|
106
|
+
end_position,
|
|
107
|
+
expected_time_position,
|
|
108
|
+
expected_shape,
|
|
109
|
+
timelined_array_3D):
|
|
110
|
+
# roll back the axis
|
|
111
|
+
rolled = timelined_array_3D.rollaxis(rolled_axis, end_position)
|
|
112
|
+
assert rolled.shape == expected_shape
|
|
113
|
+
assert rolled.time_dimension == expected_time_position
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def axis_affecting_functions_blueprint(timelined_array_3D,
|
|
117
|
+
func,
|
|
118
|
+
affected_axis,
|
|
119
|
+
time_dimension,
|
|
120
|
+
shape):
|
|
121
|
+
result = func(timelined_array_3D, axis=affected_axis)
|
|
122
|
+
if time_dimension is None:
|
|
123
|
+
with pytest.raises(AttributeError):
|
|
124
|
+
result.time_dimension
|
|
125
|
+
else:
|
|
126
|
+
assert result.time_dimension == time_dimension
|
|
127
|
+
|
|
128
|
+
if shape is None:
|
|
129
|
+
with pytest.raises(AttributeError):
|
|
130
|
+
result.shape
|
|
131
|
+
else:
|
|
132
|
+
assert result.shape == shape
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
@pytest.mark.parametrize("affected_axis, time_dimension, shape", get_axis_parameters_3D())
|
|
136
|
+
def test_ta_mean(timelined_array_3D, affected_axis, time_dimension, shape):
|
|
137
|
+
axis_affecting_functions_blueprint(timelined_array_3D, np.mean,
|
|
138
|
+
affected_axis, time_dimension, shape)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
@pytest.mark.parametrize("affected_axis, time_dimension, shape", get_axis_parameters_3D())
|
|
142
|
+
def test_ta_sum(timelined_array_3D, affected_axis, time_dimension, shape):
|
|
143
|
+
axis_affecting_functions_blueprint(timelined_array_3D, np.sum,
|
|
144
|
+
affected_axis, time_dimension, shape)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
@pytest.mark.parametrize("affected_axis, time_dimension, shape", get_axis_parameters_3D())
|
|
148
|
+
def test_ta_std(timelined_array_3D, affected_axis, time_dimension, shape):
|
|
149
|
+
axis_affecting_functions_blueprint(timelined_array_3D, np.std,
|
|
150
|
+
affected_axis, time_dimension, shape)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
@pytest.mark.parametrize("affected_axis, time_dimension, shape", get_axis_parameters_3D())
|
|
154
|
+
def test_ta_var(timelined_array_3D, affected_axis, time_dimension, shape):
|
|
155
|
+
axis_affecting_functions_blueprint(timelined_array_3D, np.var,
|
|
156
|
+
affected_axis, time_dimension, shape)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def test_masked_ta_creation():
|
|
160
|
+
data = np.random.rand(10, 10)
|
|
161
|
+
mask = data > 0.5
|
|
162
|
+
masked_ta = MaskedTimelinedArray(
|
|
163
|
+
data, mask=mask, timeline=np.arange(10), time_dimension=0)
|
|
164
|
+
assert isinstance(masked_ta, MaskedTimelinedArray)
|
|
165
|
+
assert masked_ta.shape == (10, 10)
|
|
166
|
+
assert masked_ta.time_dimension == 0
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def test_seconds_to_index():
|
|
170
|
+
sec = Seconds(10)
|
|
171
|
+
assert sec.to_index(2) == 20
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import unittest
|
|
2
|
-
import numpy as np
|
|
3
|
-
from numpy.testing import assert_array_equal
|
|
4
|
-
from timelined_array.time import TimeIndexer, Timeline, TimelinedArray, MaskedTimelinedArray
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class TestTimeline(unittest.TestCase):
|
|
8
|
-
def test_timeline_creation(self):
|
|
9
|
-
timeline = Timeline([0, 1, 2, 3, 4])
|
|
10
|
-
self.assertEqual(timeline.max(), 4)
|
|
11
|
-
self.assertEqual(timeline.min(), 0)
|
|
12
|
-
|
|
13
|
-
def test_timeline_uniformize(self):
|
|
14
|
-
with self.assertRaises(NotImplementedError):
|
|
15
|
-
Timeline._uniformize([0, 1, 2, 3, 4])
|
|
16
|
-
|
|
17
|
-
def test_timeline_step(self):
|
|
18
|
-
timeline = Timeline([0, 1, 2, 3, 4])
|
|
19
|
-
self.assertEqual(timeline.step, 1)
|
|
20
|
-
|
|
21
|
-
def test_timeline_max_step(self):
|
|
22
|
-
timeline = Timeline([0, 1, 2, 3, 4])
|
|
23
|
-
self.assertEqual(timeline.max_step, 2)
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
class TestTimeIndexer(unittest.TestCase):
|
|
27
|
-
def setUp(self):
|
|
28
|
-
self.timeline = Timeline([0, 1, 2, 3, 4])
|
|
29
|
-
self.array = TimelinedArray(np.random.rand(5, 5), timeline=self.timeline, time_dimension=0)
|
|
30
|
-
self.indexer = TimeIndexer(self.array)
|
|
31
|
-
|
|
32
|
-
def test_time_to_index(self):
|
|
33
|
-
self.assertEqual(self.indexer.time_to_index(2), 2)
|
|
34
|
-
|
|
35
|
-
def test_get_iindex(self):
|
|
36
|
-
self.assertEqual(self.indexer.get_iindex(1, 3), slice(1, 3, 1))
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
class TestTimelinedArray(unittest.TestCase):
|
|
40
|
-
def setUp(self):
|
|
41
|
-
self.timeline = Timeline([0, 1, 2, 3, 4])
|
|
42
|
-
self.array = TimelinedArray(np.random.rand(5, 5), timeline=self.timeline, time_dimension=0)
|
|
43
|
-
|
|
44
|
-
def test_array_creation(self):
|
|
45
|
-
self.assertEqual(self.array.shape, (5, 5))
|
|
46
|
-
self.assertEqual(self.array.timeline.max(), 4)
|
|
47
|
-
self.assertEqual(self.array.time_dimension, 0)
|
|
48
|
-
|
|
49
|
-
def test_array_indexing(self):
|
|
50
|
-
indexed_array = self.array[1:3]
|
|
51
|
-
self.assertEqual(indexed_array.shape, (2, 5))
|
|
52
|
-
self.assertEqual(indexed_array.timeline.min(), 1)
|
|
53
|
-
self.assertEqual(indexed_array.timeline.max(), 2)
|
|
54
|
-
|
|
55
|
-
def test_array_transpose(self):
|
|
56
|
-
transposed_array = self.array.transpose()
|
|
57
|
-
self.assertEqual(transposed_array.shape, (5, 5))
|
|
58
|
-
self.assertEqual(transposed_array.time_dimension, 1)
|
|
59
|
-
|
|
60
|
-
def test_array_mean(self):
|
|
61
|
-
mean_value = self.array.mean(axis=0)
|
|
62
|
-
self.assertEqual(mean_value.shape, (5,))
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
class TestMaskedTimelinedArray(unittest.TestCase):
|
|
66
|
-
def setUp(self):
|
|
67
|
-
self.timeline = Timeline([0, 1, 2, 3, 4])
|
|
68
|
-
self.data = np.random.rand(5, 5)
|
|
69
|
-
self.mask = np.zeros((5, 5), dtype=bool)
|
|
70
|
-
self.mask[0, 0] = True
|
|
71
|
-
self.array = MaskedTimelinedArray(self.data, mask=self.mask, timeline=self.timeline, time_dimension=0)
|
|
72
|
-
|
|
73
|
-
def test_masked_array_creation(self):
|
|
74
|
-
self.assertEqual(self.array.shape, (5, 5))
|
|
75
|
-
self.assertEqual(self.array.timeline.max(), 4)
|
|
76
|
-
self.assertEqual(self.array.time_dimension, 0)
|
|
77
|
-
self.assertTrue(self.array.mask[0, 0])
|
|
78
|
-
|
|
79
|
-
def test_masked_array_indexing(self):
|
|
80
|
-
indexed_array = self.array[1:3]
|
|
81
|
-
self.assertEqual(indexed_array.shape, (2, 5))
|
|
82
|
-
self.assertEqual(indexed_array.timeline.min(), 1)
|
|
83
|
-
self.assertEqual(indexed_array.timeline.max(), 2)
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
class TestMultidimensionnalIndexing(unittest.TestCase):
|
|
87
|
-
def setUp(self):
|
|
88
|
-
dimension = (15, 150, 200, 200)
|
|
89
|
-
y_dim_scale = 2
|
|
90
|
-
prime = [
|
|
91
|
-
[
|
|
92
|
-
(
|
|
93
|
-
np.array(
|
|
94
|
-
[
|
|
95
|
-
np.roll(np.linspace(phase, phase * 2, num=dimension[3], endpoint=True), shift=r)
|
|
96
|
-
for r in np.arange(0, dimension[2] * y_dim_scale, y_dim_scale)
|
|
97
|
-
]
|
|
98
|
-
)
|
|
99
|
-
* t
|
|
100
|
-
)
|
|
101
|
-
for t in np.sin(np.linspace(phase, phase + 2, num=dimension[1]))
|
|
102
|
-
]
|
|
103
|
-
for phase in np.linspace(1, dimension[0], num=dimension[0], endpoint=True)
|
|
104
|
-
]
|
|
105
|
-
prime = np.array(prime)
|
|
106
|
-
sin = np.sin(prime)
|
|
107
|
-
self.array = TimelinedArray(sin, time_dimension=1, timeline=np.linspace(-2, 7, num=300))
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
if __name__ == "__main__":
|
|
111
|
-
unittest.main()
|
|
File without changes
|