Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
97 commits
Select commit Hold shift + click to select a range
9db5911
Support empty array annotations
Apr 15, 2020
141fc3d
Add test with empty array annotation
Apr 15, 2020
fd1c8c1
Initial implementation of a "View" class (see #456)
apdavison May 18, 2020
dd39d20
Add Group class, start updating docs accordingly
apdavison May 19, 2020
f85c214
Merge branch 'master' into view-group
apdavison Jul 6, 2020
a3cef45
pep8 fixes
apdavison Jul 6, 2020
742a1a1
Make changes agreed during review
apdavison Jul 6, 2020
ebc4646
Some change in basefromrawio
samuelgarcia Jul 6, 2020
1085015
Rename `View` to `ChannelView`
apdavison Jul 7, 2020
f12dd4f
First draft for integrating Group into BaseFromRawIO:
samuelgarcia Sep 3, 2020
581caf7
Use NLX_Base_Class_Type to determine recording type.
Sep 8, 2020
2bbc68f
Initial test of Ncs recording type from header.
Sep 8, 2020
bfa1af5
support for Group object in NixIO
apdavison Oct 2, 2020
90db72e
Add support for ChannelView to NixIO
apdavison Oct 5, 2020
6026671
Limit index attribute of ChannelIndexs in dataset generation
JuliaSprenger Oct 6, 2020
7feb86d
Fix test dataset generation of ChannelIndex attributes and correspond…
JuliaSprenger Oct 7, 2020
0dae32b
Relax index type restrictions for View for compatibility with Channel…
JuliaSprenger Oct 7, 2020
de0b859
Add version converter
JuliaSprenger Oct 7, 2020
c421a30
Decode headers from recent file types and test them.
Oct 8, 2020
5e224b6
Add self to authors file.
Oct 8, 2020
1a5a3fc
Add 4.0.2 test data.
Oct 8, 2020
7008f9c
Do not fully test the 4.0.2 data yet.
Oct 9, 2020
b6f8153
Don’t test 4.0.2 in test of neuralynxio either.
Oct 9, 2020
b0deaf2
Add blank line for PEP8.
Oct 9, 2020
51daa93
Clean up more PEP8 style issues.
Oct 9, 2020
ea95d70
Clean up another whitespace issue for PEP8.
Oct 9, 2020
0a2b959
Move constants into class so accessible for testing.
Oct 9, 2020
799c060
Test of building NcsBlocks.
Oct 12, 2020
409ea41
Handle old files with truncated frequency in header and test.
Oct 13, 2020
2c3f80b
Change interface on parse versus build.
Oct 16, 2020
7ff456a
Merge pull request #3 from JuliaSprenger/view-group_converter
apdavison Oct 19, 2020
4f27b20
Fix container lookup for proxy objects in Group
apdavison Oct 19, 2020
6000687
Tests for PRE4 type and code corrections.
Oct 19, 2020
865fd29
Fixing unit tests
apdavison Oct 20, 2020
8e73267
Permit ChannelView to link to ProxyObjects
JuliaSprenger Oct 21, 2020
4dba99a
Fix NixIO writing multiple Groups with single ChannelView
JuliaSprenger Oct 22, 2020
27b5b82
Remove ChannelIndex from brainwaredamioio/brainwaref32io/brainscrio.
samuelgarcia Oct 23, 2020
c5858e8
Make error message more verbose.
JuliaSprenger Oct 26, 2020
9df9e3a
Remove print statement
JuliaSprenger Oct 26, 2020
c4e05ae
Fix initializer, update loop vars.
Oct 26, 2020
85a05e8
Add additional tests on v5.5.1 with 2 blocks
Oct 26, 2020
846edb0
Tests of block construction for incomplete blocks
Oct 26, 2020
5ba6113
Fix up single block case.
Oct 26, 2020
153446d
Remove unneeded classes. Clean up style.
Oct 27, 2020
968261f
Use private dtype by new private name.
Oct 27, 2020
b6ecbcd
Add test of side effects of read_ncs_files
Oct 27, 2020
6982c59
Use NcsBlocksFactory and logical or.
Oct 27, 2020
7930bb4
Deprecate old Blackrock and Neuralynx IOs
JuliaSprenger Oct 28, 2020
d9ade17
Fix off by one in range for list. Comments.
Oct 28, 2020
4af130c
Use standard time calculation for last time of block.
Oct 28, 2020
88880e0
Remove test with tolerance over whole length. Fix microsPerSampUsed a…
Oct 29, 2020
6b8b64a
Tests of raw io for incomplete records multiple block case.
Oct 29, 2020
81f14b2
Update stop times to include time for samples in partially filled rec…
Oct 29, 2020
4ed5679
PEP and style cleanup. Corrected gap comment.
Oct 29, 2020
b935d9f
Merge branch 'NlxFixes' into TypesFromHeader
Oct 29, 2020
82c93d9
Line shortening for PEP8.
Oct 29, 2020
ba82efe
More PEP8 items.
Oct 29, 2020
5052eb0
Merge pull request #887 from JuliaSprenger/enh/depr_ios
samuelgarcia Nov 2, 2020
c995a41
fixed a bug in loading hd5py data
dizcza Nov 2, 2020
e618198
Merge pull request #892 from INM-6/fix/hdf5io
JuliaSprenger Nov 2, 2020
4a75a84
Fix API change of h5py version 3.0
JuliaSprenger Nov 3, 2020
b717865
Add version check for h5py
JuliaSprenger Nov 3, 2020
44ad955
Merge pull request #893 from JuliaSprenger/fix/h5py_deprecation
samuelgarcia Nov 4, 2020
8f87b46
test fix: objects in a Group do not keep a reference to the group
apdavison Nov 5, 2020
f2fd5da
Support for nested Groups in NixIO
apdavison Nov 5, 2020
2efc3d8
fix deprecation warnings
apdavison Nov 5, 2020
2ac9596
Fixing or commenting out tests that involve ChannelIndex and Unit
apdavison Nov 5, 2020
55b80e8
Merge branch 'master' into view-group
apdavison Nov 5, 2020
1ad87a8
remove part of test_converter.py which is failing, and seems incorrect
apdavison Nov 6, 2020
268036e
Merge pull request #817 from apdavison/view-group
JuliaSprenger Nov 6, 2020
832f134
Merge pull request #806 from INM-6/fix/nix_empty_arrayannotations
JuliaSprenger Nov 6, 2020
6ed65a2
Language and function renaming.
Nov 6, 2020
8a5ffd9
Merge remote-tracking branch 'neuralensemble/master' into TypesFromHe…
Nov 6, 2020
e97ac97
Merge pull request #879 from PeterNSteinmetz/TypesFromHeader
JuliaSprenger Nov 7, 2020
3907d87
Move constants into class so accessible for testing.
Oct 9, 2020
589565e
Test of building NcsBlocks.
Oct 12, 2020
6ebcd75
Handle old files with truncated frequency in header and test.
Oct 13, 2020
1c5cd2c
Change interface on parse versus build.
Nov 7, 2020
e307614
Tests for PRE4 type and code corrections.
Nov 7, 2020
c5fac53
Fix initializer, update loop vars.
Oct 26, 2020
ddf26c6
Add additional tests on v5.5.1 with 2 blocks
Oct 26, 2020
b75989d
Tests of block construction for incomplete blocks
Oct 26, 2020
dd09521
Fix up single block case.
Oct 26, 2020
e17a869
Remove unneeded classes. Clean up style.
Nov 7, 2020
e90737a
Add test of side effects of read_ncs_files
Oct 27, 2020
1825772
Use NcsBlocksFactory and logical or.
Nov 7, 2020
97a694a
Fix off by one in range for list. Comments.
Oct 28, 2020
5a6dc62
Use standard time calculation for last time of block.
Oct 28, 2020
0837723
Remove test with tolerance over whole length. Fix microsPerSampUsed a…
Oct 29, 2020
32a26c7
Tests of raw io for incomplete records multiple block case.
Oct 29, 2020
917eb56
Update stop times to include time for samples in partially filled rec…
Oct 29, 2020
f28c4ca
PEP and style cleanup. Corrected gap comment.
Oct 29, 2020
50958f5
Line shortening for PEP8.
Oct 29, 2020
b2bbb39
More PEP8 items.
Nov 7, 2020
2ab65e7
Merge branch 'addNcsBlocks' of github.com:PeterNSteinmetz/python-neo …
Nov 7, 2020
76d3bb3
Remove conflict markers.
Nov 7, 2020
c8fa8f2
More conflict resolution for rebase.
Nov 7, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions doc/source/authors.rst
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ and may not be the current affiliation of a contributor.
* rishidhingra@github
* Hugo van Kemenade
* Aitor Morales-Gregorio [13]
* Peter N Steinmetz [22]

1. Centre de Recherche en Neuroscience de Lyon, CNRS UMR5292 - INSERM U1028 - Universite Claude Bernard Lyon 1
2. Unité de Neuroscience, Information et Complexité, CNRS UPR 3293, Gif-sur-Yvette, France
Expand All @@ -74,6 +75,7 @@ and may not be the current affiliation of a contributor.
19. IAL Developmental Neurobiology, Kazan Federal University, Kazan, Russia
20. Harden Technologies, LLC
21. Institut des Neurosciences Paris-Saclay, CNRS UMR 9197 - Université Paris-Sud, Gif-sur-Yvette, France
22. Neurtex Brain Research Institute, Dallas, TX, USAs

If we've somehow missed you off the list we're very sorry - please let us know.

Expand Down
59 changes: 29 additions & 30 deletions doc/source/core.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ There is a simple hierarchy of containers:
May contain any of the data objects.
* :py:class:`Block`: The top-level container gathering all of the data, discrete and continuous,
for a given recording session.
Contains :class:`Segment`, :class:`Unit` and :class:`ChannelIndex` objects.
Contains :class:`Segment` and :class:`Group` objects.


Grouping/linking objects
Expand All @@ -49,18 +49,16 @@ were recorded on which electrodes, which spike trains were obtained from which
membrane potential signals, etc. They contain references to data objects that
cut across the simple container hierarchy.

* :py:class:`ChannelIndex`: A set of indices into :py:class:`AnalogSignal` objects,
representing logical and/or physical recording channels. This has two uses:
* :py:class:`ChannelView`: A set of indices into :py:class:`AnalogSignal` objects,
representing logical and/or physical recording channels.
For spike sorting of extracellular signals, where spikes may be recorded on more than one
recording channel, the :py:class:`ChannelView` can be used to reference the group of recording channels
from which the spikes were obtained.

1. for linking :py:class:`AnalogSignal` objects recorded from the same (multi)electrode
across several :py:class:`Segment`\s.
2. for spike sorting of extracellular signals, where spikes may be recorded on more than one
recording channel, and the :py:class:`ChannelIndex` can be used to associate each
:py:class:`Unit` with the group of recording channels from which it was obtained.

* :py:class:`Unit`: links the :class:`SpikeTrain` objects within a :class:`Block`,
possibly across multiple Segments, that were emitted by the same cell.
A :class:`Unit` is linked to the :class:`ChannelIndex` object from which the spikes were detected.
* :py:class:`Group`: Can contain any of the data objects, views, or other groups,
outside the hierarchy of the segment and block containers.
A common use is to link the :class:`SpikeTrain` objects within a :class:`Block`,
possibly across multiple Segments, that were emitted by the same neuron.

* :py:class:`CircularRegionOfInterest`, :py:class:`RectangularRegionOfInterest` and :py:class:`PolygonRegionOfInterest`
are three subclasses that link :class:`ImageSequence` objects to signals (:class:`AnalogSignal` objects)
Expand Down Expand Up @@ -105,14 +103,14 @@ In general, an object can access its children with an attribute *childname+s* in
* :attr:`Block.segments`
* :attr:`Segments.analogsignals`
* :attr:`Segments.spiketrains`
* :attr:`Block.channel_indexes`
* :attr:`Block.groups`

These relationships are bi-directional, i.e. a child object can access its parent:

* :attr:`Segment.block`
* :attr:`AnalogSignal.segment`
* :attr:`SpikeTrain.segment`
* :attr:`ChannelIndex.block`
* :attr:`Group.block`

Here is an example showing these relationships in use::

Expand All @@ -134,38 +132,39 @@ Here is an example showing these relationships in use::

In some cases, a one-to-many relationship is sufficient. Here is a simple example with tetrodes, in which each tetrode has its own group.::

from neo import Block, ChannelIndex
from neo import Block, Group
bl = Block()

# the four tetrodes
for i in range(4):
chx = ChannelIndex(name='Tetrode %d' % i,
index=[0, 1, 2, 3])
bl.channelindexes.append(chx)
group = Group(name='Tetrode %d' % i)
bl.groups.append(group)

# now we load the data and associate it with the created channels
# ...

Now consider a more complex example: a 1x4 silicon probe, with a neuron on channels 0,1,2 and another neuron on channels 1,2,3. We create a group for each neuron to hold the :class:`Unit` object associated with this spike sorting group. Each group also contains the channels on which that neuron spiked. The relationship is many-to-many because channels 1 and 2 occur in multiple groups.::
Now consider a more complex example: a 1x4 silicon probe, with a neuron on channels 0,1,2 and another neuron on channels 1,2,3.
We create a group for each neuron to hold the spiketrains for each spike sorting group together with
the channels on which that neuron spiked::

bl = Block(name='probe data')

# one group for each neuron
chx0 = ChannelIndex(name='Group 0',
index=[0, 1, 2])
bl.channelindexes.append(chx0)
view0 = ChannelView(recorded_signals, index=[0, 1, 2])
unit0 = Group(view0, name='Group 0')
bl.groups.append(unit0)

chx1 = ChannelIndex(name='Group 1',
index=[1, 2, 3])
bl.channelindexes.append(chx1)
view1 = ChannelView(recorded_signals, index=[1, 2, 3])
unit1 = Group(view1, name='Group 1')
bl.groups.append(unit1)

# now we add the spiketrain from Unit 0 to chx0
# and add the spiketrain from Unit 1 to chx1
# now we add the spiketrains from Unit 0 to unit0
# and add the spiketrains from Unit 1 to unit1
# ...

Note that because neurons are sorted from groups of channels in this situation, it is natural that the :py:class:`ChannelIndex` contains a reference to the :py:class:`Unit` object.
That unit then contains references to its spiketrains. Also note that recording channels can be
identified by names/labels as well as, or instead of, integer indices.

Now each putative neuron is represented by a :class:`Group` containing the spiktrains of that neuron
and a view of the signal selecting only those channels from which the spikes were obtained.


See :doc:`usecases` for more examples of how the different objects may be used.
Expand Down
145 changes: 145 additions & 0 deletions doc/source/grouping.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
*************************
Grouping and linking data
*************************


... to do




Migrating from ChannelIndex/Unit to ChannelView/Group
==============================================


Examples
--------

A simple example with two tetrodes. Here the :class:`ChannelIndex` was not being
used for grouping, simply to associate a name with each channel.

Using :class:`ChannelIndex`::

import numpy as np
from quantities import kHz, mV
from neo import Block, Segment, ChannelIndex, AnalogSignal

block = Block()
segment = Segment()
segment.block = block
block.segments.append(segment)

for i in (0, 1):
signal = AnalogSignal(np.random.rand(1000, 4) * mV,
sampling_rate=1 * kHz,)
segment.analogsignals.append(signal)
chx = ChannelIndex(name=f"Tetrode #{i + 1}",
index=[0, 1, 2, 3],
channel_names=["A", "B", "C", "D"])
chx.analogsignals.append(signal)
block.channel_indexes.append(chx)

Using array annotations, we annotate the channels of the :class:`AnalogSignal` directly::

import numpy as np
from quantities import kHz, mV
from neo import Block, Segment, AnalogSignal

block = Block()
segment = Segment()
segment.block = block
block.segments.append(segment)

for i in (0, 1):
signal = AnalogSignal(np.random.rand(1000, 4) * mV,
sampling_rate=1 * kHz,
channel_names=["A", "B", "C", "D"])
segment.analogsignals.append(signal)


Now a more complex example: a 1x4 silicon probe, with a neuron on channels 0,1,2 and another neuron on channels 1,2,3.
We create a :class:`ChannelIndex` for each neuron to hold the :class:`Unit` object associated with this spike sorting group.
Each :class:`ChannelIndex` also contains the list of channels on which that neuron spiked.

::

import numpy as np
from quantities import ms, mV, kHz
from neo import Block, Segment, ChannelIndex, Unit, SpikeTrain, AnalogSignal

block = Block(name="probe data")
segment = Segment()
segment.block = block
block.segments.append(segment)

# create 4-channel AnalogSignal with dummy data
signal = AnalogSignal(np.random.rand(1000, 4) * mV,
sampling_rate=10 * kHz)
# create spike trains with dummy data
# we will pretend the spikes have been extracted from the dummy signal
spiketrains = [
SpikeTrain(np.arange(5, 100) * ms, t_stop=100 * ms),
SpikeTrain(np.arange(7, 100) * ms, t_stop=100 * ms)
]
segment.analogsignals.append(signal)
segment.spiketrains.extend(spiketrains)
# assign each spiketrain to a neuron (Unit)
units = []
for i, spiketrain in enumerate(spiketrains):
unit = Unit(name=f"Neuron #{i + 1}")
unit.spiketrains.append(spiketrain)
units.append(unit)

# create a ChannelIndex for each unit, to show which channels the spikes come from
chx0 = ChannelIndex(name="Channel Group 1", index=[0, 1, 2])
chx0.units.append(units[0])
chx0.analogsignals.append(signal)
units[0].channel_index = chx0
chx1 = ChannelIndex(name="Channel Group 2", index=[1, 2, 3])
chx1.units.append(units[1])
chx1.analogsignals.append(signal)
units[1].channel_index = chx1

block.channel_indexes.extend((chx0, chx1))


Using :class:`ChannelView` and :class`Group`::

import numpy as np
from quantities import ms, mV, kHz
from neo import Block, Segment, ChannelView, Group, SpikeTrain, AnalogSignal

block = Block(name="probe data")
segment = Segment()
segment.block = block
block.segments.append(segment)

# create 4-channel AnalogSignal with dummy data
signal = AnalogSignal(np.random.rand(1000, 4) * mV,
sampling_rate=10 * kHz)
# create spike trains with dummy data
# we will pretend the spikes have been extracted from the dummy signal
spiketrains = [
SpikeTrain(np.arange(5, 100) * ms, t_stop=100 * ms),
SpikeTrain(np.arange(7, 100) * ms, t_stop=100 * ms)
]
segment.analogsignals.append(signal)
segment.spiketrains.extend(spiketrains)
# assign each spiketrain to a neuron (now using Group)
units = []
for i, spiketrain in enumerate(spiketrains):
unit = Group(spiketrain, name=f"Neuron #{i + 1}")
units.append(unit)

# create a ChannelView of the signal for each unit, to show which channels the spikes come from
# and add it to the relevant Group
view0 = ChannelView(signal, index=[0, 1, 2], name="Channel Group 1")
units[0].add(view0)
view1 = ChannelView(signal, index=[1, 2, 3], name="Channel Group 2")
units[1].add(view1)

block.groups.extend(units)


Now each putative neuron is represented by a :class:`Group` containing the spiktrains of that neuron
and a view of the signal selecting only those channels from which the spikes were obtained.
Binary file modified doc/source/images/base_schematic.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading