Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add link spike_event_series to UnitSeries #825

Draft
wants to merge 4 commits into
base: enh/add_UnitSeries
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions src/pynwb/data/nwb.ecephys.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ groups:
- num_times
shape:
- null
links:
- name: unit_series
doc: the UnitSeries that holds the unit ids for each waveform
quantity: '?'
target_type: UnitSeries
- neurodata_type_def: ClusterWaveforms
neurodata_type_inc: NWBDataInterface
doc: 'DEPRECATED The mean waveform shape, including standard deviation, of the
Expand Down
11 changes: 8 additions & 3 deletions src/pynwb/ecephys.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from .base import TimeSeries, _default_resolution, _default_conversion
from .core import NWBContainer, NWBDataInterface, MultiContainerInterface, DynamicTableRegion
from .device import Device
from .misc import DecompositionSeries
from .misc import DecompositionSeries, UnitSeries


@register_class('ElectrodeGroup', CORE_NAMESPACE)
Expand Down Expand Up @@ -108,7 +108,9 @@ class SpikeEventSeries(ElectricalSeries):
electrode).
"""

__nwbfields__ = ()
__nwbfields__ = ({'name': 'unit_series',
'doc': 'the UnitSeries that holds the unit ids for each waveform',
'child': False},)

__help = "Snapshots of spike events from data."

Expand All @@ -119,6 +121,8 @@ class SpikeEventSeries(ElectricalSeries):
'doc': 'Timestamps for samples stored in data'},
{'name': 'electrodes', 'type': DynamicTableRegion,
'doc': 'the table region corresponding to the electrodes from which this series was recorded'},
{'name': 'unit_series', 'type': UnitSeries, 'default': None,
'doc': 'UnitSeries that matches waveforms to spikes in Units table'},
{'name': 'resolution', 'type': float,
'doc': 'The smallest meaningful difference (in specified unit) between values in data',
'default': _default_resolution},
Expand All @@ -135,7 +139,7 @@ class SpikeEventSeries(ElectricalSeries):
{'name': 'parent', 'type': 'NWBContainer',
'doc': 'The parent NWBContainer for this NWBContainer', 'default': None})
def __init__(self, **kwargs):
name, data, electrodes = popargs('name', 'data', 'electrodes', kwargs)
name, data, electrodes, unit_series = popargs('name', 'data', 'electrodes', 'unit_series', kwargs)
timestamps = getargs('timestamps', kwargs)
if not (isinstance(data, TimeSeries) and isinstance(timestamps, TimeSeries)):
if not (isinstance(data, DataChunkIterator) and isinstance(timestamps, DataChunkIterator)):
Expand All @@ -145,6 +149,7 @@ def __init__(self, **kwargs):
# TODO: add check when we have DataChunkIterators
pass
super(SpikeEventSeries, self).__init__(name, data, electrodes, **kwargs)
self.unit_series = unit_series


@register_class('EventDetection', CORE_NAMESPACE)
Expand Down
21 changes: 15 additions & 6 deletions src/pynwb/form/build/map.py
Original file line number Diff line number Diff line change
Expand Up @@ -540,12 +540,15 @@ def get_container_name(self, *args):
def convert_dt_name(cls, **kwargs):
'''Get the attribute name corresponding to a specification'''
spec = getargs('spec', kwargs)
if spec.data_type_def is not None:
name = spec.data_type_def
elif spec.data_type_inc is not None:
name = spec.data_type_inc
if isinstance(spec, LinkSpec):
name = spec.target_type
else:
raise ValueError('found spec without name or data_type')
if spec.data_type_def is not None:
name = spec.data_type_def
elif spec.data_type_inc is not None:
name = spec.data_type_inc
else:
raise ValueError('found spec without name or data_type')
s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
name = re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
if name[-1] != 's' and spec.is_many():
Expand Down Expand Up @@ -1051,7 +1054,9 @@ def __get_subspec_values(self, builder, spec, manager):
# now assign links to their respective specification
for subspec in spec.links:
if subspec.name is not None:
ret[subspec] = manager.construct(links[subspec.name].builder)
sub_builder = links.get(subspec.name)
if sub_builder is not None:
ret[subspec] = manager.construct(sub_builder.builder)
else:
sub_builder = link_dt.get(subspec.target_type)
if sub_builder is not None:
Expand Down Expand Up @@ -1100,6 +1105,10 @@ def __get_sub_builders(self, sub_builders, subspecs, manager, ret):
ret[subspec] = manager.construct(sub_builder)

def __flatten(self, sub_builder, subspec, manager):
"""
Convert one-or-many to a single object or a list,
depending on the spec
"""
tmp = [manager.construct(b) for b in sub_builder]
if len(tmp) == 1 and not subspec.is_many():
tmp = tmp[0]
Expand Down
9 changes: 6 additions & 3 deletions src/pynwb/form/spec/spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -945,9 +945,12 @@ def is_inherited_spec(self, **kwargs):
if isinstance(spec, Spec):
name = spec.name
if name is None:
name = spec.data_type_def
if name is None:
name = spec.data_type_inc
if isinstance(spec, LinkSpec):
name = spec.target_type
else:
name = spec.data_type_def
if name is None:
name = spec.data_type_inc
if name is None:
raise ValueError('received Spec with wildcard name but no data_type_inc or data_type_def')
spec = name
Expand Down