Skip to content

Commit c2d1d43

Browse files
committed
Add example code for loading Binary and Open Ephys data formats
1 parent 5d5d5b9 commit c2d1d43

File tree

3 files changed

+131
-10
lines changed

3 files changed

+131
-10
lines changed

source/User-Manual/Data-formats/Binary-format.rst

Lines changed: 66 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ Binary Format
2929

3030
**Limitations**
3131

32-
* Requires slightly more disk space because it stores two 64-bit timestamps for every sample.
32+
* Requires slightly more disk space because it stores one 64-bit sample number and one 64-bit timestamp for every sample.
3333

3434
* Continuous files are not self-contained, i.e., you need to know the number of channels and the "bit-volts" multiplier in order to read them properly.
3535

@@ -38,7 +38,9 @@ Binary Format
3838
File organization
3939
####################
4040

41-
Within a Record Node directory, data for each **experiments** (stop/start acquisition) is contained in its own sub-directory. Experiment directories are further sub-divided for individual **recordings** (stop/start recording).
41+
Within a Record Node directory, data for each **experiment** is contained in its own sub-directory. The experiment number is incremented whenever acquisition is stopped, which will reset the timestamps/sample numbers to zero. A new :code:`settings.xml` file will be created for every experiment.
42+
43+
Experiment directories are further sub-divided for individual **recordings**. The recording number is incremented whenever recording is stopped, which will not reset the timestamps/sample numbers. Data from multiple recordings within the same experiment will have internally consistent timestamps/sample numbers, and will use the same :code:`settings.xml` file.
4244

4345
.. image:: ../../_static/images/recordingdata/binary/organization.png
4446
:alt: Binary data directory structure
@@ -122,14 +124,72 @@ More detailed information about each electrode is stored in the :code:`structure
122124
Reading data in Python
123125
#######################
124126

125-
* **(recommended)** Create a :code:`Session` object using the `open-ephys-python-tools <https://github.com/open-ephys/open-ephys-python-tools>`__ package. The data format will be automatically detected.
127+
Using :code:`open-ephys-python-tools`
128+
--------------------------------------
129+
130+
The recommended method for loading data in Python is via the `open-ephys-python-tools <https://github.com/open-ephys/open-ephys-python-tools>`__ package, which can be installed via :code:`pip`.
131+
132+
First, create a :code:`Session` object that points to the top-level data directory:
133+
134+
.. code-block:: python
135+
136+
from open_ephys.analysis import Session
137+
138+
session = Session(r'C:\Users\example_user\Open Ephys\2025-08-03_10-21-22')
139+
140+
The :code:`Session` object provides access to data inside each Record Node. If you only had one Record Node in your signal chain, you can find its recordings as follows:
141+
142+
.. code-block:: python
143+
144+
recordings = session.recordnodes[0]
145+
146+
:code:`recordings` is a list of :code:`Recording` objects, which is a flattened version of the original Record Node directory. For example, if you have three "experiments," each with two "recordings," there will be six total :code:`Recording` objects in this list. The one at index 0 will be recording 1 from experiment 1, index 1 will be recording 2 from experiment 1, etc.
147+
148+
Each :code:`Recording` object provides access to the continuous data, events, spikes, and metadata for the associated recording. To read the continuous data samples for the first data stream, you can use the following code:
149+
150+
.. code-block:: python
151+
152+
samples = recordings[0].continuous[0].get_samples(start_sample_index=0, end_sample_index=10000)
153+
print(f'Stream name: {recordings[0].continuous[0].metadata("stream_name")}')
154+
155+
This will automatically scale the data into microvolts before returning it.
156+
157+
To read the events for the same recording:
158+
159+
.. code-block:: python
160+
161+
events = recordings[0].events
162+
163+
This will load the events for all data streams into a Pandas :code:`DataFrame` with the following columns:
164+
165+
* :code:`line` - the TTL line on which this event occurred
166+
* :code:`sample_number` - the sample index at which this event occurred
167+
* :code:`timestamp` - the global timestamp (in seconds) at which this event occurred (defaults to -1 if all streams were not synchronized)
168+
* :code:`processor_id` - the ID of the processor from which this event originated
169+
* :code:`stream_index` - the index of the stream from which this event originated
170+
* :code:`stream_name` - the name of the stream from which this event originated
171+
* :code:`state` - 1 or 0, to indicate whether this event is associated with a rising edge (1) or falling edge (0)
172+
173+
The fastest way to find the nearest continuous sample to a particular event is by using the :code:`np.searchsorted` function:
174+
175+
.. code-block:: python
176+
177+
import numpy as np
178+
event_index = 100 # the index of the event you're interested in
179+
event_timestamp = events.iloc[event_index].timestamp
180+
nearest_continuous_sample_index = \
181+
np.searchsorted(recordings[0].continuous[0].timestamps,
182+
event_timestamp)
183+
126184
127-
* Create a :code:`File` object using the `pyopenephys <https://github.com/CINPLA/pyopenephys>`__ package.
185+
For more information on how to use the :code:`open-ephys-python-tools` library, check out this `README <https://github.com/open-ephys/open-ephys-python-tools/tree/main/src/open_ephys/analysis>`__
128186

129-
* Use the :code:`DatLoad()` method from :code:`Binary.py` in the `open-ephys/analysis-tools <https://github.com/open-ephys/analysis-tools/blob/master/Python3/Binary.py>`__ repository.
187+
Using :code:`SpikeInterface`
188+
--------------------------------------
130189

190+
You can also load data from the Open Ephys Binary format via `SpikeInterface <https://spikeinterface.readthedocs.io/en/stable/>`__, using the :code:`read_openephys()` method.
131191

132192
Reading data in Matlab
133193
#######################
134194

135-
* Use the `open-ephys-matlab-tools <https://github.com/open-ephys/open-ephys-matlab-tools>`__ library.
195+
Use the `open-ephys-matlab-tools <https://github.com/open-ephys/open-ephys-matlab-tools>`__ library, available via the `Matlab File Exchange <https://www.mathworks.com/matlabcentral/fileexchange/122372-open-ephys-matlab-tools>`__.

source/User-Manual/Data-formats/NWB-format.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ Reading data in Python
106106

107107
* Create a :code:`Session` object using the `open-ephys-python-tools <https://github.com/open-ephys/open-ephys-python-tools>`__ package. The data format will be automatically detected.
108108

109+
* Alternatively, you can use the `PyNWB <https://pynwb.readthedocs.io/en/stable/>`__ package.
110+
109111

110112
Reading data in Matlab
111113
#######################

source/User-Manual/Data-formats/Open-Ephys-format.rst

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,14 +118,73 @@ Since the samples are saved as 16-bit unsigned integers, converting them to micr
118118
Reading data in Python
119119
#######################
120120

121-
* **(recommended)** Create a :code:`Session` object using the `open-ephys-python-tools <https://github.com/open-ephys/open-ephys-python-tools>`__ package. The data format will be automatically detected.
122121

123-
* Create a :code:`File` object using the `pyopenephys <https://github.com/CINPLA/pyopenephys>`__ package.
122+
Using :code:`open-ephys-python-tools`
123+
--------------------------------------
124124

125-
* Use the :code:`loadContinuous`, :code:`loadEvents`, or :code:`loadSpikes` methods from :code:`OpenEphys.py` in the `open-ephys/analysis-tools <https://github.com/open-ephys/analysis-tools/blob/master/Python3/OpenEphys.py>`__ repository.
125+
The recommended method for loading data in Python is via the `open-ephys-python-tools <https://github.com/open-ephys/open-ephys-python-tools>`__ package, which can be installed via :code:`pip`.
126126

127+
First, create a :code:`Session` object that points to the top-level data directory:
128+
129+
.. code-block:: python
130+
131+
from open_ephys.analysis import Session
132+
133+
session = Session(r'C:\Users\example_user\Open Ephys\2025-08-03_10-21-22')
134+
135+
The :code:`Session` object provides access to data inside each Record Node. If you only had one Record Node in your signal chain, you can find its recordings as follows:
136+
137+
.. code-block:: python
138+
139+
recordings = session.recordnodes[0]
140+
141+
:code:`recordings` is a list of :code:`Recording` objects, which is a flattened version of the original Record Node directory. For example, if you have three "experiments," each with two "recordings," there will be six total :code:`Recording` objects in this list. The one at index 0 will be recording 1 from experiment 1, index 1 will be recording 2 from experiment 1, etc.
142+
143+
Each :code:`Recording` object provides access to the continuous data, events, spikes, and metadata for the associated recording. To read the continuous data samples for the first data stream, you need to first set the sample range (to prevent all samples from being loaded into memory), and then call :code:`get_samples()`:
144+
145+
.. code-block:: python
146+
147+
recordings[0].set_sample_range([10000, 50000])
148+
samples = recordings[0].continuous[0].get_samples(start_sample_index=0, end_sample_index=10000)
149+
print(f'Stream name: {recordings[0].continuous[0].metadata("stream_name")}')
150+
151+
This will automatically scale the data into microvolts before returning it.
152+
153+
To read the events for the same recording:
154+
155+
.. code-block:: python
156+
157+
events = recordings[0].events
158+
159+
This will load the events for all data streams into a Pandas :code:`DataFrame` with the following columns:
160+
161+
* :code:`line` - the TTL line on which this event occurred
162+
* :code:`sample_number` - the sample index at which this event occurred
163+
* :code:`processor_id` - the ID of the processor from which this event originated
164+
* :code:`stream_index` - the index of the stream from which this event originated
165+
* :code:`stream_name` - the name of the stream from which this event originated
166+
* :code:`state` - 1 or 0, to indicate whether this event is associated with a rising edge (1) or falling edge (0)
167+
168+
The fastest way to find the nearest continuous sample to a particular event is by using the :code:`np.searchsorted` function:
169+
170+
.. code-block:: python
171+
172+
import numpy as np
173+
event_index = 100 # the index of the event you're interested in
174+
event_timestamp = events.iloc[event_index].timestamp
175+
nearest_continuous_sample_index = \
176+
np.searchsorted(recordings[0].continuous[0].sample_numbers,
177+
event_sample_number)
178+
179+
180+
For more information on how to use the :code:`open-ephys-python-tools` library, check out this `README <https://github.com/open-ephys/open-ephys-python-tools/tree/main/src/open_ephys/analysis>`__
181+
182+
Using :code:`SpikeInterface`
183+
--------------------------------------
184+
185+
You can also load data from the Open Ephys Binary format via `SpikeInterface <https://spikeinterface.readthedocs.io/en/stable/>`__, using the :code:`read_openephys()` method.
127186

128187
Reading data in Matlab
129188
#######################
130189

131-
* Use the `open-ephys-matlab-tools <https://github.com/open-ephys/open-ephys-matlab-tools>`__ library.
190+
Use the `open-ephys-matlab-tools <https://github.com/open-ephys/open-ephys-matlab-tools>`__ library, available via the `Matlab File Exchange <https://www.mathworks.com/matlabcentral/fileexchange/122372-open-ephys-matlab-tools>`__.

0 commit comments

Comments
 (0)