LorenFrankLab / spyglass

Neuroscience data analysis framework for reproducible research built by Loren Frank Lab at UCSF
https://lorenfranklab.github.io/spyglass/
MIT License
94 stars 43 forks source link

`DLCPosVideo` fails for non-existent interval #1160

Closed rpswenson closed 3 weeks ago

rpswenson commented 1 month ago

Describe the bug The DLCPosVideo table is unable to be populated, potentially due to a missing interval list?

To Reproduce

dlc_key = {'nwb_file_name': 'RS1220240810_.nwb', 'epoch': 8, 'video_file_num': 1, 'project_name': 'RS1220240810_run', 'dlc_model_name': 'RS1220240810_run_tutorial_01', 'dlc_model_params_name': 'default', 'dlc_centroid_params_name': 'default', 'dlc_si_cohort_centroid': 'green_red_led', 'dlc_si_cohort_orientation': 'green_red_led', 'dlc_orientation_params_name': 'default'}

sgp.DLCPosVideo().populate(dlc_key)

Error stack:

AttributeError                            Traceback (most recent call last)
Cell In[17], line 1
----> 1 sgp.DLCPosVideo().populate(dlc_key)

File ~/spyglass/src/spyglass/utils/dj_mixin.py:612, in SpyglassMixin.populate(self, *restrictions, **kwargs)
    610 if use_transact:  # Pass single-process populate to super
    611     kwargs["processes"] = processes
--> 612     return super().populate(*restrictions, **kwargs)
    613 else:  # No transaction protection, use bare make
    614     for key in keys:

File ~/miniforge3/envs/spyglass/lib/python3.9/site-packages/datajoint/autopopulate.py:248, in AutoPopulate.populate(self, suppress_errors, return_exception_objects, reserve_jobs, order, limit, max_calls, display_progress, processes, make_kwargs, *restrictions)
    242 if processes == 1:
    243     for key in (
    244         tqdm(keys, desc=self.__class__.__name__)
    245         if display_progress
    246         else keys
    247     ):
--> 248         status = self._populate1(key, jobs, **populate_kwargs)
    249         if status is True:
    250             success_list.append(1)

File ~/miniforge3/envs/spyglass/lib/python3.9/site-packages/datajoint/autopopulate.py:315, in AutoPopulate._populate1(self, key, jobs, suppress_errors, return_exception_objects, make_kwargs)
    313 self.__class__._allow_insert = True
    314 try:
--> 315     make(dict(key), **(make_kwargs or {}))
    316 except (KeyboardInterrupt, SystemExit, Exception) as error:
    317     try:

File ~/spyglass/src/spyglass/position/v1/position_dlc_selection.py:354, in DLCPosVideo.make(self, key)
    344 params = (DLCPosVideoParams & key).fetch1("params")
    346 interval_name = convert_epoch_interval_name_to_position_interval_name(
    347     {
    348         "nwb_file_name": key["nwb_file_name"],
   (...)
    351     populate_missing=False,
    352 )
    353 epoch = (
--> 354     int(interval_name.replace("pos ", "").replace(" valid times", ""))
    355     + 1
    356 )
    357 pose_est_key = {
    358     "nwb_file_name": key["nwb_file_name"],
    359     "epoch": epoch,
    360     "dlc_model_name": key["dlc_model_name"],
    361     "dlc_model_params_name": key["dlc_model_params_name"],
    362 }
    364 pose_estimation_params, video_filename, output_dir, meters_per_pixel = (
    365     DLCPoseEstimationSelection * DLCPoseEstimation & pose_est_key
    366 ).fetch1(
   (...)
    370     "meters_per_pixel",
    371 )

AttributeError: 'list' object has no attribute 'replace'

Looking at interval_name in this line: --> 354 int(interval_name.replace("pos ", "").replace(" valid times", "")) shows an empty list. I'm not sure if this is expected or not, given that we have no trodes position

CBroz1 commented 1 month ago

It looks like convert_epoch_interval_name does return an empty list for a non-existent interval when populate_missing is set to false. My memory is that @samuelbray32 developed this table, so it's worth asking him why...

  1. DLCPosVideo sets populate_missing to False
  2. convert_epoch returns an empty list, rather than raising an error

It would make sense to me to set populate_missing to True here, but I would want to check before making a fix

In the short term, you can try running the following before rerunning the populate

from spyglass.common.common_behav import (
    convert_epoch_interval_name_to_position_interval_name,
)

convert_epoch_interval_name_to_position_interval_name(
    {
        "nwb_file_name": your_file,
        "epoch": your_epoch,
    },
    populate_missing = True
)
rpswenson commented 1 month ago

Ok, I'll ask Sam about it when he's back from time off. I tried running the cell you suggested but it did not seem to like that there weren't any pos intervals:

from spyglass.common.common_behav import (
    convert_epoch_interval_name_to_position_interval_name,
)

convert_epoch_interval_name_to_position_interval_name(
    {
        "nwb_file_name": "RS1220240810_.nwb",
        "epoch": 8,
    },
    populate_missing = True
)
[14:40:18][ERROR] Spyglass: NO POS INTERVALS FOR {'nwb_file_name': 'RS1220240810_.nwb', 'interval_list_name': '08_r4'}; CANNOT POPULATE PositionIntervalMap
[14:40:18][INFO] Spyglass: No position intervals found for {'nwb_file_name': 'RS1220240810_.nwb', 'epoch': 8, 'interval_list_name': '08_r4'}

[]
CBroz1 commented 1 month ago

no trodes position

It may be that the previous effort to use this pipeline without trodes position did not consider video creation step

MichaelCoulter commented 1 month ago

could someone else take a look at this since sam is out all of next week?