diff --git a/docs/examples/tutorial_pynapple_numpy.py b/docs/examples/tutorial_pynapple_numpy.py index 73d0b899..40c13da8 100644 --- a/docs/examples/tutorial_pynapple_numpy.py +++ b/docs/examples/tutorial_pynapple_numpy.py @@ -144,7 +144,7 @@ tsdframe = nap.TsdFrame(t=np.arange(5), d=np.random.randn(5, 3)) -print(np.concatenate(tsdframe, tsdframe), 1) +print(np.concatenate((tsdframe, tsdframe), 1)) # %% # Spliting diff --git a/pynapple/core/interval_set.py b/pynapple/core/interval_set.py index 652a4a65..ca1046aa 100644 --- a/pynapple/core/interval_set.py +++ b/pynapple/core/interval_set.py @@ -562,7 +562,7 @@ def save(self, filename): objects. For example, you determined some epochs for one session that you want to save to avoid recomputing them. - You can load the object with numpy.load. Keys are 'start', 'end' and 'type'. + You can load the object with `nap.load_file`. Keys are 'start', 'end' and 'type'. See the example below. Parameters @@ -577,16 +577,10 @@ def save(self, filename): >>> ep = nap.IntervalSet(start=[0, 10, 20], end=[5, 12, 33]) >>> ep.save("my_ep.npz") - Here I can retrieve my data with numpy directly: + To load you file, you can use the `nap.load_file` function : - >>> file = np.load("my_ep.npz") - >>> print(list(file.keys())) - ['start', 'end', 'type'] - >>> print(file['start']) - [0. 10. 20.] - - It is then easy to recreate the IntervalSet object. - >>> nap.IntervalSet(file['start'], file['end']) + >>> ep = nap.load_file("my_path/my_ep.npz") + >>> ep start end 0 0.0 5.0 1 10.0 12.0 diff --git a/pynapple/core/time_index.py b/pynapple/core/time_index.py index c1c1333d..d5eb64a1 100644 --- a/pynapple/core/time_index.py +++ b/pynapple/core/time_index.py @@ -2,7 +2,8 @@ Similar to pandas.Index, `TsIndex` holds the timestamps associated with the data of a time series. This class deals with conversion between different time units for all pynapple objects as well - as making sure that timestamps are property sorted before initializing any objects. + as making sure that timestamps are property sorted before initializing any objects. + - `us`: microseconds - `ms`: milliseconds - `s`: seconds (overall default) diff --git a/pynapple/core/time_series.py b/pynapple/core/time_series.py index bb1f5b8f..5b4c24c4 100644 --- a/pynapple/core/time_series.py +++ b/pynapple/core/time_series.py @@ -658,7 +658,7 @@ def save(self, filename): filtered them. You can save the filtered channels as a npz to avoid reprocessing it. - You can load the object with numpy.load. Keys are 't', 'd', 'start', 'end', 'type' + You can load the object with `nap.load_file`. Keys are 't', 'd', 'start', 'end', 'type' and 'columns' for columns names. Parameters @@ -673,21 +673,9 @@ def save(self, filename): >>> tsdtensor = nap.TsdTensor(t=np.array([0., 1.]), d = np.zeros((2,3,4))) >>> tsdtensor.save("my_path/my_tsdtensor.npz") - Here I can retrieve my data with numpy directly: - - >>> file = np.load("my_path/my_tsdtensor.npz") - >>> print(list(file.keys())) - ['t', 'd', 'start', 'end', ''type'] - >>> print(file['t']) - [0. 1.] - - It is then easy to recreate the TsdTensor object. - >>> time_support = nap.IntervalSet(file['start'], file['end']) - >>> nap.TsdTensor(t=file['t'], d=file['d'], time_support=time_support) - Time (s) - 0.0 [[[0.0 ...]]] - 1.0 [[[0.0 ...]]] + To load you file, you can use the `nap.load_file` function : + >>> tsdtensor = nap.load_file("my_path/my_tsdtensor.npz") Raises ------ @@ -914,7 +902,7 @@ def save(self, filename): filtered them. You can save the filtered channels as a npz to avoid reprocessing it. - You can load the object with numpy.load. Keys are 't', 'd', 'start', 'end', 'type' + You can load the object with `nap.load_file`. Keys are 't', 'd', 'start', 'end', 'type' and 'columns' for columns names. Parameters @@ -929,17 +917,10 @@ def save(self, filename): >>> tsdframe = nap.TsdFrame(t=np.array([0., 1.]), d = np.array([[2, 3],[4,5]]), columns=['a', 'b']) >>> tsdframe.save("my_path/my_tsdframe.npz") - Here I can retrieve my data with numpy directly: - - >>> file = np.load("my_path/my_tsdframe.npz") - >>> print(list(file.keys())) - ['t', 'd', 'start', 'end', 'columns', 'type'] - >>> print(file['t']) - [0. 1.] + To load you file, you can use the `nap.load_file` function : - It is then easy to recreate the Tsd object. - >>> time_support = nap.IntervalSet(file['start'], file['end']) - >>> nap.TsdFrame(t=file['t'], d=file['d'], time_support=time_support, columns=file['columns']) + >>> tsdframe = nap.load_file("my_path/my_tsdframe.npz") + >>> tsdframe a b Time (s) 0.0 2 3 @@ -1236,7 +1217,7 @@ def save(self, filename): filtered it. You can save the filtered channel as a npz to avoid reprocessing it. - You can load the object with numpy.load. Keys are 't', 'd', 'start', 'end' and 'type'. + You can load the object with `nap.load_file`. Keys are 't', 'd', 'start', 'end' and 'type'. See the example below. Parameters @@ -1251,17 +1232,10 @@ def save(self, filename): >>> tsd = nap.Tsd(t=np.array([0., 1.]), d = np.array([2, 3])) >>> tsd.save("my_path/my_tsd.npz") - Here I can retrieve my data with numpy directly: + To load you file, you can use the `nap.load_file` function : - >>> file = np.load("my_path/my_tsd.npz") - >>> print(list(file.keys())) - ['t', 'd', 'start', 'end', 'type'] - >>> print(file['t']) - [0. 1.] - - It is then easy to recreate the Tsd object. - >>> time_support = nap.IntervalSet(file['start'], file['end']) - >>> nap.Tsd(t=file['t'], d=file['d'], time_support=time_support) + >>> tsd = nap.load_file("my_path/my_tsd.npz") + >>> tsd Time (s) 0.0 2 1.0 3 @@ -1530,7 +1504,7 @@ def save(self, filename): The main purpose of this function is to save small/medium sized timestamps object. - You can load the object with numpy.load. Keys are 't', 'start' and 'end' and 'type'. + You can load the object with `nap.load_file`. Keys are 't', 'start' and 'end' and 'type'. See the example below. Parameters @@ -1545,23 +1519,15 @@ def save(self, filename): >>> ts = nap.Ts(t=np.array([0., 1., 1.5])) >>> ts.save("my_path/my_ts.npz") - Here I can retrieve my data with numpy directly: - - >>> file = np.load("my_path/my_ts.npz") - >>> print(list(file.keys())) - ['t', 'start', 'end', 'type'] - >>> print(file['t']) - [0. 1. 1.5] + To load you file, you can use the `nap.load_file` function : - It is then easy to recreate the Tsd object. - >>> time_support = nap.IntervalSet(file['start'], file['end']) - >>> nap.Ts(t=file['t'], time_support=time_support) + >>> ts = nap.load_file("my_path/my_ts.npz") + >>> ts Time (s) 0.0 1.0 1.5 - Raises ------ RuntimeError diff --git a/pynapple/core/ts_group.py b/pynapple/core/ts_group.py index 0e545e29..325c9e2e 100644 --- a/pynapple/core/ts_group.py +++ b/pynapple/core/ts_group.py @@ -888,28 +888,33 @@ def save(self, filename): and assigning to each the corresponding index. Typically, a TsGroup like this : - TsGroup({ - 0 : Tsd(t=[0, 2, 4], d=[1, 2, 3]) - 1 : Tsd(t=[1, 5], d=[5, 6]) - }) + ``` py + TsGroup({ + 0 : Tsd(t=[0, 2, 4], d=[1, 2, 3]) + 1 : Tsd(t=[1, 5], d=[5, 6]) + }) + ``` will be saved as npz with the following keys: - { - 't' : [0, 1, 2, 4, 5], - 'd' : [1, 5, 2, 3, 5], - 'index' : [0, 1, 0, 0, 1], - 'start' : [0], - 'end' : [5], - 'type' : 'TsGroup' - } + ``` py + { + 't' : [0, 1, 2, 4, 5], + 'd' : [1, 5, 2, 3, 5], + 'index' : [0, 1, 0, 0, 1], + 'start' : [0], + 'end' : [5], + 'keys' : [0, 1], + 'type' : 'TsGroup' + } + ``` Metadata are saved by columns with the column name as the npz key. To avoid potential conflicts, make sure the columns name of the metadata are different - from ['t', 'd', 'start', 'end', 'index'] + from ['t', 'd', 'start', 'end', 'index', 'keys'] - You can load the object with numpy.load. Default keys are 't', 'd'(optional), - 'start', 'end', 'index' and 'type'. + You can load the object with `nap.load_file`. Default keys are 't', 'd'(optional), + 'start', 'end', 'index', 'keys' and 'type'. See the example below. Parameters @@ -935,21 +940,9 @@ def save(self, filename): 6 0.4 1 left foot >>> tsgroup.save("my_tsgroup.npz") - Here I can retrieve my data with numpy directly: - - >>> file = np.load("my_tsgroup.npz") - >>> print(list(file.keys())) - ['rate', 'group', 'location', 't', 'index', 'start', 'end', 'type'] - >>> print(file['index']) - [0 6 0 0 6] + To get back to pynapple, you can use the `nap.load_file` function : - In the case where TsGroup is a set of Ts objects, it is very direct to - recreate the TsGroup by using the function to_tsgroup : - - >>> time_support = nap.IntervalSet(file['start'], file['end']) - >>> tsd = nap.Tsd(t=file['t'], d=file['index'], time_support = time_support) - >>> tsgroup = tsd.to_tsgroup() - >>> tsgroup.set_info(group = file['group'], location = file['location']) + >>> tsgroup = nap.load_file("my_tsgroup.npz") >>> tsgroup Index rate group location ------- ------ ------- ---------- @@ -981,7 +974,7 @@ def save(self, filename): dicttosave = {"type": np.array(["TsGroup"], dtype=np.str_)} for k in self._metadata.columns: - if k not in ["t", "d", "start", "end", "index"]: + if k not in ["t", "d", "start", "end", "index", "keys"]: tmp = self._metadata[k].values if tmp.dtype == np.dtype("O"): tmp = tmp.astype(np.str_) @@ -1012,7 +1005,7 @@ def save(self, filename): dicttosave["index"] = index if not np.all(np.isnan(data)): dicttosave["d"] = data[idx] - + dicttosave["keys"] = np.array(self.keys()) dicttosave["start"] = self.time_support.start dicttosave["end"] = self.time_support.end diff --git a/pynapple/io/interface_npz.py b/pynapple/io/interface_npz.py index efd738b8..968e7d6f 100644 --- a/pynapple/io/interface_npz.py +++ b/pynapple/io/interface_npz.py @@ -4,7 +4,7 @@ # @Author: Guillaume Viejo # @Date: 2023-07-05 16:03:25 # @Last Modified by: Guillaume Viejo -# @Last Modified time: 2023-09-26 18:00:54 +# @Last Modified time: 2024-04-02 14:32:25 """ File classes help to validate and load pynapple objects or NWB files. @@ -89,12 +89,35 @@ def load(self): else: time_support = nap.IntervalSet(self.file["start"], self.file["end"]) if self.type == "TsGroup": - tsd = nap.Tsd( - t=self.file["t"], d=self.file["index"], time_support=time_support - ) - tsgroup = tsd.to_tsgroup() + + times = self.file["t"] + index = self.file["index"] + has_data = False if "d" in self.file.keys(): - print("TODO") + data = self.file["data"] + has_data = True + + if "keys" in self.file.keys(): + keys = self.file["keys"] + else: + keys = np.unique(index) + + group = {} + for k in keys: + if has_data: + group[k] = nap.Tsd( + t=times[index == k], + d=data[index == k], + time_support=time_support, + ) + else: + group[k] = nap.Ts( + t=times[index == k], time_support=time_support + ) + + tsgroup = nap.TsGroup( + group, time_support=time_support, bypass_check=True + ) metainfo = {} for k in set(self.file.keys()) - {