Skip to content

Commit d9814b8

Browse files
authored
Merge branch 'master' into remove-copy
2 parents d640ec8 + 585fdbe commit d9814b8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+479
-140
lines changed

.github/workflows/core-test.yml

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,24 +26,9 @@ jobs:
2626
matrix:
2727
os: ["ubuntu-latest", "windows-latest"]
2828
# "macos-latest",
29-
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
30-
numpy-version: ['1.20.3', '1.21.6', '1.22.4', '1.23.5', '1.24.1', '1.25.1', '1.26.4']
29+
python-version: ['3.9', '3.10', '3.11', '3.12']
30+
numpy-version: ['1.22.4', '1.23.5', '1.24.1', '1.25.1', '1.26.4']
3131
exclude:
32-
- python-version: '3.8'
33-
numpy-version: '1.25.1'
34-
- python-version: '3.8'
35-
numpy-version: '1.26.4'
36-
- python-version: '3.10'
37-
numpy-version: '1.20.3'
38-
- python-version: '3.11'
39-
numpy-version: '1.20.3'
40-
- python-version: '3.11'
41-
numpy-version: '1.21.6'
42-
- python-version: '3.12'
43-
numpy-version: '1.20.3'
44-
# python 3.12 only works on latest numpy
45-
- python-version: '3.12'
46-
numpy-version: '1.21.6'
4732
- python-version: '3.12'
4833
numpy-version: '1.22.4'
4934
- python-version: '3.12'

README.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ grant agreement FETPI-015879 (FACETS), by the European Union Seventh Framework P
6464
under grant agreements no. 269921 (BrainScaleS) and no. 604102 (HBP),
6565
and by the European Union’s Horizon 2020 Framework Programme for
6666
Research and Innovation under the Specific Grant Agreements No. 720270 (Human Brain Project SGA1),
67-
No. 785907 (Human Brain Project SGA2) and No. 945539 (Human Brain Project SGA3).
67+
No. 785907 (Human Brain Project SGA2) and No. 945539 (Human Brain Project SGA3),
68+
and by the European Union's Research and Innovation Program Horizon Europe Grant Agreement No. 101147319 (EBRAINS 2.0).
6869

6970
.. _OpenElectrophy: https://github.com/OpenElectrophy/OpenElectrophy
7071
.. _Elephant: http://neuralensemble.org/elephant

neo/io/igorproio.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,24 @@ def _wave_to_analogsignal(self, content, dirpath):
133133
header = content["wave_header"]
134134
name = str(header["bname"].decode("utf-8"))
135135
units = "".join([x.decode() for x in header["dataUnits"]])
136-
time_units = "".join([x.decode() for x in header["xUnits"]])
136+
if "xUnits" in header:
137+
# "xUnits" is used in Versions 1, 2, 3 of .pxp files
138+
time_units = "".join([x.decode() for x in header["xUnits"]])
139+
elif "dimUnits" in header:
140+
# Version 5 uses "dimUnits"
141+
# see https://github.com/AFM-analysis/igor2/blob/43fccf51714661fb96372e8119c59e17ce01f683/igor2/binarywave.py#L501
142+
_time_unit_structure = header["dimUnits"].ravel()
143+
# For the files we've seen so far, the first element of _time_unit_structure contains the units.
144+
# If someone has a file for which this assumption does not hold an Exception will be raised.
145+
if not all([element == b"" for element in _time_unit_structure[1:]]):
146+
raise Exception(
147+
"Neo cannot yet handle the units in this file. "
148+
"Please create a new issue in the Neo issue tracker at "
149+
"https://github.com/NeuralEnsemble/python-neo/issues/new/choose"
150+
)
151+
time_units = _time_unit_structure[0].decode()
152+
else:
153+
time_units = ""
137154
if len(time_units) == 0:
138155
time_units = "s"
139156
try:

neo/io/neuronexusio.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ class NeuroNexusIO(NeuroNexusRawIO, BaseFromRaw):
88

99
def __init__(self, filename):
1010
NeuroNexusRawIO.__init__(self, filename=filename)
11-
BaseFromRaw.__init__(self, filename)
11+
BaseFromRaw.__init__(self, filename)

neo/rawio/alphaomegarawio.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535

3636
from .baserawio import (
3737
BaseRawIO,
38+
_signal_buffer_dtype,
3839
_signal_stream_dtype,
3940
_signal_channel_dtype,
4041
_spike_channel_dtype,
@@ -652,8 +653,9 @@ def _parse_header(self):
652653
# could be loaded in any order
653654
self._merge_segments()
654655

656+
buffer_id = ""
655657
signal_streams = set(
656-
(stream_name, stream_id)
658+
(stream_name, stream_id, buffer_id)
657659
for segment in self._segments
658660
for stream in segment["streams"]
659661
for stream_name, _, stream_id in self.STREAM_CHANNELS
@@ -662,7 +664,9 @@ def _parse_header(self):
662664
signal_streams = list(signal_streams)
663665
signal_streams.sort(key=lambda x: x[1])
664666
signal_streams = np.array(signal_streams, dtype=_signal_stream_dtype)
667+
signal_buffers = np.array([], dtype=_signal_buffer_dtype)
665668

669+
buffer_id = ""
666670
signal_channels = set(
667671
(
668672
channel["name"],
@@ -672,11 +676,12 @@ def _parse_header(self):
672676
"uV",
673677
channel["gain"] / channel["bit_resolution"],
674678
0,
675-
stream,
679+
stream_id,
680+
buffer_id,
676681
)
677682
for segment in self._segments
678-
for stream in segment["streams"]
679-
for channel_id, channel in segment["streams"][stream].items()
683+
for stream_id in segment["streams"]
684+
for channel_id, channel in segment["streams"][stream_id].items()
680685
)
681686
signal_channels = list(signal_channels)
682687
signal_channels.sort(key=lambda x: (x[7], x[0]))
@@ -709,6 +714,7 @@ def _parse_header(self):
709714
self.header = {}
710715
self.header["nb_block"] = 1
711716
self.header["nb_segment"] = [len(self._segments)]
717+
self.header["signal_buffers"] = signal_buffers
712718
self.header["signal_streams"] = signal_streams
713719
self.header["signal_channels"] = signal_channels
714720
self.header["spike_channels"] = spike_channels

neo/rawio/axographrawio.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@
158158
BaseRawIO,
159159
_signal_channel_dtype,
160160
_signal_stream_dtype,
161+
_signal_buffer_dtype,
161162
_spike_channel_dtype,
162163
_event_channel_dtype,
163164
)
@@ -811,7 +812,19 @@ def _scan_axograph_file(self):
811812
self.logger.debug("initial data: {array[:5] * gain + offset}")
812813

813814
# channel_info will be cast to _signal_channel_dtype
814-
channel_info = (name, str(i), 1 / sampling_period, f.byte_order + dtype, units, gain, offset, "0")
815+
buffer_id = ""
816+
stream_id = "0"
817+
channel_info = (
818+
name,
819+
str(i),
820+
1 / sampling_period,
821+
f.byte_order + dtype,
822+
units,
823+
gain,
824+
offset,
825+
stream_id,
826+
buffer_id,
827+
)
815828

816829
self.logger.debug("channel_info: {channel_info}")
817830
self.logger.debug("")
@@ -1230,13 +1243,15 @@ def _scan_axograph_file(self):
12301243
event_channels.append(("AxoGraph Intervals", "", "epoch"))
12311244

12321245
if len(sig_channels) > 0:
1233-
signal_streams = [("Signals", "0")]
1246+
signal_streams = [("Signals", "0", "")]
12341247
else:
12351248
signal_streams = []
1249+
signal_buffers = []
12361250

12371251
# organize header
12381252
self.header["nb_block"] = 1
12391253
self.header["nb_segment"] = [1]
1254+
self.header["signal_buffers"] = np.array(signal_buffers, dtype=_signal_buffer_dtype)
12401255
self.header["signal_streams"] = np.array(signal_streams, dtype=_signal_stream_dtype)
12411256
self.header["signal_channels"] = np.array(sig_channels, dtype=_signal_channel_dtype)
12421257
self.header["event_channels"] = np.array(event_channels, dtype=_event_channel_dtype)

neo/rawio/axonarawio.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
BaseRawIO,
2626
_signal_channel_dtype,
2727
_signal_stream_dtype,
28+
_signal_buffer_dtype,
2829
_spike_channel_dtype,
2930
_event_channel_dtype,
3031
)
@@ -199,6 +200,7 @@ def _parse_header(self):
199200
params["set"]["sampling_rate"] = int(set_dict["rawRate"])
200201

201202
# SCAN BIN FILE
203+
signal_buffers = []
202204
signal_streams = []
203205
signal_channels = []
204206
if self.bin_file:
@@ -289,6 +291,7 @@ def _parse_header(self):
289291
self.header = {}
290292
self.header["nb_block"] = 1
291293
self.header["nb_segment"] = [1]
294+
self.header["signal_buffers"] = np.array(signal_buffers, dtype=_signal_buffer_dtype)
292295
self.header["signal_streams"] = np.array(signal_streams, dtype=_signal_stream_dtype)
293296
self.header["signal_channels"] = np.array(signal_channels, dtype=_signal_channel_dtype)
294297
self.header["spike_channels"] = np.array(spike_channels, dtype=_spike_channel_dtype)
@@ -315,7 +318,7 @@ def _parse_header(self):
315318

316319
def _get_signal_streams_header(self):
317320
# create signals stream information (we always expect a single stream)
318-
return np.array([("stream 0", "0")], dtype=_signal_stream_dtype)
321+
return np.array([("stream 0", "0", "")], dtype=_signal_stream_dtype)
319322

320323
def _segment_t_start(self, block_index, seg_index):
321324
return 0.0
@@ -638,10 +641,11 @@ def _get_signal_chan_header(self):
638641
chan_id = str(cntr)
639642
gain = gain_list[cntr]
640643
stream_id = "0"
644+
buffer_id = ""
641645
# the sampling rate information is stored in the set header
642646
# and not in the bin file
643647
sr = self.file_parameters["set"]["sampling_rate"]
644-
sig_channels.append((ch_name, chan_id, sr, dtype, units, gain, offset, stream_id))
648+
sig_channels.append((ch_name, chan_id, sr, dtype, units, gain, offset, stream_id, buffer_id))
645649

646650
return np.array(sig_channels, dtype=_signal_channel_dtype)
647651

neo/rawio/axonrawio.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
BaseRawIO,
5757
_signal_channel_dtype,
5858
_signal_stream_dtype,
59+
_signal_buffer_dtype,
5960
_spike_channel_dtype,
6061
_event_channel_dtype,
6162
)
@@ -227,12 +228,16 @@ def _parse_header(self):
227228
else:
228229
gain, offset = 1.0, 0.0
229230
stream_id = "0"
230-
signal_channels.append((name, str(chan_id), self._sampling_rate, sig_dtype, units, gain, offset, stream_id))
231+
buffer_id = "0"
232+
signal_channels.append(
233+
(name, str(chan_id), self._sampling_rate, sig_dtype, units, gain, offset, stream_id, buffer_id)
234+
)
231235

232236
signal_channels = np.array(signal_channels, dtype=_signal_channel_dtype)
233237

234-
# one unique signal stream
235-
signal_streams = np.array([("Signals", "0")], dtype=_signal_stream_dtype)
238+
# one unique signal stream and buffer
239+
signal_buffers = np.array([("Signals", "0")], dtype=_signal_buffer_dtype)
240+
signal_streams = np.array([("Signals", "0", "0")], dtype=_signal_stream_dtype)
236241

237242
# only one events channel : tag
238243
# In ABF timstamps are not attached too any particular segment
@@ -258,6 +263,7 @@ def _parse_header(self):
258263
self.header = {}
259264
self.header["nb_block"] = 1
260265
self.header["nb_segment"] = [nb_segment]
266+
self.header["signal_buffers"] = signal_buffers
261267
self.header["signal_streams"] = signal_streams
262268
self.header["signal_channels"] = signal_channels
263269
self.header["spike_channels"] = spike_channels

neo/rawio/baserawio.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,18 @@
8686

8787
error_header = "Header is not read yet, do parse_header() first"
8888

89+
_signal_buffer_dtype = [
90+
("name", "U64"), # not necessarily unique
91+
("id", "U64"), # must be unique
92+
]
93+
# To be left an empty array if the concept of buffer is undefined for a reader.
8994
_signal_stream_dtype = [
9095
("name", "U64"), # not necessarily unique
9196
("id", "U64"), # must be unique
97+
(
98+
"buffer_id",
99+
"U64",
100+
), # should be "" (empty string) when the stream is not nested under a buffer or the buffer is undefined for some reason.
92101
]
93102

94103
_signal_channel_dtype = [
@@ -100,6 +109,7 @@
100109
("gain", "float64"),
101110
("offset", "float64"),
102111
("stream_id", "U64"),
112+
("buffer_id", "U64"),
103113
]
104114

105115
# TODO for later: add t_start and length in _signal_channel_dtype

neo/rawio/bci2000rawio.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
BaseRawIO,
1616
_signal_channel_dtype,
1717
_signal_stream_dtype,
18+
_signal_buffer_dtype,
1819
_spike_channel_dtype,
1920
_event_channel_dtype,
2021
)
@@ -49,8 +50,10 @@ def _parse_header(self):
4950
self.header["nb_block"] = 1
5051
self.header["nb_segment"] = [1]
5152

52-
# one unique stream
53-
signal_streams = np.array([("Signals", "0")], dtype=_signal_stream_dtype)
53+
# one unique stream and buffer
54+
signal_buffers = np.array(("Signals", "0"), dtype=_signal_buffer_dtype)
55+
signal_streams = np.array([("Signals", "0", "0")], dtype=_signal_stream_dtype)
56+
self.header["signal_buffers"] = signal_buffers
5457
self.header["signal_streams"] = signal_streams
5558

5659
sig_channels = []
@@ -78,7 +81,8 @@ def _parse_header(self):
7881
offset = float(offset)
7982

8083
stream_id = "0"
81-
sig_channels.append((ch_name, chan_id, sr, dtype, units, gain, offset, stream_id))
84+
buffer_id = "0"
85+
sig_channels.append((ch_name, chan_id, sr, dtype, units, gain, offset, stream_id, buffer_id))
8286
self.header["signal_channels"] = np.array(sig_channels, dtype=_signal_channel_dtype)
8387

8488
self.header["spike_channels"] = np.array([], dtype=_spike_channel_dtype)

0 commit comments

Comments
 (0)