|
9 | 9 | * ComputeNoiseLevels which is very convenient to have |
10 | 10 | """ |
11 | 11 |
|
| 12 | +import warnings |
12 | 13 | import numpy as np |
13 | 14 |
|
14 | 15 | from .sortinganalyzer import AnalyzerExtension, register_result_extension |
@@ -92,6 +93,11 @@ def _merge_extension_data( |
92 | 93 | new_data["random_spikes_indices"] = np.flatnonzero(selected_mask[keep_mask]) |
93 | 94 | return new_data |
94 | 95 |
|
| 96 | + def _split_extension_data(self, split_units, new_unit_ids, new_sorting_analyzer, verbose=False, **job_kwargs): |
| 97 | + new_data = dict() |
| 98 | + new_data["random_spikes_indices"] = self.data["random_spikes_indices"].copy() |
| 99 | + return new_data |
| 100 | + |
95 | 101 | def _get_data(self): |
96 | 102 | return self.data["random_spikes_indices"] |
97 | 103 |
|
@@ -243,8 +249,6 @@ def _select_extension_data(self, unit_ids): |
243 | 249 | def _merge_extension_data( |
244 | 250 | self, merge_unit_groups, new_unit_ids, new_sorting_analyzer, keep_mask=None, verbose=False, **job_kwargs |
245 | 251 | ): |
246 | | - new_data = dict() |
247 | | - |
248 | 252 | waveforms = self.data["waveforms"] |
249 | 253 | some_spikes = self.sorting_analyzer.get_extension("random_spikes").get_random_spikes() |
250 | 254 | if keep_mask is not None: |
@@ -275,6 +279,11 @@ def _merge_extension_data( |
275 | 279 |
|
276 | 280 | return dict(waveforms=waveforms) |
277 | 281 |
|
| 282 | + def _split_extension_data(self, split_units, new_unit_ids, new_sorting_analyzer, verbose=False, **job_kwargs): |
| 283 | + # splitting only affects random spikes, not waveforms |
| 284 | + new_data = dict(waveforms=self.data["waveforms"].copy()) |
| 285 | + return new_data |
| 286 | + |
278 | 287 | def get_waveforms_one_unit(self, unit_id, force_dense: bool = False): |
279 | 288 | """ |
280 | 289 | Returns the waveforms of a unit id. |
@@ -554,6 +563,49 @@ def _merge_extension_data( |
554 | 563 |
|
555 | 564 | return new_data |
556 | 565 |
|
| 566 | + def _split_extension_data(self, split_units, new_unit_ids, new_sorting_analyzer, verbose=False, **job_kwargs): |
| 567 | + if not new_sorting_analyzer.has_extension("waveforms"): |
| 568 | + warnings.warn( |
| 569 | + "Splitting templates without the 'waveforms' extension will simply copy the template of the unit that " |
| 570 | + "was split to the new split units. This is not recommended and may lead to incorrect results. It is " |
| 571 | + "recommended to compute the 'waveforms' extension before splitting, or to use 'hard' splitting mode.", |
| 572 | + ) |
| 573 | + new_data = dict() |
| 574 | + for operator, arr in self.data.items(): |
| 575 | + # we first copy the unsplit units |
| 576 | + new_array = np.zeros((len(new_sorting_analyzer.unit_ids), arr.shape[1], arr.shape[2]), dtype=arr.dtype) |
| 577 | + new_analyzer_unit_ids = list(new_sorting_analyzer.unit_ids) |
| 578 | + unsplit_unit_ids = [unit_id for unit_id in self.sorting_analyzer.unit_ids if unit_id not in split_units] |
| 579 | + new_indices = np.array([new_analyzer_unit_ids.index(unit_id) for unit_id in unsplit_unit_ids]) |
| 580 | + old_indices = self.sorting_analyzer.sorting.ids_to_indices(unsplit_unit_ids) |
| 581 | + new_array[new_indices, ...] = arr[old_indices, ...] |
| 582 | + |
| 583 | + for split_unit_id, new_splits in zip(split_units, new_unit_ids): |
| 584 | + if new_sorting_analyzer.has_extension("waveforms"): |
| 585 | + for new_unit_id in new_splits: |
| 586 | + split_unit_index = new_sorting_analyzer.sorting.id_to_index(new_unit_id) |
| 587 | + wfs = new_sorting_analyzer.get_extension("waveforms").get_waveforms_one_unit( |
| 588 | + new_unit_id, force_dense=True |
| 589 | + ) |
| 590 | + |
| 591 | + if operator == "average": |
| 592 | + arr = np.average(wfs, axis=0) |
| 593 | + elif operator == "std": |
| 594 | + arr = np.std(wfs, axis=0) |
| 595 | + elif operator == "median": |
| 596 | + arr = np.median(wfs, axis=0) |
| 597 | + elif "percentile" in operator: |
| 598 | + _, percentile = operator.splot("_") |
| 599 | + arr = np.percentile(wfs, float(percentile), axis=0) |
| 600 | + new_array[split_unit_index, ...] = arr |
| 601 | + else: |
| 602 | + split_unit_index = self.sorting_analyzer.sorting.id_to_index(split_unit_id) |
| 603 | + old_template = arr[split_unit_index, ...] |
| 604 | + new_indices = new_sorting_analyzer.sorting.ids_to_indices(new_splits) |
| 605 | + new_array[new_indices, ...] = np.tile(old_template, (len(new_splits), 1, 1)) |
| 606 | + new_data[operator] = new_array |
| 607 | + return new_data |
| 608 | + |
557 | 609 | def _get_data(self, operator="average", percentile=None, outputs="numpy"): |
558 | 610 | if operator != "percentile": |
559 | 611 | key = operator |
@@ -646,7 +698,7 @@ def get_templates(self, unit_ids=None, operator="average", percentile=None, save |
646 | 698 | channel_ids=self.sorting_analyzer.channel_ids, |
647 | 699 | unit_ids=unit_ids, |
648 | 700 | probe=self.sorting_analyzer.get_probe(), |
649 | | - is_scaled=self.sorting_analyzer.return_in_uV, |
| 701 | + is_in_uV=self.sorting_analyzer.return_in_uV, |
650 | 702 | ) |
651 | 703 | else: |
652 | 704 | raise ValueError("`outputs` must be 'numpy' or 'Templates'") |
@@ -727,6 +779,10 @@ def _merge_extension_data( |
727 | 779 | # this does not depend on units |
728 | 780 | return self.data.copy() |
729 | 781 |
|
| 782 | + def _split_extension_data(self, split_units, new_unit_ids, new_sorting_analyzer, verbose=False, **job_kwargs): |
| 783 | + # this does not depend on units |
| 784 | + return self.data.copy() |
| 785 | + |
730 | 786 | def _run(self, verbose=False, **job_kwargs): |
731 | 787 | self.data["noise_levels"] = get_noise_levels( |
732 | 788 | self.sorting_analyzer.recording, |
|
0 commit comments