figpack 0.2.16__py3-none-any.whl → 0.2.17__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. figpack/__init__.py +2 -3
  2. figpack/core/__init__.py +2 -2
  3. figpack/core/_bundle_utils.py +56 -18
  4. figpack/core/extension_view.py +7 -25
  5. figpack/core/figpack_extension.py +0 -71
  6. figpack/figpack-figure-dist/assets/index-DBwmtEpB.js +91 -0
  7. figpack/figpack-figure-dist/assets/{index-D9a3K6eW.css → index-DHWczh-Q.css} +1 -1
  8. figpack/figpack-figure-dist/index.html +2 -2
  9. figpack/views/PlotlyExtension/PlotlyExtension.py +4 -50
  10. figpack/views/PlotlyExtension/_plotly_extension.py +46 -0
  11. figpack/views/PlotlyExtension/plotly_view.js +84 -80
  12. figpack/views/__init__.py +1 -0
  13. {figpack-0.2.16.dist-info → figpack-0.2.17.dist-info}/METADATA +1 -1
  14. figpack-0.2.17.dist-info/RECORD +43 -0
  15. figpack/figpack-figure-dist/assets/index-DtOnN02w.js +0 -846
  16. figpack/franklab/__init__.py +0 -5
  17. figpack/franklab/views/TrackAnimation.py +0 -154
  18. figpack/franklab/views/__init__.py +0 -9
  19. figpack/spike_sorting/__init__.py +0 -5
  20. figpack/spike_sorting/views/AutocorrelogramItem.py +0 -32
  21. figpack/spike_sorting/views/Autocorrelograms.py +0 -116
  22. figpack/spike_sorting/views/AverageWaveforms.py +0 -146
  23. figpack/spike_sorting/views/CrossCorrelogramItem.py +0 -35
  24. figpack/spike_sorting/views/CrossCorrelograms.py +0 -131
  25. figpack/spike_sorting/views/RasterPlot.py +0 -284
  26. figpack/spike_sorting/views/RasterPlotItem.py +0 -28
  27. figpack/spike_sorting/views/SpikeAmplitudes.py +0 -364
  28. figpack/spike_sorting/views/SpikeAmplitudesItem.py +0 -38
  29. figpack/spike_sorting/views/UnitMetricsGraph.py +0 -127
  30. figpack/spike_sorting/views/UnitSimilarityScore.py +0 -40
  31. figpack/spike_sorting/views/UnitsTable.py +0 -82
  32. figpack/spike_sorting/views/UnitsTableColumn.py +0 -40
  33. figpack/spike_sorting/views/UnitsTableRow.py +0 -36
  34. figpack/spike_sorting/views/__init__.py +0 -41
  35. figpack-0.2.16.dist-info/RECORD +0 -61
  36. {figpack-0.2.16.dist-info → figpack-0.2.17.dist-info}/WHEEL +0 -0
  37. {figpack-0.2.16.dist-info → figpack-0.2.17.dist-info}/entry_points.txt +0 -0
  38. {figpack-0.2.16.dist-info → figpack-0.2.17.dist-info}/licenses/LICENSE +0 -0
  39. {figpack-0.2.16.dist-info → figpack-0.2.17.dist-info}/top_level.txt +0 -0
@@ -1,5 +0,0 @@
1
- """
2
- Franklab views for figpack
3
- """
4
-
5
- from . import views
@@ -1,154 +0,0 @@
1
- """
2
- TrackAnimation view for figpack - displays animated tracking data
3
- """
4
-
5
- from typing import Optional
6
-
7
- import numpy as np
8
- import zarr
9
-
10
- from ...core.figpack_view import FigpackView
11
- from ...core.zarr import Group
12
-
13
-
14
- class TrackAnimation(FigpackView):
15
- """
16
- A track animation visualization component for displaying animal tracking data
17
- """
18
-
19
- def __init__(
20
- self,
21
- *,
22
- bin_height: float,
23
- bin_width: float,
24
- frame_bounds: np.ndarray,
25
- locations: np.ndarray,
26
- values: np.ndarray,
27
- xcount: int,
28
- ycount: int,
29
- xmin: float,
30
- ymin: float,
31
- head_direction: np.ndarray,
32
- positions: np.ndarray,
33
- timestamps: np.ndarray,
34
- track_bin_corners: np.ndarray,
35
- sampling_frequency_hz: float,
36
- timestamp_start: float,
37
- total_recording_frame_length: int,
38
- track_bin_height: float,
39
- track_bin_width: float,
40
- xmax: float,
41
- ymax: float,
42
- ):
43
- """
44
- Initialize a TrackAnimation view
45
-
46
- Args:
47
- bin_height: Height of spatial bins
48
- bin_width: Width of spatial bins
49
- frame_bounds: Array of frame boundaries
50
- locations: Array of spatial locations
51
- values: Array of values at each location
52
- xcount: Number of bins in x direction
53
- ycount: Number of bins in y direction
54
- xmin: Minimum x coordinate
55
- ymin: Minimum y coordinate
56
- head_direction: Array of head direction angles
57
- positions: Array of position coordinates (2D)
58
- timestamps: Array of timestamps
59
- track_bin_corners: Array of track bin corner coordinates
60
- sampling_frequency_hz: Sampling frequency in Hz
61
- timestamp_start: Start timestamp
62
- total_recording_frame_length: Total number of frames
63
- track_bin_height: Height of track bins
64
- track_bin_width: Width of track bins
65
- xmax: Maximum x coordinate
66
- ymax: Maximum y coordinate
67
- """
68
- # Validate input arrays
69
- assert isinstance(
70
- frame_bounds, np.ndarray
71
- ), "frame_bounds must be a numpy array"
72
- assert isinstance(locations, np.ndarray), "locations must be a numpy array"
73
- assert isinstance(values, np.ndarray), "values must be a numpy array"
74
- assert isinstance(
75
- head_direction, np.ndarray
76
- ), "head_direction must be a numpy array"
77
- assert isinstance(positions, np.ndarray), "positions must be a numpy array"
78
- assert isinstance(timestamps, np.ndarray), "timestamps must be a numpy array"
79
- assert isinstance(
80
- track_bin_corners, np.ndarray
81
- ), "track_bin_corners must be a numpy array"
82
-
83
- assert len(locations) == len(
84
- values
85
- ), "locations and values must have same length"
86
- assert len(head_direction) == len(
87
- timestamps
88
- ), "head_direction and timestamps must have same length"
89
- assert positions.shape[1] == len(
90
- timestamps
91
- ), "positions second dimension must match timestamps length"
92
- assert positions.shape[0] == 2, "positions must have shape (2, N)"
93
-
94
- # Store spatial binning parameters
95
- self.bin_height = bin_height
96
- self.bin_width = bin_width
97
- self.xcount = xcount
98
- self.ycount = ycount
99
- self.xmin = xmin
100
- self.ymin = ymin
101
- self.xmax = xmax
102
- self.ymax = ymax
103
-
104
- # Store arrays
105
- self.frame_bounds = frame_bounds
106
- self.locations = locations
107
- self.values = values
108
- self.head_direction = head_direction
109
- self.positions = positions
110
- self.timestamps = timestamps
111
- self.track_bin_corners = track_bin_corners
112
-
113
- # Store metadata
114
- self.sampling_frequency_hz = sampling_frequency_hz
115
- self.timestamp_start = timestamp_start
116
- self.total_recording_frame_length = total_recording_frame_length
117
- self.track_bin_height = track_bin_height
118
- self.track_bin_width = track_bin_width
119
-
120
- def _write_to_zarr_group(self, group: Group) -> None:
121
- """
122
- Write the track animation data to a Zarr group
123
-
124
- Args:
125
- group: Zarr group to write data into
126
- """
127
- # Set view type
128
- group.attrs["view_type"] = "TrackAnimation"
129
-
130
- # Store spatial binning parameters
131
- group.attrs["bin_height"] = self.bin_height
132
- group.attrs["bin_width"] = self.bin_width
133
- group.attrs["xcount"] = self.xcount
134
- group.attrs["ycount"] = self.ycount
135
- group.attrs["xmin"] = self.xmin
136
- group.attrs["ymin"] = self.ymin
137
- group.attrs["xmax"] = self.xmax
138
- group.attrs["ymax"] = self.ymax
139
-
140
- # Store metadata
141
- group.attrs["sampling_frequency_hz"] = self.sampling_frequency_hz
142
- group.attrs["timestamp_start"] = self.timestamp_start
143
- group.attrs["total_recording_frame_length"] = self.total_recording_frame_length
144
- group.attrs["track_bin_height"] = self.track_bin_height
145
- group.attrs["track_bin_width"] = self.track_bin_width
146
-
147
- # Store arrays as datasets
148
- group.create_dataset("frame_bounds", data=self.frame_bounds)
149
- group.create_dataset("locations", data=self.locations)
150
- group.create_dataset("values", data=self.values)
151
- group.create_dataset("head_direction", data=self.head_direction)
152
- group.create_dataset("positions", data=self.positions)
153
- group.create_dataset("timestamps", data=self.timestamps)
154
- group.create_dataset("track_bin_corners", data=self.track_bin_corners)
@@ -1,9 +0,0 @@
1
- """
2
- Franklab views for figpack
3
- """
4
-
5
- from .TrackAnimation import TrackAnimation
6
-
7
- __all__ = [
8
- "TrackAnimation",
9
- ]
@@ -1,5 +0,0 @@
1
- """
2
- Spike sorting views for figpack
3
- """
4
-
5
- from . import views
@@ -1,32 +0,0 @@
1
- """
2
- AutocorrelogramItem for spike sorting views
3
- """
4
-
5
- from typing import Union
6
-
7
- import numpy as np
8
-
9
-
10
- class AutocorrelogramItem:
11
- """
12
- Represents a single autocorrelogram for a unit
13
- """
14
-
15
- def __init__(
16
- self,
17
- *,
18
- unit_id: Union[str, int],
19
- bin_edges_sec: np.ndarray,
20
- bin_counts: np.ndarray,
21
- ):
22
- """
23
- Initialize an AutocorrelogramItem
24
-
25
- Args:
26
- unit_id: Identifier for the unit
27
- bin_edges_sec: Array of bin edges in seconds
28
- bin_counts: Array of bin counts
29
- """
30
- self.unit_id = unit_id
31
- self.bin_edges_sec = np.array(bin_edges_sec, dtype=np.float32)
32
- self.bin_counts = np.array(bin_counts, dtype=np.int32)
@@ -1,116 +0,0 @@
1
- """
2
- Autocorrelograms view for figpack - displays multiple autocorrelograms
3
- """
4
-
5
- from typing import List
6
-
7
- import numpy as np
8
-
9
- from ...core.figpack_view import FigpackView
10
- from ...core.zarr import Group
11
- from .AutocorrelogramItem import AutocorrelogramItem
12
-
13
-
14
- class Autocorrelograms(FigpackView):
15
- """
16
- A view that displays multiple autocorrelograms for spike sorting analysis
17
- """
18
-
19
- def __init__(
20
- self,
21
- *,
22
- autocorrelograms: List[AutocorrelogramItem],
23
- ):
24
- """
25
- Initialize an Autocorrelograms view
26
-
27
- Args:
28
- autocorrelograms: List of AutocorrelogramItem objects
29
- """
30
- self.autocorrelograms = autocorrelograms
31
-
32
- @staticmethod
33
- def from_sorting(sorting):
34
- import spikeinterface as si
35
- import spikeinterface.widgets as sw
36
-
37
- assert isinstance(sorting, si.BaseSorting), "Input must be a BaseSorting object"
38
- W = sw.plot_autocorrelograms(sorting)
39
- return Autocorrelograms.from_spikeinterface_widget(W)
40
-
41
- @staticmethod
42
- def from_spikeinterface_widget(W):
43
- from spikeinterface.widgets.base import to_attr
44
- from spikeinterface.widgets.utils_sortingview import make_serializable
45
-
46
- from .AutocorrelogramItem import AutocorrelogramItem
47
-
48
- data_plot = W.data_plot
49
-
50
- dp = to_attr(data_plot)
51
-
52
- unit_ids = make_serializable(dp.unit_ids)
53
-
54
- ac_items = []
55
- for i in range(len(unit_ids)):
56
- for j in range(i, len(unit_ids)):
57
- if i == j:
58
- ac_items.append(
59
- AutocorrelogramItem(
60
- unit_id=unit_ids[i],
61
- bin_edges_sec=(dp.bins / 1000.0).astype("float32"),
62
- bin_counts=dp.correlograms[i, j].astype("int32"),
63
- )
64
- )
65
-
66
- view = Autocorrelograms(autocorrelograms=ac_items)
67
- return view
68
-
69
- def _write_to_zarr_group(self, group: Group) -> None:
70
- """
71
- Write the Autocorrelograms data to a Zarr group
72
-
73
- Args:
74
- group: Zarr group to write data into
75
- """
76
- # Set the view type
77
- group.attrs["view_type"] = "Autocorrelograms"
78
-
79
- # Store the number of autocorrelograms
80
- num_autocorrelograms = len(self.autocorrelograms)
81
- group.attrs["num_autocorrelograms"] = num_autocorrelograms
82
-
83
- if num_autocorrelograms == 0:
84
- return
85
-
86
- # Get dimensions from first autocorrelogram
87
- num_bins = len(self.autocorrelograms[0].bin_counts)
88
-
89
- # Store bin edges (same for all autocorrelograms)
90
- group.create_dataset(
91
- "bin_edges_sec",
92
- data=self.autocorrelograms[0].bin_edges_sec,
93
- )
94
-
95
- # Create 2D array for all bin counts
96
- bin_counts = np.zeros((num_autocorrelograms, num_bins), dtype=np.int32)
97
-
98
- # Store metadata for each autocorrelogram and populate bin counts array
99
- autocorrelogram_metadata = []
100
- for i, autocorr in enumerate(self.autocorrelograms):
101
- metadata = {
102
- "unit_id": str(autocorr.unit_id),
103
- "index": i, # Store index to map to bin_counts array
104
- "num_bins": num_bins,
105
- }
106
- autocorrelogram_metadata.append(metadata)
107
- bin_counts[i] = autocorr.bin_counts
108
-
109
- # Store the bin counts as a single 2D dataset
110
- group.create_dataset(
111
- "bin_counts",
112
- data=bin_counts,
113
- )
114
-
115
- # Store the autocorrelogram metadata
116
- group.attrs["autocorrelograms"] = autocorrelogram_metadata
@@ -1,146 +0,0 @@
1
- """
2
- AverageWaveforms view for figpack - displays multiple average waveforms
3
- """
4
-
5
- from typing import List, Optional, Union
6
-
7
- import numpy as np
8
- import zarr
9
-
10
- from ...core.figpack_view import FigpackView
11
- from ...core.zarr import Group
12
-
13
-
14
- class AverageWaveformItem:
15
- """
16
- Represents a single average waveform for a unit
17
- """
18
-
19
- def __init__(
20
- self,
21
- *,
22
- unit_id: Union[str, int],
23
- channel_ids: List[Union[str, int]],
24
- waveform: np.ndarray,
25
- waveform_std_dev: Optional[np.ndarray] = None,
26
- waveform_percentiles: Optional[List[np.ndarray]] = None,
27
- ):
28
- """
29
- Initialize an AverageWaveformItem
30
-
31
- Args:
32
- unit_id: Identifier for the unit
33
- channel_ids: List of channel identifiers
34
- waveform: 2D numpy array representing the average waveform (num_samples x num_channels)
35
- waveform_std_dev: Optional 2D numpy array representing the standard deviation of the waveform
36
- waveform_percentiles: Optional list of 2D numpy arrays representing percentiles of the waveform
37
- """
38
- self.unit_id = unit_id
39
- self.channel_ids = channel_ids
40
- self.waveform = np.array(waveform, dtype=np.float32)
41
- self.waveform_std_dev = (
42
- np.array(waveform_std_dev, dtype=np.float32)
43
- if waveform_std_dev is not None
44
- else None
45
- )
46
- if waveform_percentiles is not None:
47
- self.waveform_percentiles = [
48
- np.array(p, dtype=np.float32) for p in waveform_percentiles
49
- ]
50
- else:
51
- self.waveform_percentiles = None
52
-
53
-
54
- class AverageWaveforms(FigpackView):
55
- """
56
- A view that displays multiple average waveforms for spike sorting analysis
57
- """
58
-
59
- def __init__(self, *, average_waveforms: List[AverageWaveformItem]):
60
- """
61
- Initialize an AverageWaveforms view
62
-
63
- Args:
64
- average_waveforms: List of AverageWaveformItem objects
65
- """
66
- self.average_waveforms = average_waveforms
67
-
68
- @staticmethod
69
- def from_sorting_analyzer(sorting_analyzer):
70
- sorting_analyzer.compute(
71
- ["random_spikes", "waveforms", "templates", "noise_levels"]
72
- )
73
- ext_templates = sorting_analyzer.get_extension("templates")
74
- # shape is num_units, num_samples, num_channels
75
- av_templates = ext_templates.get_data(operator="average")
76
-
77
- ext_noise_levels = sorting_analyzer.get_extension("noise_levels")
78
- noise_levels = ext_noise_levels.get_data()
79
-
80
- waveform_std_dev = np.zeros(
81
- (av_templates.shape[1], av_templates.shape[2]), dtype=np.float32
82
- )
83
- for i in range(av_templates.shape[2]):
84
- waveform_std_dev[:, i] = noise_levels[i]
85
-
86
- average_waveform_items = []
87
- for i, unit_id in enumerate(sorting_analyzer.unit_ids):
88
- waveform = av_templates[i]
89
- channel_ids = list(sorting_analyzer.recording.get_channel_ids())
90
- average_waveform_items.append(
91
- AverageWaveformItem(
92
- unit_id=unit_id,
93
- waveform=waveform,
94
- channel_ids=channel_ids,
95
- waveform_std_dev=waveform_std_dev,
96
- )
97
- )
98
- view = AverageWaveforms(average_waveforms=average_waveform_items)
99
- return view
100
-
101
- def _write_to_zarr_group(self, group: Group) -> None:
102
- """
103
- Write the AverageWaveforms data to a Zarr group
104
-
105
- Args:
106
- group: Zarr group to write data into
107
- """
108
- # Set the view type
109
- group.attrs["view_type"] = "AverageWaveforms"
110
-
111
- # Store the number of average waveforms
112
- group.attrs["num_average_waveforms"] = len(self.average_waveforms)
113
-
114
- # Store metadata for each average waveform
115
- average_waveform_metadata = []
116
- for i, waveform in enumerate(self.average_waveforms):
117
- waveform_name = f"waveform_{i}"
118
-
119
- # Store metadata
120
- metadata = {
121
- "name": waveform_name,
122
- "unit_id": str(waveform.unit_id),
123
- "channel_ids": [str(ch) for ch in waveform.channel_ids],
124
- }
125
- average_waveform_metadata.append(metadata)
126
-
127
- # Create arrays for this average waveform
128
- group.create_dataset(
129
- f"{waveform_name}/waveform",
130
- data=waveform.waveform,
131
- )
132
- if waveform.waveform_std_dev is not None:
133
- group.create_dataset(
134
- f"{waveform_name}/waveform_std_dev",
135
- data=waveform.waveform_std_dev,
136
- )
137
- if waveform.waveform_percentiles is not None:
138
- for j, p in enumerate(waveform.waveform_percentiles):
139
- group.create_dataset(
140
- f"{waveform_name}/waveform_percentile_{j}",
141
- data=p,
142
- dtype=p.dtype,
143
- )
144
-
145
- # Store the average waveform metadata
146
- group.attrs["average_waveforms"] = average_waveform_metadata
@@ -1,35 +0,0 @@
1
- """
2
- CrossCorrelogramItem for spike sorting views
3
- """
4
-
5
- from typing import Union
6
-
7
- import numpy as np
8
-
9
-
10
- class CrossCorrelogramItem:
11
- """
12
- Represents a single cross-correlogram between two units
13
- """
14
-
15
- def __init__(
16
- self,
17
- *,
18
- unit_id1: Union[str, int],
19
- unit_id2: Union[str, int],
20
- bin_edges_sec: np.ndarray,
21
- bin_counts: np.ndarray,
22
- ):
23
- """
24
- Initialize a CrossCorrelogramItem
25
-
26
- Args:
27
- unit_id1: Identifier for the first unit
28
- unit_id2: Identifier for the second unit
29
- bin_edges_sec: Array of bin edges in seconds
30
- bin_counts: Array of bin counts
31
- """
32
- self.unit_id1 = unit_id1
33
- self.unit_id2 = unit_id2
34
- self.bin_edges_sec = np.array(bin_edges_sec, dtype=np.float32)
35
- self.bin_counts = np.array(bin_counts, dtype=np.int32)
@@ -1,131 +0,0 @@
1
- """
2
- CrossCorrelograms view for figpack - displays multiple cross-correlograms
3
- """
4
-
5
- from typing import List, Optional
6
-
7
- import numpy as np
8
- import zarr
9
-
10
- from ...core.figpack_view import FigpackView
11
- from ...core.zarr import Group
12
- from .CrossCorrelogramItem import CrossCorrelogramItem
13
-
14
-
15
- class CrossCorrelograms(FigpackView):
16
- """
17
- A view that displays multiple cross-correlograms for spike sorting analysis
18
- """
19
-
20
- def __init__(
21
- self,
22
- *,
23
- cross_correlograms: List[CrossCorrelogramItem],
24
- hide_unit_selector: Optional[bool] = False,
25
- ):
26
- """
27
- Initialize a CrossCorrelograms view
28
-
29
- Args:
30
- cross_correlograms: List of CrossCorrelogramItem objects
31
- hide_unit_selector: Whether to hide the unit selector widget
32
- """
33
- self.cross_correlograms = cross_correlograms
34
- self.hide_unit_selector = hide_unit_selector
35
-
36
- @staticmethod
37
- def from_sorting(sorting):
38
- import spikeinterface as si
39
- import spikeinterface.widgets as sw
40
-
41
- assert isinstance(sorting, si.BaseSorting), "Input must be a BaseSorting object"
42
- W = sw.CrossCorrelogramsWidget(sorting)
43
- return CrossCorrelograms.from_spikeinterface_widget(W)
44
-
45
- @staticmethod
46
- def from_spikeinterface_widget(W):
47
- from spikeinterface.widgets.base import to_attr
48
- from spikeinterface.widgets.utils_sortingview import make_serializable
49
-
50
- from .CrossCorrelogramItem import CrossCorrelogramItem
51
-
52
- data_plot = W.data_plot
53
-
54
- dp = to_attr(data_plot)
55
-
56
- unit_ids = make_serializable(dp.unit_ids)
57
-
58
- if dp.similarity is not None:
59
- similarity = dp.similarity
60
- else:
61
- similarity = np.ones((len(unit_ids), len(unit_ids)))
62
-
63
- cc_items = []
64
- for i in range(len(unit_ids)):
65
- for j in range(i, len(unit_ids)):
66
- if similarity[i, j] >= dp.min_similarity_for_correlograms:
67
- cc_items.append(
68
- CrossCorrelogramItem(
69
- unit_id1=unit_ids[i],
70
- unit_id2=unit_ids[j],
71
- bin_edges_sec=(dp.bins / 1000.0).astype("float32"),
72
- bin_counts=dp.correlograms[i, j].astype("int32"),
73
- )
74
- )
75
-
76
- view = CrossCorrelograms(cross_correlograms=cc_items, hide_unit_selector=False)
77
- return view
78
-
79
- def _write_to_zarr_group(self, group: Group) -> None:
80
- """
81
- Write the CrossCorrelograms data to a Zarr group
82
-
83
- Args:
84
- group: Zarr group to write data into
85
- """
86
- # Set the view type
87
- group.attrs["view_type"] = "CrossCorrelograms"
88
-
89
- # Set view properties
90
- if self.hide_unit_selector is not None:
91
- group.attrs["hide_unit_selector"] = self.hide_unit_selector
92
-
93
- # Store the number of cross-correlograms
94
- num_cross_correlograms = len(self.cross_correlograms)
95
- group.attrs["num_cross_correlograms"] = num_cross_correlograms
96
-
97
- if num_cross_correlograms == 0:
98
- return
99
-
100
- # Get dimensions from first cross-correlogram
101
- num_bins = len(self.cross_correlograms[0].bin_counts)
102
-
103
- # Store bin edges (same for all cross-correlograms)
104
- group.create_dataset(
105
- "bin_edges_sec",
106
- data=self.cross_correlograms[0].bin_edges_sec,
107
- )
108
-
109
- # Create 2D array for all bin counts
110
- bin_counts = np.zeros((num_cross_correlograms, num_bins), dtype=np.int32)
111
-
112
- # Store metadata for each cross-correlogram and populate bin counts array
113
- cross_correlogram_metadata = []
114
- for i, cross_corr in enumerate(self.cross_correlograms):
115
- metadata = {
116
- "unit_id1": str(cross_corr.unit_id1),
117
- "unit_id2": str(cross_corr.unit_id2),
118
- "index": i, # Store index to map to bin_counts array
119
- "num_bins": num_bins,
120
- }
121
- cross_correlogram_metadata.append(metadata)
122
- bin_counts[i] = cross_corr.bin_counts
123
-
124
- # Store the bin counts as a single 2D dataset
125
- group.create_dataset(
126
- "bin_counts",
127
- data=bin_counts,
128
- )
129
-
130
- # Store the cross-correlogram metadata
131
- group.attrs["cross_correlograms"] = cross_correlogram_metadata