rly / ndx-pose

NWB extension to store pose estimation data
BSD 3-Clause "New" or "Revised" License
13 stars 11 forks source link

Use ImageSeries for original and labeled videos #13

Open rly opened 1 year ago

rly commented 1 year ago

Fix #12. Not tested yet, but posting to get feedback.

I tried to maintain backwards compatibility by creating new fields with different names for original and labeled videos and raising a warning if the old fields are used.

  1. Added untyped group named original_videos_series (like how acquisition is an untyped group in NWBFile for organizational purposes) that holds links to ImageSeries objects.
  2. Added untyped group named labeled_videos_series that holds included ImageSeries objects
  3. For clean and consistent organization, I also moved the included PoseEstimationSeries objects into an untyped group named pose_estimation_series that holds included PoseEstimationSeries objects.

cc @codycbakerphd

CodyCBakerPhD commented 1 year ago

Worked fine until io.write(nwbfile), hope this traceback helps

Also, given how little time there is left on the IBL turnaround (I need to reserve at least a week if not more just for running) I think I'll just use closely matched object names to make the connection clear

This will be a more preferred approach going forward however to make the linkage explicit

    io.write(nwbfile)
  File "/home/jovyan/my-conda-envs/run_ibl/lib/python3.8/site-packages/hdmf/utils.py", line 645, in func_call
    return func(args[0], **pargs)
  File "/home/jovyan/my-conda-envs/run_ibl/lib/python3.8/site-packages/hdmf/backends/hdf5/h5tools.py", line 360, in write
    super().write(**kwargs)
  File "/home/jovyan/my-conda-envs/run_ibl/lib/python3.8/site-packages/hdmf/utils.py", line 645, in func_call
    return func(args[0], **pargs)
  File "/home/jovyan/my-conda-envs/run_ibl/lib/python3.8/site-packages/hdmf/backends/io.py", line 50, in write
    f_builder = self.__manager.build(container, source=self.__source, root=True)
  File "/home/jovyan/my-conda-envs/run_ibl/lib/python3.8/site-packages/hdmf/utils.py", line 645, in func_call
    return func(args[0], **pargs)
  File "/home/jovyan/my-conda-envs/run_ibl/lib/python3.8/site-packages/hdmf/build/manager.py", line 171, in build
    result = self.__type_map.build(container, self, source=source, spec_ext=spec_ext, export=export)
  File "/home/jovyan/my-conda-envs/run_ibl/lib/python3.8/site-packages/hdmf/utils.py", line 645, in func_call
    return func(args[0], **pargs)
  File "/home/jovyan/my-conda-envs/run_ibl/lib/python3.8/site-packages/hdmf/build/manager.py", line 764, in build
    builder = obj_mapper.build(container, manager, builder=builder, source=source, spec_ext=spec_ext, export=export)
  File "/home/jovyan/my-conda-envs/run_ibl/lib/python3.8/site-packages/hdmf/utils.py", line 645, in func_call
    return func(args[0], **pargs)
  File "/home/jovyan/my-conda-envs/run_ibl/lib/python3.8/site-packages/hdmf/build/objectmapper.py", line 706, in build
    self.__add_groups(builder, self.__spec.groups, container, manager, source, export)
  File "/home/jovyan/my-conda-envs/run_ibl/lib/python3.8/site-packages/hdmf/build/objectmapper.py", line 1027, in __add_groups
    self.__add_groups(sub_builder, spec.groups, container, build_manager, source, export)
  File "/home/jovyan/my-conda-envs/run_ibl/lib/python3.8/site-packages/hdmf/build/objectmapper.py", line 1040, in __add_groups
    self.__add_containers(builder, spec, attr_value, build_manager, source, container, export)
  File "/home/jovyan/my-conda-envs/run_ibl/lib/python3.8/site-packages/hdmf/build/objectmapper.py", line 1098, in __add_containers
    self.__add_containers(builder, spec, container, build_manager, source, parent_container, export)
  File "/home/jovyan/my-conda-envs/run_ibl/lib/python3.8/site-packages/hdmf/build/objectmapper.py", line 1060, in __add_containers
    new_builder = build_manager.build(value, source=source, spec_ext=spec, export=export)
  File "/home/jovyan/my-conda-envs/run_ibl/lib/python3.8/site-packages/hdmf/utils.py", line 645, in func_call
    return func(args[0], **pargs)
  File "/home/jovyan/my-conda-envs/run_ibl/lib/python3.8/site-packages/hdmf/build/manager.py", line 171, in build
    result = self.__type_map.build(container, self, source=source, spec_ext=spec_ext, export=export)
  File "/home/jovyan/my-conda-envs/run_ibl/lib/python3.8/site-packages/hdmf/utils.py", line 645, in func_call
    return func(args[0], **pargs)
  File "/home/jovyan/my-conda-envs/run_ibl/lib/python3.8/site-packages/hdmf/build/manager.py", line 764, in build
    builder = obj_mapper.build(container, manager, builder=builder, source=source, spec_ext=spec_ext, export=export)
  File "/home/jovyan/my-conda-envs/run_ibl/lib/python3.8/site-packages/hdmf/utils.py", line 645, in func_call
    return func(args[0], **pargs)
  File "/home/jovyan/my-conda-envs/run_ibl/lib/python3.8/site-packages/hdmf/build/objectmapper.py", line 706, in build
    self.__add_groups(builder, self.__spec.groups, container, manager, source, export)
  File "/home/jovyan/my-conda-envs/run_ibl/lib/python3.8/site-packages/hdmf/build/objectmapper.py", line 1040, in __add_groups
    self.__add_containers(builder, spec, attr_value, build_manager, source, container, export)
  File "/home/jovyan/my-conda-envs/run_ibl/lib/python3.8/site-packages/hdmf/build/objectmapper.py", line 1098, in __add_containers
    self.__add_containers(builder, spec, container, build_manager, source, parent_container, export)
  File "/home/jovyan/my-conda-envs/run_ibl/lib/python3.8/site-packages/hdmf/build/objectmapper.py", line 1060, in __add_containers
    new_builder = build_manager.build(value, source=source, spec_ext=spec, export=export)
  File "/home/jovyan/my-conda-envs/run_ibl/lib/python3.8/site-packages/hdmf/utils.py", line 645, in func_call
    return func(args[0], **pargs)
  File "/home/jovyan/my-conda-envs/run_ibl/lib/python3.8/site-packages/hdmf/build/manager.py", line 171, in build
    result = self.__type_map.build(container, self, source=source, spec_ext=spec_ext, export=export)
  File "/home/jovyan/my-conda-envs/run_ibl/lib/python3.8/site-packages/hdmf/utils.py", line 645, in func_call
    return func(args[0], **pargs)
  File "/home/jovyan/my-conda-envs/run_ibl/lib/python3.8/site-packages/hdmf/build/manager.py", line 757, in build
    obj_mapper = self.get_map(container)
  File "/home/jovyan/my-conda-envs/run_ibl/lib/python3.8/site-packages/hdmf/utils.py", line 645, in func_call
    return func(args[0], **pargs)
  File "/home/jovyan/my-conda-envs/run_ibl/lib/python3.8/site-packages/hdmf/build/manager.py", line 714, in get_map
    mapper = mapper_cls(spec)
  File "/home/jovyan/GitHub/ndx-pose/src/pynwb/ndx_pose/io/pose.py", line 34, in __init__
    self.map_spec('original_videos_series', original_videos_series_spec.get_neurodata_type('ImageSeries'))
  File "/home/jovyan/my-conda-envs/run_ibl/lib/python3.8/site-packages/hdmf/utils.py", line 644, in func_call
    pargs = _check_args(args, kwargs)
  File "/home/jovyan/my-conda-envs/run_ibl/lib/python3.8/site-packages/hdmf/utils.py", line 637, in _check_args
    raise ExceptionType(msg)
TypeError: ObjectMapper.map_spec: None is not allowed for 'spec' (expected 'Spec', not None)
weiglszonja commented 9 months ago

hey @rly, I'm working on a new data interface in NeuroConv to support writing data from LightningPose to NWB using this extension. I think making this change work would be a great improvement, do you have any idea how to fix this mapping error that @CodyCBakerPhD noticed?

rly commented 9 months ago

I pushed the likely fix, but I might not get to fully testing this branch until next week. I need to update the main branch with #21 first before making other changes to the schema.

bendichter commented 9 months ago

@rly do we really need to keep around all these old deprecated parts? Would you be OK with just deleting them?

weiglszonja commented 9 months ago

@rly I'm testing it now but it seems the mapping is not working yet:

tests/test_on_data/test_format_converters/test_lightningpose_converter.py:44 (TestLightningPoseConverter.test_run_conversion_add_conversion_options)
self = <tests.test_on_data.test_format_converters.test_lightningpose_converter.TestLightningPoseConverter testMethod=test_run_conversion_add_conversion_options>

    def test_run_conversion_add_conversion_options(self):
        nwbfile_path = str(self.test_dir / "test_lightningpose_converter_conversion_options.nwb")
>       self.converter.run_conversion(
            nwbfile_path=nwbfile_path,
            **self.conversion_options,
        )

test_lightningpose_converter.py:47: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../src/neuroconv/datainterfaces/behavior/lightningpose/lightningposeconverter.py:122: in run_conversion
    with make_or_load_nwbfile(
/Users/weian/anaconda3/envs/neuroconv311/lib/python3.11/contextlib.py:144: in __exit__
    next(self.gen)
../../../src/neuroconv/tools/nwb_helpers/_metadata_and_file_helpers.py:189: in make_or_load_nwbfile
    io.write(nwbfile)
/Users/weian/anaconda3/envs/neuroconv311/lib/python3.11/site-packages/hdmf/utils.py:664: in func_call
    return func(args[0], **pargs)
/Users/weian/anaconda3/envs/neuroconv311/lib/python3.11/site-packages/hdmf/backends/hdf5/h5tools.py:375: in write
    super().write(**kwargs)
/Users/weian/anaconda3/envs/neuroconv311/lib/python3.11/site-packages/hdmf/utils.py:664: in func_call
    return func(args[0], **pargs)
/Users/weian/anaconda3/envs/neuroconv311/lib/python3.11/site-packages/hdmf/backends/io.py:98: in write
    f_builder = self.__manager.build(container, source=self.__source, root=True)
/Users/weian/anaconda3/envs/neuroconv311/lib/python3.11/site-packages/hdmf/utils.py:664: in func_call
    return func(args[0], **pargs)
/Users/weian/anaconda3/envs/neuroconv311/lib/python3.11/site-packages/hdmf/build/manager.py:171: in build
    result = self.__type_map.build(container, self, source=source, spec_ext=spec_ext, export=export)
/Users/weian/anaconda3/envs/neuroconv311/lib/python3.11/site-packages/hdmf/utils.py:664: in func_call
    return func(args[0], **pargs)
/Users/weian/anaconda3/envs/neuroconv311/lib/python3.11/site-packages/hdmf/build/manager.py:770: in build
    builder = obj_mapper.build(container, manager, builder=builder, source=source, spec_ext=spec_ext, export=export)
/Users/weian/anaconda3/envs/neuroconv311/lib/python3.11/site-packages/hdmf/utils.py:664: in func_call
    return func(args[0], **pargs)
/Users/weian/anaconda3/envs/neuroconv311/lib/python3.11/site-packages/hdmf/build/objectmapper.py:717: in build
    self.__add_groups(builder, self.__spec.groups, container, manager, source, export)
/Users/weian/anaconda3/envs/neuroconv311/lib/python3.11/site-packages/hdmf/build/objectmapper.py:1037: in __add_groups
    self.__add_groups(sub_builder, spec.groups, container, build_manager, source, export)
/Users/weian/anaconda3/envs/neuroconv311/lib/python3.11/site-packages/hdmf/build/objectmapper.py:1050: in __add_groups
    self.__add_containers(builder, spec, attr_value, build_manager, source, container, export)
/Users/weian/anaconda3/envs/neuroconv311/lib/python3.11/site-packages/hdmf/build/objectmapper.py:1108: in __add_containers
    self.__add_containers(builder, spec, container, build_manager, source, parent_container, export)
/Users/weian/anaconda3/envs/neuroconv311/lib/python3.11/site-packages/hdmf/build/objectmapper.py:1070: in __add_containers
    new_builder = build_manager.build(value, source=source, spec_ext=spec, export=export)
/Users/weian/anaconda3/envs/neuroconv311/lib/python3.11/site-packages/hdmf/utils.py:664: in func_call
    return func(args[0], **pargs)
/Users/weian/anaconda3/envs/neuroconv311/lib/python3.11/site-packages/hdmf/build/manager.py:171: in build
    result = self.__type_map.build(container, self, source=source, spec_ext=spec_ext, export=export)
/Users/weian/anaconda3/envs/neuroconv311/lib/python3.11/site-packages/hdmf/utils.py:664: in func_call
    return func(args[0], **pargs)
/Users/weian/anaconda3/envs/neuroconv311/lib/python3.11/site-packages/hdmf/build/manager.py:770: in build
    builder = obj_mapper.build(container, manager, builder=builder, source=source, spec_ext=spec_ext, export=export)
/Users/weian/anaconda3/envs/neuroconv311/lib/python3.11/site-packages/hdmf/utils.py:664: in func_call
    return func(args[0], **pargs)
/Users/weian/anaconda3/envs/neuroconv311/lib/python3.11/site-packages/hdmf/build/objectmapper.py:717: in build
    self.__add_groups(builder, self.__spec.groups, container, manager, source, export)
/Users/weian/anaconda3/envs/neuroconv311/lib/python3.11/site-packages/hdmf/build/objectmapper.py:1050: in __add_groups
    self.__add_containers(builder, spec, attr_value, build_manager, source, container, export)
/Users/weian/anaconda3/envs/neuroconv311/lib/python3.11/site-packages/hdmf/build/objectmapper.py:1108: in __add_containers
    self.__add_containers(builder, spec, container, build_manager, source, parent_container, export)
/Users/weian/anaconda3/envs/neuroconv311/lib/python3.11/site-packages/hdmf/build/objectmapper.py:1070: in __add_containers
    new_builder = build_manager.build(value, source=source, spec_ext=spec, export=export)
/Users/weian/anaconda3/envs/neuroconv311/lib/python3.11/site-packages/hdmf/utils.py:664: in func_call
    return func(args[0], **pargs)
/Users/weian/anaconda3/envs/neuroconv311/lib/python3.11/site-packages/hdmf/build/manager.py:171: in build
    result = self.__type_map.build(container, self, source=source, spec_ext=spec_ext, export=export)
/Users/weian/anaconda3/envs/neuroconv311/lib/python3.11/site-packages/hdmf/utils.py:664: in func_call
    return func(args[0], **pargs)
/Users/weian/anaconda3/envs/neuroconv311/lib/python3.11/site-packages/hdmf/build/manager.py:763: in build
    obj_mapper = self.get_map(container)
/Users/weian/anaconda3/envs/neuroconv311/lib/python3.11/site-packages/hdmf/utils.py:664: in func_call
    return func(args[0], **pargs)
/Users/weian/anaconda3/envs/neuroconv311/lib/python3.11/site-packages/hdmf/build/manager.py:720: in get_map
    mapper = mapper_cls(spec)
/Users/weian/anaconda3/envs/neuroconv311/lib/python3.11/site-packages/ndx_pose/io/pose.py:29: in __init__
    self.unmap(pose_estimates_spec)
/Users/weian/anaconda3/envs/neuroconv311/lib/python3.11/site-packages/hdmf/utils.py:663: in func_call
    pargs = _check_args(args, kwargs)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<ndx_pose.io.pose.PoseEstimationMap object at 0x2ac19c610>, None)
kwargs = {}

    def _check_args(args, kwargs):
        """Parse and check arguments to decorated function. Raise warnings and errors as appropriate."""
        # this function was separated from func_call() in order to make stepping through lines of code using pdb
        # easier

        parsed = __parse_args(
            loc_val,
            args[1:] if is_method else args,
            kwargs,
            enforce_type=enforce_type,
            enforce_shape=enforce_shape,
            allow_extra=allow_extra,
            allow_positional=allow_positional
        )

        parse_warnings = parsed.get('future_warnings')
        if parse_warnings:
            msg = '%s: %s' % (func.__qualname__, ', '.join(parse_warnings))
            warnings.warn(msg, FutureWarning)

        for error_type, ExceptionType in (('type_errors', TypeError),
                                          ('value_errors', ValueError),
                                          ('syntax_errors', SyntaxError)):
            parse_err = parsed.get(error_type)
            if parse_err:
                msg = '%s: %s' % (func.__qualname__, ', '.join(parse_err))
>               raise ExceptionType(msg)
E               TypeError: ObjectMapper.unmap: None is not allowed for 'spec' (expected 'Spec', not None)

/Users/weian/anaconda3/envs/neuroconv311/lib/python3.11/site-packages/hdmf/utils.py:656: TypeError