19
19
# -----------------------------------------------------------------------------
20
20
21
21
# 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 ):
23
23
"""
24
24
TODO: assumes 1-segment recording
25
25
"""
@@ -41,11 +41,14 @@ def get_entire_session_hist(recording, peaks, peak_locations, spatial_bin_edges)
41
41
42
42
spatial_centers = get_bin_centers (spatial_bin_edges )
43
43
44
+ if log_scale :
45
+ entire_session_hist = np .log10 (1 + entire_session_hist )
46
+
44
47
return entire_session_hist , temporal_bin_edges , spatial_centers
45
48
46
49
47
50
def 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
49
52
):
50
53
chunked_session_hist , temporal_bin_edges , _ = \
51
54
make_2d_motion_histogram (
@@ -66,6 +69,9 @@ def get_chunked_histogram( # TODO: this function might be pointless
66
69
bin_times = np .diff (temporal_bin_edges )[:, np .newaxis ]
67
70
chunked_session_hist /= bin_times
68
71
72
+ if log_scale :
73
+ chunked_session_hist = np .log10 (1 + chunked_session_hist )
74
+
69
75
return chunked_session_hist , temporal_centers , spatial_centers
70
76
71
77
# -----------------------------------------------------------------------------
@@ -354,72 +360,81 @@ def run_kilosort_like_rigid_registration(all_hists, non_rigid_windows):
354
360
return - optimal_shift_indices # TODO: these are reversed at this stage
355
361
356
362
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
+
357
385
def 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
359
387
):
360
388
"""
361
389
"""
390
+ # TODO: figure out best way to represent this, should probably be
391
+ # suffix _list instead of prefixed all_ for consistency
362
392
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 )
364
394
365
395
num_bins = spatial_bin_centers .size
366
396
num_sessions = all_session_hists .shape [0 ]
367
397
398
+ # TODO: rename
368
399
hist_array = _compute_rigid_hist_crosscorr (
369
400
num_sessions , num_bins , all_session_hists , robust
370
- ) # TODO: rename
401
+ )
371
402
372
403
optimal_shift_indices = - np .mean (hist_array , axis = 0 )[:, np .newaxis ]
373
- # (2, 1)
404
+
405
+ # First, perform the rigid alignment.
406
+
374
407
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 .
377
410
non_rigid_windows , non_rigid_window_centers = get_spatial_windows (
378
411
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
380
412
spatial_bin_centers ,
381
413
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 ,
385
416
win_margin_um = 0 ,
386
- # zero_threshold=None,
417
+ # win_scale_um=win_scale_um,
418
+ # zero_threshold=None,
387
419
)
388
420
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
394
423
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
397
425
398
426
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 ,
400
428
spatial_bin_centers ,
401
429
rigid = False ,
402
- win_shape = "gaussian" , # rect
430
+ win_shape = "gaussian" ,
403
431
win_step_um = win_step_um , # TODO: expose!
404
- # win_scale_um=win_scale_um,
405
432
win_margin_um = 0 ,
406
- # zero_threshold=None,
433
+ # win_scale_um=win_scale_um,
434
+ # zero_threshold=None,
407
435
)
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
419
436
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
423
438
shifted_histograms = np .zeros_like (all_session_hists )
424
439
for i in range (all_session_hists .shape [0 ]):
425
440
@@ -431,20 +446,39 @@ def run_alignment_estimation(
431
446
cut_padded_hist = padded_hist [abs_shift :] if shift > 0 else padded_hist [:- abs_shift ]
432
447
shifted_histograms [i , :] = cut_padded_hist
433
448
449
+ # For each nonrigid window, compute the shift
434
450
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 ):
436
452
437
453
windowed_histogram = shifted_histograms * window
438
454
455
+ # NOTE: this method just xcorr the entire window,
456
+ # does not provide subset of samples like kilosort_like
439
457
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
441
459
)
442
460
non_rigid_shifts [:, i ] = - np .mean (window_hist_array , axis = 0 )
443
461
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
445
481
446
- # TODO: what about the Akima Spline
447
- # TODO: try out logarithmic scaling as some neurons fire too much...
448
482
449
483
def _compute_rigid_hist_crosscorr (num_sessions , num_bins , all_session_hists , robust = False ):
450
484
""""""
0 commit comments