Skip to content

Commit 2a751aa

Browse files
nwb_image_series
1 parent 3980028 commit 2a751aa

File tree

9 files changed

+150
-2
lines changed

9 files changed

+150
-2
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,9 @@ Representation of CameraDevice object in NWB <br>
7272
**Attributes:** <br>
7373
**meters_per_pixel** `float`: meter per pixel <br>
7474

75+
#### NbwTimeSeries
76+
Extension of ImageSeries object in NWB <br>
77+
**Attributes:** <br>
78+
**devices** `list of Device`: devices used to record video <br>
79+
7580
This extension was created using [ndx-template](https://github.com/nwb-extensions/ndx-template).

spec/ndx-franklab-novela.extensions.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,13 @@ groups:
7272
- name: meters_per_pixel
7373
dtype: float
7474
doc: meters per pixel
75+
- neurodata_type_def: NwbImageSeries
76+
neurodata_type_inc: ImageSeries
77+
doc: Extension of ImageSeries object in NWB
78+
groups:
79+
- neurodata_type_inc: Device
80+
doc: devices used to record video
81+
quantity: '*'
7582
- neurodata_type_def: HeaderDevice
7683
neurodata_type_inc: Device
7784
doc: metadata from global configuration from header

spec/ndx-franklab-novela.namespace.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@ namespaces:
1111
- ElectrodeGroup
1212
- Device
1313
- NWBDataInterface
14+
- ImageSeries
1415
- source: ndx-franklab-novela.extensions.yaml
1516
version: 0.0.007
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
from hdmf import docval
2+
from hdmf.utils import get_docval, call_docval_func
3+
from pynwb import register_class
4+
from pynwb.core import MultiContainerInterface
5+
from pynwb.device import Device
6+
from pynwb.image import ImageSeries
7+
8+
9+
@register_class('NwbImageSeries', 'ndx-franklab-novela')
10+
class NwbImageSeries(ImageSeries, MultiContainerInterface):
11+
''' Extension of ImageSeries object in NWB '''
12+
13+
@docval(*get_docval(ImageSeries .__init__) + (
14+
{'name': 'devices', 'type': (list, tuple), 'doc': 'devices used to record video', 'default': list()},
15+
))
16+
def __init__(self, **kwargs):
17+
super().__init__(**{kwargs_item: kwargs[kwargs_item]
18+
for kwargs_item in kwargs.copy()
19+
if kwargs_item != 'devices'
20+
})
21+
call_docval_func(super(NwbImageSeries, self).__init__, kwargs)
22+
self.devices = kwargs['devices']
23+
24+
__clsconf__ = [
25+
{
26+
'attr': 'devices',
27+
'type': Device,
28+
'add': 'add_device',
29+
'get': 'get_device'
30+
}
31+
]

src/pynwb/ndx_franklab_novela/spec/ndx-franklab-novela.extensions.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,13 @@ groups:
7272
- name: meters_per_pixel
7373
dtype: float
7474
doc: meters per pixel
75+
- neurodata_type_def: NwbImageSeries
76+
neurodata_type_inc: ImageSeries
77+
doc: Extension of ImageSeries object in NWB
78+
groups:
79+
- neurodata_type_inc: Device
80+
doc: devices used to record video
81+
quantity: '*'
7582
- neurodata_type_def: HeaderDevice
7683
neurodata_type_inc: Device
7784
doc: metadata from global configuration from header

src/pynwb/ndx_franklab_novela/spec/ndx-franklab-novela.namespace.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@ namespaces:
1111
- ElectrodeGroup
1212
- Device
1313
- NWBDataInterface
14+
- ImageSeries
1415
- source: ndx-franklab-novela.extensions.yaml
1516
version: 0.0.007
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
from unittest import TestCase
2+
from unittest.mock import Mock
3+
4+
from pynwb.device import Device
5+
6+
from src.pynwb.ndx_franklab_novela.nwb_image_series import NwbImageSeries
7+
8+
9+
class TestNwbImageSeries(TestCase):
10+
11+
def test_nwb_image_series_created_successfully(self):
12+
mock_device_1 = Mock(spec=Device)
13+
mock_device_2 = Mock(spec=Device)
14+
mock_timestamps = [1, 2, 3]
15+
mock_external_file = []
16+
17+
nwb_image_series = NwbImageSeries(
18+
name='NwbImageSeries1',
19+
timestamps=mock_timestamps,
20+
external_file=mock_external_file,
21+
devices=[mock_device_1, mock_device_2]
22+
)
23+
24+
self.assertEqual(nwb_image_series.name, 'NwbImageSeries1')
25+
self.assertEqual(nwb_image_series.timestamps, mock_timestamps)
26+
self.assertEqual(nwb_image_series.external_file, mock_external_file)
27+
self.assertEqual(nwb_image_series.devices, {
28+
mock_device_1.name: mock_device_1,
29+
mock_device_2.name: mock_device_2
30+
})

src/pynwb/tests/test_read_nwb.py

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
import os
2+
from unittest.mock import Mock
23

34
import pynwb
4-
from pynwb import NWBHDF5IO
5+
from pynwb import NWBHDF5IO, ProcessingModule
56

67
from datetime import datetime
78
from dateutil.tz import tzlocal
89
from pynwb import NWBFile
10+
from pynwb.behavior import BehavioralTimeSeries
911
from pynwb.device import Device
1012
from pynwb.testing import TestCase
1113

14+
from src.pynwb.ndx_franklab_novela.camera_device import CameraDevice
1215
from src.pynwb.ndx_franklab_novela.data_acq_device import DataAcqDevice
1316
from src.pynwb.ndx_franklab_novela.header_device import HeaderDevice
1417
from src.pynwb.ndx_franklab_novela.nwb_electrode_group import NwbElectrodeGroup
18+
from src.pynwb.ndx_franklab_novela.nwb_image_series import NwbImageSeries
1519
from src.pynwb.ndx_franklab_novela.probe import Probe, Shank, ShanksElectrode
1620

1721

@@ -116,6 +120,54 @@ def test_read_nwb_data_acq_device_successfully(self):
116120

117121
self.delete_nwb('data_acq_device')
118122

123+
def test_read_nwb_camera_device_successfully(self):
124+
camera_device = CameraDevice(
125+
name='CameraDevice1',
126+
meters_per_pixel=0.20
127+
)
128+
self.nwb_file_content.add_device(camera_device)
129+
130+
nwb_file_handler = NWBHDF5IO('camera_device.nwb', mode='w')
131+
nwb_file_handler.write(self.nwb_file_content)
132+
nwb_file_handler.close()
133+
134+
self.assertTrue(os.path.exists('camera_device.nwb'))
135+
with pynwb.NWBHDF5IO('camera_device.nwb', 'r', load_namespaces=True) as nwb_file_handler:
136+
nwb_file = nwb_file_handler.read()
137+
self.assertContainerEqual(nwb_file.devices['CameraDevice1'], camera_device)
138+
139+
self.delete_nwb('camera_device')
140+
141+
def test_read_nwb_nwb_image_series_successfully(self):
142+
mock_device_1 = Mock(spec=Device)
143+
mock_device_2 = Mock(spec=Device)
144+
mock_timestamps = [1, 2, 3]
145+
mock_external_file = []
146+
147+
nwb_image_series = NwbImageSeries(
148+
name='NwbImageSeries1',
149+
timestamps=mock_timestamps,
150+
external_file=mock_external_file,
151+
devices=[mock_device_1, mock_device_2]
152+
)
153+
behavioral_time_series = BehavioralTimeSeries(name="ImageSeries")
154+
behavioral_time_series.add_timeseries(nwb_image_series)
155+
processing_module = ProcessingModule(name='PM_ImageSeries', description='')
156+
self.nwb_file_content.add_processing_module(processing_module)
157+
self.nwb_file_content.processing['PM_ImageSeries'].add(behavioral_time_series)
158+
159+
nwb_file_handler = NWBHDF5IO('nwb_image_series.nwb', mode='w')
160+
nwb_file_handler.write(self.nwb_file_content)
161+
# nwb_file_handler.close()
162+
#
163+
# self.assertTrue(os.path.exists('nwb_image_series.nwb'))
164+
# with pynwb.NWBHDF5IO('nwb_image_series.nwb', 'r', load_namespaces=True) as nwb_file_handler:
165+
# nwb_file = nwb_file_handler.read()
166+
# print(nwb_file.processing['PM_ImageSeries'])
167+
# self.assertContainerEqual(nwb_file.processing['PM_ImageSeries'], nwb_image_series)
168+
#
169+
# self.delete_nwb('nwb_image_series')
170+
119171
def test_read_nwb_nwb_electrode_group_successfully(self):
120172
device = Device('device_0')
121173
self.nwb_file_content.add_device(device)

src/spec/create_extension_spec.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ def main():
2121
ns_builder.include_type('ElectrodeGroup', namespace='core')
2222
ns_builder.include_type('Device', namespace='core')
2323
ns_builder.include_type('NWBDataInterface', namespace='core')
24+
ns_builder.include_type('ImageSeries', namespace='core')
2425

2526
# see https://pynwb.readthedocs.io/en/latest/extensions.html#extending-nwb
2627
# for more information
@@ -172,6 +173,19 @@ def main():
172173
]
173174
)
174175

176+
nwb_image_series = NWBGroupSpec(
177+
neurodata_type_def='NwbImageSeries',
178+
neurodata_type_inc='ImageSeries',
179+
doc='Extension of ImageSeries object in NWB',
180+
groups=[
181+
NWBGroupSpec(
182+
neurodata_type_inc='Device',
183+
doc='devices used to record video',
184+
quantity='*'
185+
)
186+
],
187+
)
188+
175189
header_device = NWBGroupSpec(
176190
doc='metadata from global configuration from header',
177191
neurodata_type_def='HeaderDevice',
@@ -314,7 +328,7 @@ def main():
314328
)
315329

316330
new_data_types = [
317-
shanks_electrode, shanks, probe, data_acq_device, camera_device, header_device, associated_files, nwb_electrode_group
331+
shanks_electrode, shanks, probe, data_acq_device, camera_device, nwb_image_series, header_device, associated_files, nwb_electrode_group
318332
]
319333

320334
# export the spec to yaml files in the spec folder

0 commit comments

Comments
 (0)