1919# -----------------------------------------------------------------------------
2020
2121# TODO: this function might be pointless
22- def get_entire_session_hist (recording , peaks , peak_locations , spatial_bin_edges ):
22+ def get_entire_session_hist (recording , peaks , peak_locations , spatial_bin_edges , log_scale ):
2323 """
2424 TODO: assumes 1-segment recording
2525 """
@@ -41,11 +41,14 @@ def get_entire_session_hist(recording, peaks, peak_locations, spatial_bin_edges)
4141
4242 spatial_centers = get_bin_centers (spatial_bin_edges )
4343
44+ if log_scale :
45+ entire_session_hist = np .log10 (1 + entire_session_hist )
46+
4447 return entire_session_hist , temporal_bin_edges , spatial_centers
4548
4649
4750def get_chunked_histogram ( # TODO: this function might be pointless
48- recording , peaks , peak_locations , bin_s , spatial_bin_edges , weight_with_amplitude = False
51+ recording , peaks , peak_locations , bin_s , spatial_bin_edges , log_scale , weight_with_amplitude = False
4952):
5053 chunked_session_hist , temporal_bin_edges , _ = \
5154 make_2d_motion_histogram (
@@ -66,6 +69,9 @@ def get_chunked_histogram( # TODO: this function might be pointless
6669 bin_times = np .diff (temporal_bin_edges )[:, np .newaxis ]
6770 chunked_session_hist /= bin_times
6871
72+ if log_scale :
73+ chunked_session_hist = np .log10 (1 + chunked_session_hist )
74+
6975 return chunked_session_hist , temporal_centers , spatial_centers
7076
7177# -----------------------------------------------------------------------------
@@ -354,72 +360,81 @@ def run_kilosort_like_rigid_registration(all_hists, non_rigid_windows):
354360 return - optimal_shift_indices # TODO: these are reversed at this stage
355361
356362
363+ # TODO: I wonder if it is better to estimate the hitsogram with finer bin size
364+ # than try and interpolate the xcorr. What about smoothing the activity histograms directly?
365+
366+ # TOOD: the iterative_template seems a little different to the interpolation
367+ # of nonrigid segments that is described in the NP2.0 paper. Oh, the KS
368+ # implementation is different to that described in the paper/ where is the
369+ # Akima spline interpolation?
370+
371+ # TODO: make sure that the num bins will always align.
372+ # Apply the linear shifts, don't roll, as we don't want circular (why would the top of the probe appear at the bottom?)
373+ # They roll the windowed version that is zeros, but here we want all done up front to simplify later code
374+
375+ # TODO: this is basically a re-implimentation of the nonrigid part
376+ # of iterative template. Want to leave separate for now for prototyping
377+ # but should combine the shared parts later.
378+
379+ # TOOD: important differenence, this does not roll, will need to test when new spikes are added...
380+
381+ # TODO: try out logarithmic scaling as some neurons fire too much...
382+
383+
384+
357385def run_alignment_estimation (
358- all_session_hists , spatial_bin_centers , rigid , robust = False
386+ all_session_hists , spatial_bin_centers , rigid , num_nonrigid_bins , robust = False
359387):
360388 """
361389 """
390+ # TODO: figure out best way to represent this, should probably be
391+ # suffix _list instead of prefixed all_ for consistency
362392 if isinstance (all_session_hists , list ):
363- all_session_hists = np .array (all_session_hists ) # TODO: figure out best way to represent this, should probably be suffix _list instead of prefixed all_ for consistency
393+ all_session_hists = np .array (all_session_hists )
364394
365395 num_bins = spatial_bin_centers .size
366396 num_sessions = all_session_hists .shape [0 ]
367397
398+ # TODO: rename
368399 hist_array = _compute_rigid_hist_crosscorr (
369400 num_sessions , num_bins , all_session_hists , robust
370- ) # TODO: rename
401+ )
371402
372403 optimal_shift_indices = - np .mean (hist_array , axis = 0 )[:, np .newaxis ]
373- # (2, 1)
404+
405+ # First, perform the rigid alignment.
406+
374407 if rigid :
375- # TODO: this just shifts everything to the center. It would be (better?)
376- # to optmize so all shifts are about the same .
408+ # TODO: used to get window center, for now just get them from the spatial bin
409+ # centers and use no margin, which was applied earlier. Same below .
377410 non_rigid_windows , non_rigid_window_centers = get_spatial_windows (
378411 spatial_bin_centers ,
379- # TODO: used to get window center, for now just get them from the spatial bin centers and use no margin, which was applied earlier
380412 spatial_bin_centers ,
381413 rigid = True ,
382- win_shape = "gaussian" , # rect
383- win_step_um = None , # TODO: expose! CHECK THIS!
384- # win_scale_um=win_scale_um,
414+ win_shape = "gaussian" ,
415+ win_step_um = None ,
385416 win_margin_um = 0 ,
386- # zero_threshold=None,
417+ # win_scale_um=win_scale_um,
418+ # zero_threshold=None,
387419 )
388420
389- return optimal_shift_indices , non_rigid_window_centers # TODO: rename rigid, also this is weird to pass back bins in the rigid case
390-
391- # TODO: this is basically a re-implimentation of the nonrigid part
392- # of iterative template. Want to leave separate for now for prototyping
393- # but should combine the shared parts later.
421+ # TODO: rename rigid, also this is weird to pass back bins in the rigid case
422+ return optimal_shift_indices , non_rigid_window_centers
394423
395- num_steps = 7
396- win_step_um = (np .max (spatial_bin_centers ) - np .min (spatial_bin_centers )) / num_steps
424+ win_step_um = (np .max (spatial_bin_centers ) - np .min (spatial_bin_centers )) / num_nonrigid_bins
397425
398426 non_rigid_windows , non_rigid_window_centers = get_spatial_windows (
399- spatial_bin_centers , # TODO: used to get window center, for now just get them from the spatial bin centers and use no margin, which was applied earlier
427+ spatial_bin_centers ,
400428 spatial_bin_centers ,
401429 rigid = False ,
402- win_shape = "gaussian" , # rect
430+ win_shape = "gaussian" ,
403431 win_step_um = win_step_um , # TODO: expose!
404- # win_scale_um=win_scale_um,
405432 win_margin_um = 0 ,
406- # zero_threshold=None,
433+ # win_scale_um=win_scale_um,
434+ # zero_threshold=None,
407435 )
408- # TODO: I wonder if it is better to estimate the hitsogram with finer bin size
409- # than try and interpolate the xcorr. What about smoothing the activity histograms directly?
410-
411- # TOOD: the iterative_template seems a little different to the interpolation
412- # of nonrigid segments that is described in the NP2.0 paper. Oh, the KS
413- # implementation is different to that described in the paper/ where is the
414- # Akima spline interpolation?
415-
416- # TODO: make sure that the num bins will always align.
417- # Apply the linear shifts, don't roll, as we don't want circular (why would the top of the probe appear at the bottom?)
418- # They roll the windowed version that is zeros, but here we want all done up front to simplify later code
419436
420- import matplotlib .pyplot as plt
421-
422- # TODO: for recursive version, shift cannot be larger than previous shift!
437+ # Shift the histograms according to the rigid shift
423438 shifted_histograms = np .zeros_like (all_session_hists )
424439 for i in range (all_session_hists .shape [0 ]):
425440
@@ -431,20 +446,39 @@ def run_alignment_estimation(
431446 cut_padded_hist = padded_hist [abs_shift :] if shift > 0 else padded_hist [:- abs_shift ]
432447 shifted_histograms [i , :] = cut_padded_hist
433448
449+ # For each nonrigid window, compute the shift
434450 non_rigid_shifts = np .zeros ((num_sessions , non_rigid_windows .shape [0 ]))
435- for i , window in enumerate (non_rigid_windows ): # TODO: use same name
451+ for i , window in enumerate (non_rigid_windows ):
436452
437453 windowed_histogram = shifted_histograms * window
438454
455+ # NOTE: this method just xcorr the entire window,
456+ # does not provide subset of samples like kilosort_like
439457 window_hist_array = _compute_rigid_hist_crosscorr (
440- num_sessions , num_bins , windowed_histogram , robust = False # this method just xcorr the entire window does not provide subset of samples like kilosort_like
458+ num_sessions , num_bins , windowed_histogram , robust = False
441459 )
442460 non_rigid_shifts [:, i ] = - np .mean (window_hist_array , axis = 0 )
443461
444- return optimal_shift_indices + non_rigid_shifts , non_rigid_window_centers # TODO: tidy up
462+ akima = False # TODO: decide whether to keep, factor to own function
463+ if akima :
464+ from scipy .interpolate import Akima1DInterpolator
465+ x = win_step_um * np .arange (non_rigid_windows .shape [0 ])
466+ xs = spatial_bin_centers
467+
468+ new_nonrigid_shifts = np .zeros ((non_rigid_shifts .shape [0 ], num_bins ))
469+ for ses_idx in range (non_rigid_shifts .shape [0 ]):
470+
471+ y = non_rigid_shifts [ses_idx ]
472+ y_new = Akima1DInterpolator (x , y , method = "akima" , extrapolate = True )(xs ) # requires scipy 14
473+ new_nonrigid_shifts [ses_idx , :] = y_new
474+
475+ shifts = optimal_shift_indices + new_nonrigid_shifts
476+ non_rigid_window_centers = spatial_bin_centers
477+ else :
478+ shifts = optimal_shift_indices + non_rigid_shifts
479+
480+ return shifts , non_rigid_window_centers
445481
446- # TODO: what about the Akima Spline
447- # TODO: try out logarithmic scaling as some neurons fire too much...
448482
449483def _compute_rigid_hist_crosscorr (num_sessions , num_bins , all_session_hists , robust = False ):
450484 """"""
0 commit comments