Skip to content

Commit ed356e8

Browse files
committed
handle more complex metadata in nwb files
cf NeuralEnsemble#1413
1 parent a54c191 commit ed356e8

File tree

1 file changed

+38
-7
lines changed

1 file changed

+38
-7
lines changed

neo/io/nwbio.py

+38-7
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import numpy as np
2626
import quantities as pq
2727

28+
from neo.core.baseneo import _check_annotations
2829
from neo.core import Segment, SpikeTrain, Epoch, Event, AnalogSignal, IrregularlySampledSignal, Block, ImageSequence
2930
from neo.io.baseio import BaseIO
3031
from neo.io.proxyobjects import (
@@ -195,6 +196,18 @@ def _recompose_unit(base_unit_name, conversion):
195196
return pq.dimensionless
196197

197198

199+
def nwb_obj_to_dict(obj):
200+
if not hasattr(obj, "fields"):
201+
raise TypeError("Does not seem to be an NWB object")
202+
result = {}
203+
for key, value in obj.fields.items():
204+
if hasattr(value, "fields"):
205+
result[key] = nwb_obj_to_dict(value)
206+
else:
207+
result[key] = value
208+
return result
209+
210+
198211
class NWBIO(BaseIO):
199212
"""
200213
Class for "reading" experimental data from a .nwb file, and "writing" a .nwb file from Neo
@@ -244,6 +257,7 @@ def read_all_blocks(self, lazy=False, **kwargs):
244257
"""
245258
Load all blocks in the file.
246259
"""
260+
import hdmf
247261
import pynwb
248262

249263
if self.nwb_file_mode not in ("r",):
@@ -264,6 +278,11 @@ def read_all_blocks(self, lazy=False, **kwargs):
264278
if value is not None:
265279
if annotation_name in POSSIBLE_JSON_FIELDS:
266280
value = try_json_field(value)
281+
elif isinstance(value, hdmf.utils.StrDataset):
282+
value = list(value)
283+
# placing this check here for easier debugging, but it's redundant so we should remove it
284+
# once we're handling all possible annotation types
285+
_check_annotations(value)
267286
self.global_block_metadata[annotation_name] = value
268287
if "session_description" in self.global_block_metadata:
269288
self.global_block_metadata["description"] = self.global_block_metadata["session_description"]
@@ -691,6 +710,8 @@ class AnalogSignalProxy(BaseAnalogSignalProxy):
691710
)
692711

693712
def __init__(self, timeseries, nwb_group):
713+
import pynwb
714+
694715
self._timeseries = timeseries
695716
self.units = timeseries.unit
696717
if timeseries.conversion:
@@ -722,8 +743,11 @@ def __init__(self, timeseries, nwb_group):
722743
pass
723744
for field_name in metadata_fields:
724745
value = getattr(timeseries, field_name)
746+
if hasattr(value, "fields"):
747+
value = nwb_obj_to_dict(value)
725748
if value is not None:
726749
self.annotations[f"nwb:{field_name}"] = value
750+
_check_annotations(value) # tmp for easier debugging
727751
self.annotations["nwb_neurodata_type"] = (timeseries.__class__.__module__, timeseries.__class__.__name__)
728752
if hasattr(timeseries, "electrode"):
729753
# todo: once the Group class is available, we could add electrode metadata
@@ -865,15 +889,22 @@ def __init__(self, units_table, id):
865889
self._units_table = units_table
866890
self.id = id
867891
self.units = pq.s
868-
obs_intervals = units_table.get_unit_obs_intervals(id)
869-
if len(obs_intervals) == 0:
892+
try:
893+
obs_intervals = units_table.get_unit_obs_intervals(id)
894+
except KeyError:
895+
logger.warn("Unable to retrieve obs_intervals")
870896
t_start, t_stop = None, None
871-
elif len(obs_intervals) == 1:
872-
t_start, t_stop = obs_intervals[0]
873897
else:
874-
raise NotImplementedError("Can't yet handle multiple observation intervals")
875-
self.t_start = t_start * pq.s
876-
self.t_stop = t_stop * pq.s
898+
if len(obs_intervals) == 0:
899+
t_start, t_stop = None, None
900+
elif len(obs_intervals) == 1:
901+
t_start, t_stop = obs_intervals[0]
902+
t_start = t_start * pq.s
903+
t_stop = t_stop * pq.s
904+
else:
905+
raise NotImplementedError("Can't yet handle multiple observation intervals")
906+
self.t_start = t_start
907+
self.t_stop = t_stop
877908
self.annotations = {"nwb_group": "acquisition"}
878909
try:
879910
# NWB files created by Neo store the name as an extra column

0 commit comments

Comments
 (0)