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

Enh/add links to elec grp #828

Draft
wants to merge 3 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 2 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
14 changes: 14 additions & 0 deletions src/pynwb/data/nwb.ecephys.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,20 @@ groups:
- name: location
dtype: text
doc: description of location of this electrode group
datasets:
bendichter marked this conversation as resolved.
Show resolved Hide resolved
- name: acquisition
neurodata_type_inc: ElectricalSeries
doc: 'ElectricalSeries recorded by this ElectrodeGroup'
quantity: '?'
groups:
- neurodata_type_inc: LFP
name: lfp
doc: 'LFP recorded from this ElectrodeGroup'
quantity: '?'
- neurodata_type_inc: EventWaveform
name: event_waveform
doc: 'Spike waveforms recorded from this ElectrodeGroup'
quantity: '?'
links:
- name: device
doc: the device that was used to record from this electrode group
Expand Down
17 changes: 15 additions & 2 deletions src/pynwb/ecephys.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,33 @@ class ElectrodeGroup(NWBContainer):
__nwbfields__ = ('name',
'description',
'location',
'device')
'device',
{'name': 'lfp', 'doc': 'LFP recorded from this ElectrodeGroup', 'child': False},
{'name': 'event_waveform', 'doc': 'Spike waveforms recorded from this ElectrodeGroup',
'child': False},
{'name': 'acquisition', 'doc': 'ElectricalSeries recorded by this ElectrodeGroup', 'child': False})

@docval({'name': 'name', 'type': str, 'doc': 'the name of this electrode'},
{'name': 'description', 'type': str, 'doc': 'description of this electrode group'},
{'name': 'location', 'type': str, 'doc': 'description of location of this electrode group'},
{'name': 'device', 'type': Device, 'doc': 'the device that was used to record from this electrode group'},
{'name': 'lfp', 'type': 'LFP', 'doc': 'LFP recorded from this ElectrodeGroup', 'default': None},
{'name': 'event_waveform', 'type': 'EventWaveform',
'doc': 'Spike waveforms recorded from this ElectrodeGroup', 'default': None},
{'name': 'acquisition', 'type': 'ElectricalSeries',
'doc': 'ElectricalSeries recorded by this ElectrodeGroup', 'default': None},
{'name': 'parent', 'type': 'NWBContainer',
'doc': 'The parent NWBContainer for this NWBContainer', 'default': None})
def __init__(self, **kwargs):
call_docval_func(super(ElectrodeGroup, self).__init__, kwargs)
description, location, device = popargs("description", "location", "device", kwargs)
description, location, device, lfp, event_waveform, acquisition = popargs(
"description", "location", "device", "lfp", "event_waveform", "acquisition", kwargs)
self.description = description
self.location = location
self.device = device
self.lfp = lfp
self.event_waveform = event_waveform
self.acquisition = acquisition


_et_docval = [
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
25 changes: 8 additions & 17 deletions tests/integration/ui_write/test_ecephys.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,19 @@ class TestElectrodeGroupIO(base.TestMapRoundTrip):

def setUpContainer(self):
self.dev1 = Device('dev1')
return ElectrodeGroup('elec1', 'a test ElectrodeGroup',
'a nonexistent place',
self.dev1)
self.event_waveform = EventWaveform()
self.lfp = LFP()

def setUpBuilder(self):
device_builder = GroupBuilder('dev1',
attributes={'neurodata_type': 'Device',
'namespace': 'core',
'help': 'A recording device e.g. amplifier'})
return GroupBuilder('elec1',
attributes={'neurodata_type': 'ElectrodeGroup',
'namespace': 'core',
'help': 'A physical grouping of channels',
'description': 'a test ElectrodeGroup',
'location': 'a nonexistent place'},
links={
'device': LinkBuilder(device_builder, 'device')
})
return ElectrodeGroup('elec1', 'a test ElectrodeGroup', 'a nonexistent place', self.dev1,
event_waveform=self.event_waveform, lfp=self.lfp)

def addContainer(self, nwbfile):
''' Should take an NWBFile object and add the container to it '''
nwbfile.add_device(self.dev1)
ecephys_mod = nwbfile.create_processing_module('ecephys', 'description')
ecephys_mod.add_data_interface(self.event_waveform)
ecephys_mod.add_data_interface(self.lfp)

nwbfile.add_electrode_group(self.container)

def getContainer(self, nwbfile):
Expand Down