The Neo io module aims to provide an exhaustive way of loading and saving several widely used data formats in electrophysiology. The more these heterogeneous formats are supported, the easier it will be to manipulate them as Neo objects in a similar way. Therefore the IO set of classes propose a simple and flexible IO API that fits many format specifications. It is not only file-oriented, it can also read/write objects from a database.
neo.io can be seen as a pure-Python and open-source Neuroshare replacement.
Combining 1 for reading and 3 for writing is a good example of use: converting your datasets to a more standard format when you want to share/collaborate.
There is an intrinsic structure in the different Neo objects, that could be seen as a hierachy with cross-links. See Neo core. The highest level object is the Block object, which is the high level container able to encapsulate all the others.
A Block is therefore a list of Segment objects, that can, in some file formats, be accessed individually. Depending on the file format, i.e. if it is streamable or not, the whole Block may need to be loaded, but sometimes particular Segment objects can be accessed individually. Within a Segment, the same hierarchical organisation applies. A Segment embeds several objects, such as SpikeTrain, AnalogSignal, AnaloSignalArray, EpochArray, EventArray (basically, all the different Neo objects).
Depending on the file format, these objects can sometimes be loaded separately, without the need to load the whole file. If possible, a file IO therefore provides distinct methods allowing to load only particular objects that may be present in the file. The basic idea of each IO file format is to have, as much as possible, read/write methods for the individual encapsulated objects, and otherwise to provide a read/write method that will return the object at the highest level of hierarchy (by default, a Block or a Segment).
The neo.io API is a balance between full flexibility for the user (all read_XXX() methods are enabled) and simple, clean and understandable code for the developer (few read_XXX() methods are enabled). This means that not all IOs offer the full flexibility for partial reading of data files.
The basic syntax is as follows. If you want to load a file format that is implemented in a generic MyFormatIO class:
>>> from neo.io import MyFormatIO
>>> reader = MyFormatIO(filename = "myfile.dat")
you can replace MyFormatIO by any implemented class, see List of implemented formats
IO can be based on file, directory, database or fake This is describe in mode attribute of the IO class.
>>> from neo.io import MyFormatIO
>>> print MyFormatIO.mode
'file'
For file mode the filename keyword argument is necessary. For directory mode the dirname keyword argument is necessary.
>>> reader = io.PlexonIO(filename='File_plexon_1.plx')
>>> reader = io.TdtIO(dirname='aep_05')
To know what types of object are supported by a given IO interface:
>>> MyFormatIO.supported_objects
[Segment , AnalogSignal , SpikeTrain, Event, Spike]
Supported objects does not mean objects that you can read directly. For instance, many formats support AnalogSignal but don’t allow them to be loaded directly, rather to access the AnalogSignal objects, you must read a Segment:
>>> seg = reader.read_segment()
>>> print(seg.analogsignals)
>>> print(seg.analogsignals[0])
To get a list of directly readable objects
>>> MyFormatIO.readable_objects
[Segment]
The first element of the previous list is the highest level for reading the file. This mean that the IO has a read_segment() method:
>>> seg = reader.read_segment()
>>> type(seg)
neo.core.Segment
All IOs have a read() method that returns a Block object:
>>> bl = reader.read()
>>> print bl.segments[0]
neo.core.Segment
In some cases you may not want to load everything in memory because it could be too big. For this scenario, two options are available:
- lazy=True/False. With lazy=True all arrays will have a size of zero, but all the metadata will be loaded. lazy_shape attribute is added to all object that inheritate Quantitities or numpy.ndarray (AnalogSignal, AnalogSignalArray, SpikeTrain) and to object that have array like attributes (EpochArray, EventArray) In that cases, lazy_shape is a tuple that have the same shape with lazy=False.
- cascade=True/False. With cascade=False only one object is read (and one_to_many and many_to_many relationship are not read).
By default (if they are not specified), lazy=False and cascade=True, i.e. all data is loaded.
>>> seg = reader.read_segment( cascade=True)
>>> print(len(seg.analogsignals)) # this is N
>>> seg = reader.read_segment(cascade=False)
>>> print(len(seg.analogsignals)) # this is zero
>>> seg = reader.read_segment(lazy=False)
>>> print(seg.analogsignals[0].shape) # this is N
>>> seg = reader.read_segment(lazy=True)
>>> print(seg.analogsignals[0].shape) # this is zero, the AnalogSignal is empty
>>> print(seg.analogsignals[0].lazy_shape) # this is N
neo.io provides classes for reading and/or writing electrophysiological data files.
Note that if the package dependency is not satisfied for one io, it does not raise an error but a warning.
neo.io.iolist provides the classes list of succesfully imported io.
Class for reading plx file.
>>> from neo import io
>>> r = io.PlexonIO(filename='File_plexon_1.plx')
>>> seg = r.read_segment(lazy=False, cascade=True)
>>> print seg.analogsignals
[]
>>> print seg.spiketrains
[<SpikeTrain(array([ 2.75000000e-02, 5.68250000e-02, 8.52500000e-02, ...,
...
>>> print seg.eventarrays
[]
Class for reading nex file.
>>> from neo import io
>>> r = io.NeuroExplorerIO(filename='File_neuroexplorer_1.nex')
>>> seg = r.read_segment(lazy=False, cascade=True)
>>> print seg.analogsignals
[<AnalogSignal(array([ 39.0625 , 0. , 0. , ..., -26.85546875, ...
>>> print seg.spiketrains
[<SpikeTrain(array([ 2.29499992e-02, 6.79249987e-02, 1.13399997e-01, ...
>>> print seg.eventarrays
[<EventArray: @21.1967754364 s, @21.2993755341 s, @21.350725174 s, @21.5048999786 s, ...
>>> print seg.epocharrays
[<neo.core.epocharray.EpochArray object at 0x10561ba90>, <neo.core.epocharray.EpochArray object at 0x10561bad0>]
Class for reading abf (axon binary file) file.
>>> from neo import io
>>> r = io.AxonIO(filename='File_axon_1.abf')
>>> bl = r.read_block(lazy=False, cascade=True)
>>> print bl.segments
[<neo.core.segment.Segment object at 0x105516fd0>]
>>> print bl.segments[0].analogsignals
[<AnalogSignal(array([ 2.18811035, 2.19726562, 2.21252441, ..., 1.33056641,
1.3458252 , 1.3671875 ], dtype=float32) * pA, [0.0 s, 191.2832 s], sampling rate: 10000.0 Hz)>]
>>> print bl.segments[0].eventarrays
[]
Class for reading data from from Tucker Davis TTank format.
>>> from neo import io
>>> r = io.TdtIO(dirname='aep_05')
>>> bl = r.read_block(lazy=False, cascade=True)
>>> print bl.segments
[<neo.core.segment.Segment object at 0x1060a4d10>]
>>> print bl.segments[0].analogsignals
[<AnalogSignal(array([ 2.18811035, 2.19726562, 2.21252441, ..., 1.33056641,
1.3458252 , 1.3671875 ], dtype=float32) * pA, [0.0 s, 191.2832 s], sampling rate: 10000.0 Hz)>]
>>> print bl.segments[0].eventarrays
[]
Class for reading data from WinEDR.
>>> from neo import io
>>> r = io.WinEdrIO(filename='File_WinEDR_1.EDR')
>>> seg = r.read_segment(lazy=False, cascade=True,)
>>> print seg.analogsignals
[<AnalogSignal(array([ 89.21203613, 88.83666992, 87.21008301, ..., 64.56298828,
67.94128418, 68.44177246], dtype=float32) * pA, [0.0 s, 101.5808 s], sampling rate: 10000.0 Hz)>]
Class for reading from a WinWCP file.
>>> from neo import io
>>> r = io.WinWcpIO( filename = 'File_winwcp_1.wcp')
>>> bl = r.read_block(lazy = False, cascade = True,)
>>> print bl.segments
[<neo.core.segment.Segment object at 0x1057bd350>, <neo.core.segment.Segment object at 0x1057bd2d0>,
...
>>> print bl.segments[0].analogsignals
[<AnalogSignal(array([-2438.73388672, -2428.96801758, -2425.61083984, ..., -2695.39453125,
...
Classe for reading/writing data from Elan.
>>> from neo import io
>>> r = io.ElanIO( filename = 'File_elan_1.eeg')
>>> seg = r.read_segment(lazy = False, cascade = True,)
>>> print seg.analogsignals
[<AnalogSignal(array([ 89.21203613, 88.83666992, 87.21008301, ..., 64.56298828,
67.94128418, 68.44177246], dtype=float32) * pA, [0.0 s, 101.5808 s], sampling rate: 10000.0 Hz)>]
>>> print seg.spiketrains
[]
>>> print seg.eventarrays
[]
Class for reading signal in generic ascii format. Columns respresents signal. They share all the same sampling rate. The sampling rate is externally known or the first columns could hold the time vector.
>>> from neo import io
>>> r = io.AsciiSignalIO(filename='File_asciisignal_2.txt')
>>> seg = r.read_segment(lazy=False, cascade=True)
>>> print seg.analogsignals
[<AnalogSignal(array([ 39.0625 , 0. , 0. , ..., -26.85546875 ...
Classe for reading/writing SpikeTrain in a text file. Each Spiketrain is a line.
>>> from neo import io
>>> r = io.AsciiSpikeTrainIO( filename = 'File_ascii_spiketrain_1.txt')
>>> seg = r.read_segment(lazy = False, cascade = True,)
>>> print seg.spiketrains
[<SpikeTrain(array([ 3.89981604, 4.73258781, 0.608428 , 4.60246277, 1.23805797,
...
Class for reading/writing data in a raw binary interleaved compact file.
>>> from neo import io
>>> r = io.RawBinarySignalIO( filename = 'File_ascii_signal_2.txt')
>>> seg = r.read_segment(lazy = False, cascade = True,)
>>> print seg.analogsignals
...
Class for reading data from micromed (.trc).
>>> from neo import io
>>> r = io.MicromedIO(filename='File_micromed_1.TRC')
>>> seg = r.read_segment(lazy=False, cascade=True)
>>> print seg.analogsignals
[<AnalogSignal(array([ -1.77246094e+02, -2.24707031e+02, -2.66015625e+02,
...
Class for reading file trougth neuroshare API. The user need the DLLs in the path of the file format.
>>> from neo import io
>>> r = io.NeuroshareIO(filename='a_file', dllname=the_name_of_dll)
>>> seg = r.read_segment(lazy=False, cascade=True, import_neuroshare_segment=True)
>>> print seg.analogsignals
[<AnalogSignal(array([ -1.77246094e+02, -2.24707031e+02, -2.66015625e+02,
...
>>> print seg.spiketrains
[]
>>> print seg.eventarrays
[<EventArray: 1@1.12890625 s, 1@2.02734375 s, 1@3.82421875 s>]
neuroshare.ns_ENTITY_EVENT: are converted to neo.EventArray neuroshare.ns_ENTITY_ANALOG: are converted to neo.AnalogSignal neuroshare.ns_ENTITY_NEURALEVENT: are converted to neo.SpikeTrain
Reads/writes data from/to PyNN NumpyBinaryFile format
Reads/writes data from/to PyNN StandardTextFile format
Class for reading/writing data in a BlackRock Neuroshare ns5 files.
Class for reading data from Alpha Omega .map files (experimental)
This class is an experimental reader with important limitations. See the source code for details of the limitations. The code of this reader is of alpha quality and received very limited testing.
>>> from neo import io
>>> r = io.AlphaOmegaIO( filename = 'File_AlphaOmega_1.map')
>>> blck = r.read_block(lazy = False, cascade = True)
>>> print blck.segments[0].analogsignals
Class for reading/writing data from BrainVision product (brainAmp, brain analyser...)
>>> from neo import io
>>> r = io.BrainVisionIO( filename = 'File_brainvision_1.eeg')
>>> seg = r.read_segment(lazy = False, cascade = True,)
Class for reading from and writing to an Elphy file.
It enables reading: - Block - Segment - RecordingChannel - RecordingChannelGroup - EventArray - SpikeTrain
>>> from neo import io
>>> r = io.ElphyIO(filename='ElphyExample.DAT')
>>> seg = r.read_block(lazy=False, cascade=True)
>>> print(seg.analogsignals)
>>> print(seg.spiketrains)
>>> print(seg.eventarrays)
>>> print(anasig._data_description)
>>> anasig = r.read_analogsignal(lazy=False, cascade=False)
>>> bl = Block()
>>> ... creating segments, their contents and append to bl
>>> r.write_block( bl )
See IO developers’ guide for information on how to implement of a new IO.