Skip to content

Commit d364883

Browse files
authored
Merge branch 'pynapple-org:main' into main
2 parents 87d2486 + 4039000 commit d364883

13 files changed

+363
-216
lines changed

docs/examples/tutorial_pynapple_numpy.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,13 @@
139139

140140
print(np.concatenate((tsd1, tsd2, tsd3)))
141141

142+
#%%
143+
# It's also possible to concatenate vertically if time indexes matches up to pynapple float precision
144+
145+
tsdframe = nap.TsdFrame(t=np.arange(5), d=np.random.randn(5, 3))
146+
147+
print(np.concatenate((tsdframe, tsdframe), 1))
148+
142149
# %%
143150
# Spliting
144151
# --------

pynapple/core/base_class.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -426,8 +426,8 @@ def get(self, start, end=None, time_units="s"):
426426
Parameters
427427
----------
428428
start : float or int
429-
The start
430-
end : float or int
429+
The start (or closest time point if `end` is None)
430+
end : float or int or None
431431
The end
432432
"""
433433
assert isinstance(start, Number), "start should be a float or int"

pynapple/core/interval_set.py

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,11 @@ def __init__(self, start, end=None, time_units="s", **kwargs):
9696
If `start` and `end` arguments are of unknown type
9797
9898
"""
99-
if isinstance(start, pd.DataFrame):
99+
if isinstance(start, IntervalSet):
100+
end = start.values[:, 1].astype(np.float64)
101+
start = start.values[:, 0].astype(np.float64)
102+
103+
elif isinstance(start, pd.DataFrame):
100104
assert (
101105
"start" in start.columns
102106
and "end" in start.columns
@@ -558,7 +562,7 @@ def save(self, filename):
558562
objects. For example, you determined some epochs for one session that you want to save
559563
to avoid recomputing them.
560564
561-
You can load the object with numpy.load. Keys are 'start', 'end' and 'type'.
565+
You can load the object with `nap.load_file`. Keys are 'start', 'end' and 'type'.
562566
See the example below.
563567
564568
Parameters
@@ -573,16 +577,10 @@ def save(self, filename):
573577
>>> ep = nap.IntervalSet(start=[0, 10, 20], end=[5, 12, 33])
574578
>>> ep.save("my_ep.npz")
575579
576-
Here I can retrieve my data with numpy directly:
577-
578-
>>> file = np.load("my_ep.npz")
579-
>>> print(list(file.keys()))
580-
['start', 'end', 'type']
581-
>>> print(file['start'])
582-
[0. 10. 20.]
580+
To load you file, you can use the `nap.load_file` function :
583581
584-
It is then easy to recreate the IntervalSet object.
585-
>>> nap.IntervalSet(file['start'], file['end'])
582+
>>> ep = nap.load_file("my_path/my_ep.npz")
583+
>>> ep
586584
start end
587585
0 0.0 5.0
588586
1 10.0 12.0

pynapple/core/time_index.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
33
Similar to pandas.Index, `TsIndex` holds the timestamps associated with the data of a time series.
44
This class deals with conversion between different time units for all pynapple objects as well
5-
as making sure that timestamps are property sorted before initializing any objects.
5+
as making sure that timestamps are property sorted before initializing any objects.
6+
67
- `us`: microseconds
78
- `ms`: milliseconds
89
- `s`: seconds (overall default)

pynapple/core/time_series.py

Lines changed: 35 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,20 @@ def __setitem__(self, key, value):
117117
except IndexError:
118118
raise IndexError
119119

120+
def __getattr__(self, name):
121+
"""Allow numpy functions to be attached as attributes of Tsd objects"""
122+
if hasattr(np, name):
123+
np_func = getattr(np, name)
124+
125+
def method(*args, **kwargs):
126+
return np_func(self, *args, **kwargs)
127+
128+
return method
129+
130+
raise AttributeError(
131+
"Time series object does not have the attribute {}".format(name)
132+
)
133+
120134
@property
121135
def d(self):
122136
return self.values
@@ -178,8 +192,6 @@ def __array_ufunc__(self, ufunc, method, *args, **kwargs):
178192

179193
def __array_function__(self, func, types, args, kwargs):
180194
if func in [
181-
np.hstack,
182-
np.dstack,
183195
np.sort,
184196
np.lexsort,
185197
np.sort_complex,
@@ -194,12 +206,8 @@ def __array_function__(self, func, types, args, kwargs):
194206
if func in [np.split, np.array_split, np.dsplit, np.hsplit, np.vsplit]:
195207
return _split_tsd(func, *args, **kwargs)
196208

197-
if func in [np.vstack, np.concatenate]:
198-
if func == np.concatenate:
199-
if "axis" in kwargs:
200-
if kwargs["axis"] != 0:
201-
return NotImplemented
202-
return _concatenate_tsd(func, *args)
209+
if func in [np.concatenate, np.vstack, np.hstack, np.dstack]:
210+
return _concatenate_tsd(func, *args, **kwargs)
203211

204212
new_args = []
205213
for a in args:
@@ -655,7 +663,7 @@ def save(self, filename):
655663
filtered them. You can save the filtered channels as a npz to avoid
656664
reprocessing it.
657665
658-
You can load the object with numpy.load. Keys are 't', 'd', 'start', 'end', 'type'
666+
You can load the object with `nap.load_file`. Keys are 't', 'd', 'start', 'end', 'type'
659667
and 'columns' for columns names.
660668
661669
Parameters
@@ -670,21 +678,9 @@ def save(self, filename):
670678
>>> tsdtensor = nap.TsdTensor(t=np.array([0., 1.]), d = np.zeros((2,3,4)))
671679
>>> tsdtensor.save("my_path/my_tsdtensor.npz")
672680
673-
Here I can retrieve my data with numpy directly:
674-
675-
>>> file = np.load("my_path/my_tsdtensor.npz")
676-
>>> print(list(file.keys()))
677-
['t', 'd', 'start', 'end', ''type']
678-
>>> print(file['t'])
679-
[0. 1.]
680-
681-
It is then easy to recreate the TsdTensor object.
682-
>>> time_support = nap.IntervalSet(file['start'], file['end'])
683-
>>> nap.TsdTensor(t=file['t'], d=file['d'], time_support=time_support)
684-
Time (s)
685-
0.0 [[[0.0 ...]]]
686-
1.0 [[[0.0 ...]]]
681+
To load you file, you can use the `nap.load_file` function :
687682
683+
>>> tsdtensor = nap.load_file("my_path/my_tsdtensor.npz")
688684
689685
Raises
690686
------
@@ -911,7 +907,7 @@ def save(self, filename):
911907
filtered them. You can save the filtered channels as a npz to avoid
912908
reprocessing it.
913909
914-
You can load the object with numpy.load. Keys are 't', 'd', 'start', 'end', 'type'
910+
You can load the object with `nap.load_file`. Keys are 't', 'd', 'start', 'end', 'type'
915911
and 'columns' for columns names.
916912
917913
Parameters
@@ -926,17 +922,10 @@ def save(self, filename):
926922
>>> tsdframe = nap.TsdFrame(t=np.array([0., 1.]), d = np.array([[2, 3],[4,5]]), columns=['a', 'b'])
927923
>>> tsdframe.save("my_path/my_tsdframe.npz")
928924
929-
Here I can retrieve my data with numpy directly:
930-
931-
>>> file = np.load("my_path/my_tsdframe.npz")
932-
>>> print(list(file.keys()))
933-
['t', 'd', 'start', 'end', 'columns', 'type']
934-
>>> print(file['t'])
935-
[0. 1.]
925+
To load you file, you can use the `nap.load_file` function :
936926
937-
It is then easy to recreate the Tsd object.
938-
>>> time_support = nap.IntervalSet(file['start'], file['end'])
939-
>>> nap.TsdFrame(t=file['t'], d=file['d'], time_support=time_support, columns=file['columns'])
927+
>>> tsdframe = nap.load_file("my_path/my_tsdframe.npz")
928+
>>> tsdframe
940929
a b
941930
Time (s)
942931
0.0 2 3
@@ -1208,6 +1197,7 @@ def to_tsgroup(self):
12081197
TsGroup
12091198
Grouped timestamps
12101199
1200+
12111201
"""
12121202
ts_group = importlib.import_module(".ts_group", "pynapple.core")
12131203
t = self.index.values
@@ -1218,7 +1208,9 @@ def to_tsgroup(self):
12181208
for k in idx:
12191209
group[k] = Ts(t=t[d == k], time_support=self.time_support)
12201210

1221-
return ts_group.TsGroup(group, time_support=self.time_support)
1211+
return ts_group.TsGroup(
1212+
group, time_support=self.time_support, bypass_check=True
1213+
)
12221214

12231215
def save(self, filename):
12241216
"""
@@ -1230,7 +1222,7 @@ def save(self, filename):
12301222
filtered it. You can save the filtered channel as a npz to avoid
12311223
reprocessing it.
12321224
1233-
You can load the object with numpy.load. Keys are 't', 'd', 'start', 'end' and 'type'.
1225+
You can load the object with `nap.load_file`. Keys are 't', 'd', 'start', 'end' and 'type'.
12341226
See the example below.
12351227
12361228
Parameters
@@ -1245,17 +1237,10 @@ def save(self, filename):
12451237
>>> tsd = nap.Tsd(t=np.array([0., 1.]), d = np.array([2, 3]))
12461238
>>> tsd.save("my_path/my_tsd.npz")
12471239
1248-
Here I can retrieve my data with numpy directly:
1240+
To load you file, you can use the `nap.load_file` function :
12491241
1250-
>>> file = np.load("my_path/my_tsd.npz")
1251-
>>> print(list(file.keys()))
1252-
['t', 'd', 'start', 'end', 'type']
1253-
>>> print(file['t'])
1254-
[0. 1.]
1255-
1256-
It is then easy to recreate the Tsd object.
1257-
>>> time_support = nap.IntervalSet(file['start'], file['end'])
1258-
>>> nap.Tsd(t=file['t'], d=file['d'], time_support=time_support)
1242+
>>> tsd = nap.load_file("my_path/my_tsd.npz")
1243+
>>> tsd
12591244
Time (s)
12601245
0.0 2
12611246
1.0 3
@@ -1524,7 +1509,7 @@ def save(self, filename):
15241509
The main purpose of this function is to save small/medium sized timestamps
15251510
object.
15261511
1527-
You can load the object with numpy.load. Keys are 't', 'start' and 'end' and 'type'.
1512+
You can load the object with `nap.load_file`. Keys are 't', 'start' and 'end' and 'type'.
15281513
See the example below.
15291514
15301515
Parameters
@@ -1539,23 +1524,15 @@ def save(self, filename):
15391524
>>> ts = nap.Ts(t=np.array([0., 1., 1.5]))
15401525
>>> ts.save("my_path/my_ts.npz")
15411526
1542-
Here I can retrieve my data with numpy directly:
1543-
1544-
>>> file = np.load("my_path/my_ts.npz")
1545-
>>> print(list(file.keys()))
1546-
['t', 'start', 'end', 'type']
1547-
>>> print(file['t'])
1548-
[0. 1. 1.5]
1527+
To load you file, you can use the `nap.load_file` function :
15491528
1550-
It is then easy to recreate the Tsd object.
1551-
>>> time_support = nap.IntervalSet(file['start'], file['end'])
1552-
>>> nap.Ts(t=file['t'], time_support=time_support)
1529+
>>> ts = nap.load_file("my_path/my_ts.npz")
1530+
>>> ts
15531531
Time (s)
15541532
0.0
15551533
1.0
15561534
1.5
15571535
1558-
15591536
Raises
15601537
------
15611538
RuntimeError

0 commit comments

Comments
 (0)