@@ -41,6 +41,8 @@ def insert_idx(array, values):
4141 idx [np .where (abs (values - array [idx - 1 ]) < abs (values - array [idx ]))] -= 1
4242 # If 0 index was reduced, revert
4343 idx [idx == - 1 ] = 0
44+ if np .all (idx == 0 ):
45+ raise ValueError ('Something is wrong, all values to insert are outside of the array.' )
4446 return idx
4547
4648
@@ -121,7 +123,7 @@ def get_feature_event_times(dlc, dlc_t, features):
121123
122124def get_licks (dlc , dlc_t ):
123125 """
124- Compute lick times from the toungue dlc points
126+ Compute lick times from the tongue dlc points
125127 :param dlc: dlc pqt table
126128 :param dlc_t: dlc times
127129 :return:
@@ -216,6 +218,9 @@ def get_smooth_pupil_diameter(diameter_raw, camera, std_thresh=5, nan_thresh=1):
216218 else :
217219 raise NotImplementedError ("camera has to be 'left' or 'right" )
218220
221+ # Raise error if too many NaN time points, in this case it doesn't make sense to interpolate
222+ if np .mean (np .isnan (diameter_raw )) > 0.9 :
223+ raise ValueError (f"Raw pupil diameter for { camera } is too often NaN, cannot smooth." )
219224 # run savitzy-golay filter on non-nan time points to denoise
220225 diameter_smoothed = smooth_interpolate_savgol (diameter_raw , window = window , order = 3 , interp_kind = 'linear' )
221226
@@ -440,26 +445,37 @@ def plot_motion_energy_hist(camera_dict, trials_df):
440445 'body' : '#035382' }
441446
442447 start_window , end_window = plt_window (trials_df ['stimOn_times' ])
448+ missing_data = []
443449 for cam in camera_dict .keys ():
444- try :
445- motion_energy = zscore (camera_dict [cam ]['motion_energy' ], nan_policy = 'omit' )
446- start_idx = insert_idx (camera_dict [cam ]['times' ], start_window )
447- end_idx = np .array (start_idx + int (WINDOW_LEN * SAMPLING [cam ]), dtype = 'int64' )
448- me_all = [motion_energy [start_idx [i ]:end_idx [i ]] for i in range (len (start_idx ))]
449- times = np .arange (len (me_all [0 ])) / SAMPLING [cam ] + WINDOW_LAG
450- me_mean = np .mean (me_all , axis = 0 )
451- me_std = np .std (me_all , axis = 0 ) / np .sqrt (len (me_all ))
452- plt .plot (times , me_mean , label = f'{ cam } cam' , color = colors [cam ], linewidth = 2 )
453- plt .fill_between (times , me_mean + me_std , me_mean - me_std , color = colors [cam ], alpha = 0.2 )
454- except AttributeError :
455- logger .warning (f"Cannot load motion energy AND times data for { cam } camera" )
450+ if (camera_dict [cam ]['motion_energy' ] is not None and len (camera_dict [cam ]['motion_energy' ]) > 0
451+ and camera_dict [cam ]['times' ] is not None and len (camera_dict [cam ]['times' ]) > 0 ):
452+ try :
453+ motion_energy = zscore (camera_dict [cam ]['motion_energy' ], nan_policy = 'omit' )
454+ start_idx = insert_idx (camera_dict [cam ]['times' ], start_window )
455+ end_idx = np .array (start_idx + int (WINDOW_LEN * SAMPLING [cam ]), dtype = 'int64' )
456+ me_all = [motion_energy [start_idx [i ]:end_idx [i ]] for i in range (len (start_idx ))]
457+ times = np .arange (len (me_all [0 ])) / SAMPLING [cam ] + WINDOW_LAG
458+ me_mean = np .mean (me_all , axis = 0 )
459+ me_std = np .std (me_all , axis = 0 ) / np .sqrt (len (me_all ))
460+ plt .plot (times , me_mean , label = f'{ cam } cam' , color = colors [cam ], linewidth = 2 )
461+ plt .fill_between (times , me_mean + me_std , me_mean - me_std , color = colors [cam ], alpha = 0.2 )
462+ except AttributeError :
463+ logger .warning (f"Cannot load motion energy and/or times data for { cam } camera" )
464+ missing_data .append (cam )
465+ else :
466+ logger .warning (f"Data missing or empty for motion energy and/or times data for { cam } camera" )
467+ missing_data .append (cam )
456468
457469 plt .xticks ([- 0.5 , 0 , 0.5 , 1 , 1.5 ])
458470 plt .ylabel ('z-scored motion energy [a.u.]' )
459471 plt .xlabel ('time [sec]' )
460472 plt .axvline (x = 0 , label = 'stimOn' , linestyle = '--' , c = 'k' )
461473 plt .legend (loc = 'lower right' )
462474 plt .title ('Motion Energy' )
475+ if len (missing_data ) > 0 :
476+ ax = plt .gca ()
477+ ax .text (.95 , .35 , f"Data incomplete for\n { ' and ' .join (missing_data )} camera" , color = 'r' , fontsize = 10 ,
478+ horizontalalignment = 'right' , verticalalignment = 'center' , transform = ax .transAxes )
463479 return plt .gca ()
464480
465481
@@ -477,6 +493,8 @@ def plot_speed_hist(dlc_df, cam_times, trials_df, feature='paw_r', cam='left', l
477493 """
478494 # Threshold the dlc traces
479495 dlc_df = likelihood_threshold (dlc_df )
496+ # For pre-GPIO sessions, remove the first few timestamps to match the number of frames
497+ cam_times = cam_times [- len (dlc_df ):]
480498 # Get speeds
481499 speeds = get_speed (dlc_df , cam_times , camera = cam , feature = feature )
482500 # Windows aligned to align_to
@@ -495,7 +513,7 @@ def plot_speed_hist(dlc_df, cam_times, trials_df, feature='paw_r', cam='left', l
495513 plt .plot (times , pd .DataFrame .from_dict (dict (zip (incorrect .index , incorrect .values ))).mean (axis = 1 ),
496514 c = 'gray' , label = 'incorrect trial' )
497515 plt .axvline (x = 0 , label = 'stimOn' , linestyle = '--' , c = 'r' )
498- plt .title (f'{ feature .split ("_" )[0 ].capitalize ()} speed' )
516+ plt .title (f'{ feature .split ("_" )[0 ].capitalize ()} speed ( { cam } cam) ' )
499517 plt .xticks ([- 0.5 , 0 , 0.5 , 1 , 1.5 ])
500518 plt .xlabel ('time [sec]' )
501519 plt .ylabel ('speed [px/sec]' )
@@ -531,7 +549,7 @@ def plot_pupil_diameter_hist(pupil_diameter, cam_times, trials_df, cam='left'):
531549 plt .plot (times , pupil_mean , label = align_to .split ("_" )[0 ], color = color )
532550 plt .fill_between (times , pupil_mean + pupil_std , pupil_mean - pupil_std , color = color , alpha = 0.5 )
533551 plt .axvline (x = 0 , linestyle = '--' , c = 'k' )
534- plt .title ('Pupil diameter' )
552+ plt .title (f 'Pupil diameter ( { cam } cam) ' )
535553 plt .xlabel ('time [sec]' )
536554 plt .xticks ([- 0.5 , 0 , 0.5 , 1 , 1.5 ])
537555 plt .ylabel ('pupil diameter [px]' )
0 commit comments