figpack 0.2.1__py3-none-any.whl → 0.2.3__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.
Potentially problematic release.
This version of figpack might be problematic. Click here for more details.
- figpack/__init__.py +1 -1
- figpack/cli.py +60 -3
- figpack/core/_server_manager.py +304 -0
- figpack/core/_show_view.py +128 -92
- figpack/core/_upload_bundle.py +19 -9
- figpack/core/figpack_view.py +34 -2
- figpack/figpack-gui-dist/assets/index-DUR9Dmwh.js +847 -0
- figpack/figpack-gui-dist/index.html +1 -1
- figpack/franklab/__init__.py +5 -0
- figpack/franklab/views/TrackAnimation.py +153 -0
- figpack/franklab/views/__init__.py +9 -0
- figpack/spike_sorting/views/AutocorrelogramItem.py +0 -10
- figpack/spike_sorting/views/Autocorrelograms.py +2 -0
- figpack/spike_sorting/views/AverageWaveforms.py +147 -0
- figpack/spike_sorting/views/CrossCorrelogramItem.py +0 -11
- figpack/spike_sorting/views/CrossCorrelograms.py +2 -0
- figpack/spike_sorting/views/SpikeAmplitudes.py +89 -0
- figpack/spike_sorting/views/SpikeAmplitudesItem.py +38 -0
- figpack/spike_sorting/views/__init__.py +6 -0
- {figpack-0.2.1.dist-info → figpack-0.2.3.dist-info}/METADATA +3 -2
- figpack-0.2.3.dist-info/RECORD +47 -0
- figpack/figpack-gui-dist/assets/index-BqYF6BN-.js +0 -846
- figpack-0.2.1.dist-info/RECORD +0 -40
- {figpack-0.2.1.dist-info → figpack-0.2.3.dist-info}/WHEEL +0 -0
- {figpack-0.2.1.dist-info → figpack-0.2.3.dist-info}/entry_points.txt +0 -0
- {figpack-0.2.1.dist-info → figpack-0.2.3.dist-info}/licenses/LICENSE +0 -0
- {figpack-0.2.1.dist-info → figpack-0.2.3.dist-info}/top_level.txt +0 -0
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<link rel="icon" type="image/png" href="./assets/neurosift-logo-CLsuwLMO.png" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<title>figpack figure</title>
|
|
8
|
-
<script type="module" crossorigin src="./assets/index-
|
|
8
|
+
<script type="module" crossorigin src="./assets/index-DUR9Dmwh.js"></script>
|
|
9
9
|
<link rel="stylesheet" crossorigin href="./assets/index-Cmae55E4.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
@@ -0,0 +1,153 @@
|
|
|
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
|
+
|
|
12
|
+
|
|
13
|
+
class TrackAnimation(FigpackView):
|
|
14
|
+
"""
|
|
15
|
+
A track animation visualization component for displaying animal tracking data
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def __init__(
|
|
19
|
+
self,
|
|
20
|
+
*,
|
|
21
|
+
bin_height: float,
|
|
22
|
+
bin_width: float,
|
|
23
|
+
frame_bounds: np.ndarray,
|
|
24
|
+
locations: np.ndarray,
|
|
25
|
+
values: np.ndarray,
|
|
26
|
+
xcount: int,
|
|
27
|
+
ycount: int,
|
|
28
|
+
xmin: float,
|
|
29
|
+
ymin: float,
|
|
30
|
+
head_direction: np.ndarray,
|
|
31
|
+
positions: np.ndarray,
|
|
32
|
+
timestamps: np.ndarray,
|
|
33
|
+
track_bin_corners: np.ndarray,
|
|
34
|
+
sampling_frequency_hz: float,
|
|
35
|
+
timestamp_start: float,
|
|
36
|
+
total_recording_frame_length: int,
|
|
37
|
+
track_bin_height: float,
|
|
38
|
+
track_bin_width: float,
|
|
39
|
+
xmax: float,
|
|
40
|
+
ymax: float,
|
|
41
|
+
):
|
|
42
|
+
"""
|
|
43
|
+
Initialize a TrackAnimation view
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
bin_height: Height of spatial bins
|
|
47
|
+
bin_width: Width of spatial bins
|
|
48
|
+
frame_bounds: Array of frame boundaries
|
|
49
|
+
locations: Array of spatial locations
|
|
50
|
+
values: Array of values at each location
|
|
51
|
+
xcount: Number of bins in x direction
|
|
52
|
+
ycount: Number of bins in y direction
|
|
53
|
+
xmin: Minimum x coordinate
|
|
54
|
+
ymin: Minimum y coordinate
|
|
55
|
+
head_direction: Array of head direction angles
|
|
56
|
+
positions: Array of position coordinates (2D)
|
|
57
|
+
timestamps: Array of timestamps
|
|
58
|
+
track_bin_corners: Array of track bin corner coordinates
|
|
59
|
+
sampling_frequency_hz: Sampling frequency in Hz
|
|
60
|
+
timestamp_start: Start timestamp
|
|
61
|
+
total_recording_frame_length: Total number of frames
|
|
62
|
+
track_bin_height: Height of track bins
|
|
63
|
+
track_bin_width: Width of track bins
|
|
64
|
+
xmax: Maximum x coordinate
|
|
65
|
+
ymax: Maximum y coordinate
|
|
66
|
+
"""
|
|
67
|
+
# Validate input arrays
|
|
68
|
+
assert isinstance(
|
|
69
|
+
frame_bounds, np.ndarray
|
|
70
|
+
), "frame_bounds must be a numpy array"
|
|
71
|
+
assert isinstance(locations, np.ndarray), "locations must be a numpy array"
|
|
72
|
+
assert isinstance(values, np.ndarray), "values must be a numpy array"
|
|
73
|
+
assert isinstance(
|
|
74
|
+
head_direction, np.ndarray
|
|
75
|
+
), "head_direction must be a numpy array"
|
|
76
|
+
assert isinstance(positions, np.ndarray), "positions must be a numpy array"
|
|
77
|
+
assert isinstance(timestamps, np.ndarray), "timestamps must be a numpy array"
|
|
78
|
+
assert isinstance(
|
|
79
|
+
track_bin_corners, np.ndarray
|
|
80
|
+
), "track_bin_corners must be a numpy array"
|
|
81
|
+
|
|
82
|
+
assert len(locations) == len(
|
|
83
|
+
values
|
|
84
|
+
), "locations and values must have same length"
|
|
85
|
+
assert len(head_direction) == len(
|
|
86
|
+
timestamps
|
|
87
|
+
), "head_direction and timestamps must have same length"
|
|
88
|
+
assert positions.shape[1] == len(
|
|
89
|
+
timestamps
|
|
90
|
+
), "positions second dimension must match timestamps length"
|
|
91
|
+
assert positions.shape[0] == 2, "positions must have shape (2, N)"
|
|
92
|
+
|
|
93
|
+
# Store spatial binning parameters
|
|
94
|
+
self.bin_height = bin_height
|
|
95
|
+
self.bin_width = bin_width
|
|
96
|
+
self.xcount = xcount
|
|
97
|
+
self.ycount = ycount
|
|
98
|
+
self.xmin = xmin
|
|
99
|
+
self.ymin = ymin
|
|
100
|
+
self.xmax = xmax
|
|
101
|
+
self.ymax = ymax
|
|
102
|
+
|
|
103
|
+
# Store arrays
|
|
104
|
+
self.frame_bounds = frame_bounds
|
|
105
|
+
self.locations = locations
|
|
106
|
+
self.values = values
|
|
107
|
+
self.head_direction = head_direction
|
|
108
|
+
self.positions = positions
|
|
109
|
+
self.timestamps = timestamps
|
|
110
|
+
self.track_bin_corners = track_bin_corners
|
|
111
|
+
|
|
112
|
+
# Store metadata
|
|
113
|
+
self.sampling_frequency_hz = sampling_frequency_hz
|
|
114
|
+
self.timestamp_start = timestamp_start
|
|
115
|
+
self.total_recording_frame_length = total_recording_frame_length
|
|
116
|
+
self.track_bin_height = track_bin_height
|
|
117
|
+
self.track_bin_width = track_bin_width
|
|
118
|
+
|
|
119
|
+
def _write_to_zarr_group(self, group: zarr.Group) -> None:
|
|
120
|
+
"""
|
|
121
|
+
Write the track animation data to a Zarr group
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
group: Zarr group to write data into
|
|
125
|
+
"""
|
|
126
|
+
# Set view type
|
|
127
|
+
group.attrs["view_type"] = "TrackAnimation"
|
|
128
|
+
|
|
129
|
+
# Store spatial binning parameters
|
|
130
|
+
group.attrs["bin_height"] = self.bin_height
|
|
131
|
+
group.attrs["bin_width"] = self.bin_width
|
|
132
|
+
group.attrs["xcount"] = self.xcount
|
|
133
|
+
group.attrs["ycount"] = self.ycount
|
|
134
|
+
group.attrs["xmin"] = self.xmin
|
|
135
|
+
group.attrs["ymin"] = self.ymin
|
|
136
|
+
group.attrs["xmax"] = self.xmax
|
|
137
|
+
group.attrs["ymax"] = self.ymax
|
|
138
|
+
|
|
139
|
+
# Store metadata
|
|
140
|
+
group.attrs["sampling_frequency_hz"] = self.sampling_frequency_hz
|
|
141
|
+
group.attrs["timestamp_start"] = self.timestamp_start
|
|
142
|
+
group.attrs["total_recording_frame_length"] = self.total_recording_frame_length
|
|
143
|
+
group.attrs["track_bin_height"] = self.track_bin_height
|
|
144
|
+
group.attrs["track_bin_width"] = self.track_bin_width
|
|
145
|
+
|
|
146
|
+
# Store arrays as datasets
|
|
147
|
+
group.create_dataset("frame_bounds", data=self.frame_bounds)
|
|
148
|
+
group.create_dataset("locations", data=self.locations)
|
|
149
|
+
group.create_dataset("values", data=self.values)
|
|
150
|
+
group.create_dataset("head_direction", data=self.head_direction)
|
|
151
|
+
group.create_dataset("positions", data=self.positions)
|
|
152
|
+
group.create_dataset("timestamps", data=self.timestamps)
|
|
153
|
+
group.create_dataset("track_bin_corners", data=self.track_bin_corners)
|
|
@@ -30,13 +30,3 @@ class AutocorrelogramItem:
|
|
|
30
30
|
self.unit_id = unit_id
|
|
31
31
|
self.bin_edges_sec = np.array(bin_edges_sec, dtype=np.float32)
|
|
32
32
|
self.bin_counts = np.array(bin_counts, dtype=np.int32)
|
|
33
|
-
|
|
34
|
-
def to_dict(self):
|
|
35
|
-
"""
|
|
36
|
-
Convert the autocorrelogram item to a dictionary representation
|
|
37
|
-
"""
|
|
38
|
-
return {
|
|
39
|
-
"unit_id": str(self.unit_id),
|
|
40
|
-
"bin_edges_sec": self.bin_edges_sec.tolist(),
|
|
41
|
-
"bin_counts": self.bin_counts.tolist(),
|
|
42
|
-
}
|
|
@@ -29,6 +29,7 @@ class Autocorrelograms(FigpackView):
|
|
|
29
29
|
"""
|
|
30
30
|
self.autocorrelograms = autocorrelograms
|
|
31
31
|
|
|
32
|
+
@staticmethod
|
|
32
33
|
def from_sorting(sorting):
|
|
33
34
|
import spikeinterface as si
|
|
34
35
|
import spikeinterface.widgets as sw
|
|
@@ -37,6 +38,7 @@ class Autocorrelograms(FigpackView):
|
|
|
37
38
|
W = sw.plot_autocorrelograms(sorting)
|
|
38
39
|
return Autocorrelograms.from_spikeinterface_widget(W)
|
|
39
40
|
|
|
41
|
+
@staticmethod
|
|
40
42
|
def from_spikeinterface_widget(W):
|
|
41
43
|
from spikeinterface.widgets.base import to_attr
|
|
42
44
|
from spikeinterface.widgets.utils_sortingview import make_serializable
|
|
@@ -0,0 +1,147 @@
|
|
|
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
|
+
|
|
12
|
+
|
|
13
|
+
class AverageWaveformItem:
|
|
14
|
+
"""
|
|
15
|
+
Represents a single average waveform for a unit
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def __init__(
|
|
19
|
+
self,
|
|
20
|
+
*,
|
|
21
|
+
unit_id: Union[str, int],
|
|
22
|
+
channel_ids: List[Union[str, int]],
|
|
23
|
+
waveform: np.ndarray,
|
|
24
|
+
waveform_std_dev: Optional[np.ndarray] = None,
|
|
25
|
+
waveform_percentiles: Optional[List[np.ndarray]] = None,
|
|
26
|
+
):
|
|
27
|
+
"""
|
|
28
|
+
Initialize an AverageWaveformItem
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
unit_id: Identifier for the unit
|
|
32
|
+
channel_ids: List of channel identifiers
|
|
33
|
+
waveform: 2D numpy array representing the average waveform (num_samples x num_channels)
|
|
34
|
+
waveform_std_dev: Optional 2D numpy array representing the standard deviation of the waveform
|
|
35
|
+
waveform_percentiles: Optional list of 2D numpy arrays representing percentiles of the waveform
|
|
36
|
+
"""
|
|
37
|
+
self.unit_id = unit_id
|
|
38
|
+
self.channel_ids = channel_ids
|
|
39
|
+
self.waveform = np.array(waveform, dtype=np.float32)
|
|
40
|
+
self.waveform_std_dev = (
|
|
41
|
+
np.array(waveform_std_dev, dtype=np.float32)
|
|
42
|
+
if waveform_std_dev is not None
|
|
43
|
+
else None
|
|
44
|
+
)
|
|
45
|
+
if waveform_percentiles is not None:
|
|
46
|
+
self.waveform_percentiles = [
|
|
47
|
+
np.array(p, dtype=np.float32) for p in waveform_percentiles
|
|
48
|
+
]
|
|
49
|
+
else:
|
|
50
|
+
self.waveform_percentiles = None
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class AverageWaveforms(FigpackView):
|
|
54
|
+
"""
|
|
55
|
+
A view that displays multiple average waveforms for spike sorting analysis
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
def __init__(self, *, average_waveforms: List[AverageWaveformItem]):
|
|
59
|
+
"""
|
|
60
|
+
Initialize an AverageWaveforms view
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
average_waveforms: List of AverageWaveformItem objects
|
|
64
|
+
"""
|
|
65
|
+
self.average_waveforms = average_waveforms
|
|
66
|
+
|
|
67
|
+
@staticmethod
|
|
68
|
+
def from_sorting_analyzer(sorting_analyzer):
|
|
69
|
+
sorting_analyzer.compute(
|
|
70
|
+
["random_spikes", "waveforms", "templates", "noise_levels"]
|
|
71
|
+
)
|
|
72
|
+
ext_templates = sorting_analyzer.get_extension("templates")
|
|
73
|
+
# shape is num_units, num_samples, num_channels
|
|
74
|
+
av_templates = ext_templates.get_data(operator="average")
|
|
75
|
+
|
|
76
|
+
ext_noise_levels = sorting_analyzer.get_extension("noise_levels")
|
|
77
|
+
noise_levels = ext_noise_levels.get_data()
|
|
78
|
+
|
|
79
|
+
waveform_std_dev = np.zeros(
|
|
80
|
+
(av_templates.shape[1], av_templates.shape[2]), dtype=np.float32
|
|
81
|
+
)
|
|
82
|
+
for i in range(av_templates.shape[2]):
|
|
83
|
+
waveform_std_dev[:, i] = noise_levels[i]
|
|
84
|
+
|
|
85
|
+
average_waveform_items = []
|
|
86
|
+
for i, unit_id in enumerate(sorting_analyzer.unit_ids):
|
|
87
|
+
waveform = av_templates[i]
|
|
88
|
+
channel_ids = list(sorting_analyzer.recording.get_channel_ids())
|
|
89
|
+
average_waveform_items.append(
|
|
90
|
+
AverageWaveformItem(
|
|
91
|
+
unit_id=unit_id,
|
|
92
|
+
waveform=waveform,
|
|
93
|
+
channel_ids=channel_ids,
|
|
94
|
+
waveform_std_dev=waveform_std_dev,
|
|
95
|
+
)
|
|
96
|
+
)
|
|
97
|
+
view = AverageWaveforms(average_waveforms=average_waveform_items)
|
|
98
|
+
return view
|
|
99
|
+
|
|
100
|
+
def _write_to_zarr_group(self, group: zarr.Group) -> None:
|
|
101
|
+
"""
|
|
102
|
+
Write the AverageWaveforms data to a Zarr group
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
group: Zarr group to write data into
|
|
106
|
+
"""
|
|
107
|
+
# Set the view type
|
|
108
|
+
group.attrs["view_type"] = "AverageWaveforms"
|
|
109
|
+
|
|
110
|
+
# Store the number of average waveforms
|
|
111
|
+
group.attrs["num_average_waveforms"] = len(self.average_waveforms)
|
|
112
|
+
|
|
113
|
+
# Store metadata for each average waveform
|
|
114
|
+
average_waveform_metadata = []
|
|
115
|
+
for i, waveform in enumerate(self.average_waveforms):
|
|
116
|
+
waveform_name = f"waveform_{i}"
|
|
117
|
+
|
|
118
|
+
# Store metadata
|
|
119
|
+
metadata = {
|
|
120
|
+
"name": waveform_name,
|
|
121
|
+
"unit_id": str(waveform.unit_id),
|
|
122
|
+
"channel_ids": [str(ch) for ch in waveform.channel_ids],
|
|
123
|
+
}
|
|
124
|
+
average_waveform_metadata.append(metadata)
|
|
125
|
+
|
|
126
|
+
# Create arrays for this average waveform
|
|
127
|
+
group.create_dataset(
|
|
128
|
+
f"{waveform_name}/waveform",
|
|
129
|
+
data=waveform.waveform,
|
|
130
|
+
dtype=waveform.waveform.dtype,
|
|
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
|
+
dtype=waveform.waveform_std_dev.dtype,
|
|
137
|
+
)
|
|
138
|
+
if waveform.waveform_percentiles is not None:
|
|
139
|
+
for j, p in enumerate(waveform.waveform_percentiles):
|
|
140
|
+
group.create_dataset(
|
|
141
|
+
f"{waveform_name}/waveform_percentile_{j}",
|
|
142
|
+
data=p,
|
|
143
|
+
dtype=p.dtype,
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
# Store the average waveform metadata
|
|
147
|
+
group.attrs["average_waveforms"] = average_waveform_metadata
|
|
@@ -33,14 +33,3 @@ class CrossCorrelogramItem:
|
|
|
33
33
|
self.unit_id2 = unit_id2
|
|
34
34
|
self.bin_edges_sec = np.array(bin_edges_sec, dtype=np.float32)
|
|
35
35
|
self.bin_counts = np.array(bin_counts, dtype=np.int32)
|
|
36
|
-
|
|
37
|
-
def to_dict(self):
|
|
38
|
-
"""
|
|
39
|
-
Convert the cross-correlogram item to a dictionary representation
|
|
40
|
-
"""
|
|
41
|
-
return {
|
|
42
|
-
"unit_id1": str(self.unit_id1),
|
|
43
|
-
"unit_id2": str(self.unit_id2),
|
|
44
|
-
"bin_edges_sec": self.bin_edges_sec.tolist(),
|
|
45
|
-
"bin_counts": self.bin_counts.tolist(),
|
|
46
|
-
}
|
|
@@ -32,6 +32,7 @@ class CrossCorrelograms(FigpackView):
|
|
|
32
32
|
self.cross_correlograms = cross_correlograms
|
|
33
33
|
self.hide_unit_selector = hide_unit_selector
|
|
34
34
|
|
|
35
|
+
@staticmethod
|
|
35
36
|
def from_sorting(sorting):
|
|
36
37
|
import spikeinterface as si
|
|
37
38
|
import spikeinterface.widgets as sw
|
|
@@ -40,6 +41,7 @@ class CrossCorrelograms(FigpackView):
|
|
|
40
41
|
W = sw.CrossCorrelogramsWidget(sorting)
|
|
41
42
|
return CrossCorrelograms.from_spikeinterface_widget(W)
|
|
42
43
|
|
|
44
|
+
@staticmethod
|
|
43
45
|
def from_spikeinterface_widget(W):
|
|
44
46
|
from spikeinterface.widgets.base import to_attr
|
|
45
47
|
from spikeinterface.widgets.utils_sortingview import make_serializable
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"""
|
|
2
|
+
SpikeAmplitudes view for figpack - displays spike amplitudes over time
|
|
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 .SpikeAmplitudesItem import SpikeAmplitudesItem
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class SpikeAmplitudes(FigpackView):
|
|
15
|
+
"""
|
|
16
|
+
A view that displays spike amplitudes over time for multiple units
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(
|
|
20
|
+
self,
|
|
21
|
+
*,
|
|
22
|
+
start_time_sec: float,
|
|
23
|
+
end_time_sec: float,
|
|
24
|
+
plots: List[SpikeAmplitudesItem],
|
|
25
|
+
hide_unit_selector: bool = False,
|
|
26
|
+
height: int = 500,
|
|
27
|
+
):
|
|
28
|
+
"""
|
|
29
|
+
Initialize a SpikeAmplitudes view
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
start_time_sec: Start time of the view in seconds
|
|
33
|
+
end_time_sec: End time of the view in seconds
|
|
34
|
+
plots: List of SpikeAmplitudesItem objects
|
|
35
|
+
hide_unit_selector: Whether to hide the unit selector
|
|
36
|
+
height: Height of the view in pixels
|
|
37
|
+
"""
|
|
38
|
+
self.start_time_sec = start_time_sec
|
|
39
|
+
self.end_time_sec = end_time_sec
|
|
40
|
+
self.plots = plots
|
|
41
|
+
self.hide_unit_selector = hide_unit_selector
|
|
42
|
+
self.height = height
|
|
43
|
+
|
|
44
|
+
def _write_to_zarr_group(self, group: zarr.Group) -> None:
|
|
45
|
+
"""
|
|
46
|
+
Write the SpikeAmplitudes data to a Zarr group
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
group: Zarr group to write data into
|
|
50
|
+
"""
|
|
51
|
+
# Set the view type
|
|
52
|
+
group.attrs["view_type"] = "SpikeAmplitudes"
|
|
53
|
+
|
|
54
|
+
# Store view parameters
|
|
55
|
+
group.attrs["start_time_sec"] = self.start_time_sec
|
|
56
|
+
group.attrs["end_time_sec"] = self.end_time_sec
|
|
57
|
+
group.attrs["hide_unit_selector"] = self.hide_unit_selector
|
|
58
|
+
group.attrs["height"] = self.height
|
|
59
|
+
|
|
60
|
+
# Store the number of plots
|
|
61
|
+
group.attrs["num_plots"] = len(self.plots)
|
|
62
|
+
|
|
63
|
+
# Store metadata for each plot
|
|
64
|
+
plot_metadata = []
|
|
65
|
+
for i, plot in enumerate(self.plots):
|
|
66
|
+
plot_name = f"plot_{i}"
|
|
67
|
+
|
|
68
|
+
# Store metadata
|
|
69
|
+
metadata = {
|
|
70
|
+
"name": plot_name,
|
|
71
|
+
"unit_id": str(plot.unit_id),
|
|
72
|
+
"num_spikes": len(plot.spike_times_sec),
|
|
73
|
+
}
|
|
74
|
+
plot_metadata.append(metadata)
|
|
75
|
+
|
|
76
|
+
# Create arrays for this plot
|
|
77
|
+
group.create_dataset(
|
|
78
|
+
f"{plot_name}/spike_times_sec",
|
|
79
|
+
data=plot.spike_times_sec,
|
|
80
|
+
dtype=np.float32,
|
|
81
|
+
)
|
|
82
|
+
group.create_dataset(
|
|
83
|
+
f"{plot_name}/spike_amplitudes",
|
|
84
|
+
data=plot.spike_amplitudes,
|
|
85
|
+
dtype=np.float32,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
# Store the plot metadata
|
|
89
|
+
group.attrs["plots"] = plot_metadata
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""
|
|
2
|
+
SpikeAmplitudesItem for figpack - represents spike amplitudes for a single unit
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Union
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class SpikeAmplitudesItem:
|
|
11
|
+
"""
|
|
12
|
+
Represents spike amplitudes for a single unit
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
*,
|
|
18
|
+
unit_id: Union[str, int],
|
|
19
|
+
spike_times_sec: np.ndarray,
|
|
20
|
+
spike_amplitudes: np.ndarray,
|
|
21
|
+
):
|
|
22
|
+
"""
|
|
23
|
+
Initialize a SpikeAmplitudesItem
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
unit_id: Identifier for the unit
|
|
27
|
+
spike_times_sec: 1D numpy array of spike times in seconds
|
|
28
|
+
spike_amplitudes: 1D numpy array of spike amplitudes
|
|
29
|
+
"""
|
|
30
|
+
assert spike_times_sec.ndim == 1, "Spike times must be 1-dimensional"
|
|
31
|
+
assert spike_amplitudes.ndim == 1, "Spike amplitudes must be 1-dimensional"
|
|
32
|
+
assert len(spike_times_sec) == len(
|
|
33
|
+
spike_amplitudes
|
|
34
|
+
), "Spike times and amplitudes must have the same length"
|
|
35
|
+
|
|
36
|
+
self.unit_id = unit_id
|
|
37
|
+
self.spike_times_sec = np.array(spike_times_sec, dtype=np.float32)
|
|
38
|
+
self.spike_amplitudes = np.array(spike_amplitudes, dtype=np.float32)
|
|
@@ -10,6 +10,9 @@ from .UnitSimilarityScore import UnitSimilarityScore
|
|
|
10
10
|
from .UnitsTable import UnitsTable
|
|
11
11
|
from .UnitsTableColumn import UnitsTableColumn
|
|
12
12
|
from .UnitsTableRow import UnitsTableRow
|
|
13
|
+
from .AverageWaveforms import AverageWaveforms
|
|
14
|
+
from .SpikeAmplitudesItem import SpikeAmplitudesItem
|
|
15
|
+
from .SpikeAmplitudes import SpikeAmplitudes
|
|
13
16
|
|
|
14
17
|
__all__ = [
|
|
15
18
|
"AutocorrelogramItem",
|
|
@@ -20,4 +23,7 @@ __all__ = [
|
|
|
20
23
|
"UnitsTableRow",
|
|
21
24
|
"UnitSimilarityScore",
|
|
22
25
|
"UnitsTable",
|
|
26
|
+
"AverageWaveforms",
|
|
27
|
+
"SpikeAmplitudesItem",
|
|
28
|
+
"SpikeAmplitudes",
|
|
23
29
|
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: figpack
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: A Python package for creating shareable, interactive visualizations in the browser
|
|
5
5
|
Author-email: Jeremy Magland <jmagland@flatironinstitute.org>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -25,8 +25,9 @@ Requires-Python: >=3.8
|
|
|
25
25
|
Description-Content-Type: text/markdown
|
|
26
26
|
License-File: LICENSE
|
|
27
27
|
Requires-Dist: numpy
|
|
28
|
-
Requires-Dist: zarr
|
|
28
|
+
Requires-Dist: zarr<3
|
|
29
29
|
Requires-Dist: requests
|
|
30
|
+
Requires-Dist: psutil
|
|
30
31
|
Provides-Extra: test
|
|
31
32
|
Requires-Dist: pytest>=7.0; extra == "test"
|
|
32
33
|
Requires-Dist: pytest-cov>=4.0; extra == "test"
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
figpack/__init__.py,sha256=qKVa2XgXzmxB506Y98CMOKvDXy8y-xdiDmkDLGJ3YE8,124
|
|
2
|
+
figpack/cli.py,sha256=DYV-DxzWnQTMNywW-ZzhlTEFOEIt11rAKdobdBmRQFk,12051
|
|
3
|
+
figpack/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
figpack/core/_bundle_utils.py,sha256=73E6FinAvrt1QATGncIqyg6JLeiWVmlGF8NOcFyeYSs,1913
|
|
5
|
+
figpack/core/_server_manager.py,sha256=8uxJftMgJ7EcVXtLo_VQuaiCZIyqgE89yDfCXKEgyeQ,10922
|
|
6
|
+
figpack/core/_show_view.py,sha256=WeHbQ1qdq5Lr54XTuNqmCIrwR4jbPWu8dT7Sm_UNcsk,5194
|
|
7
|
+
figpack/core/_upload_bundle.py,sha256=8D3M778E7nvkl9xnyrFOBlFhOOhywdiwLzOSPCMm4KE,13351
|
|
8
|
+
figpack/core/config.py,sha256=6EU9CMvzGk9308Xlx8iJ2cIHJV6pqhXyiZGkK2snA4g,108
|
|
9
|
+
figpack/core/figpack_view.py,sha256=q-Xxk9X4dnLy_kGX0POC7FLB6qwmBfqrWD6uelPJZVE,3708
|
|
10
|
+
figpack/figpack-gui-dist/index.html,sha256=HU8Dv1EzISPzQjibGxDA6tAz7VpzjL6o-HXOPKv4s4E,486
|
|
11
|
+
figpack/figpack-gui-dist/assets/index-Cmae55E4.css,sha256=Yg0apcYehJwQvSQIUH13S7tsfqWQDevpJsAho0dDf0g,5499
|
|
12
|
+
figpack/figpack-gui-dist/assets/index-DUR9Dmwh.js,sha256=iHbhpBXkfKoDzn-ZDxh2_uktWyzSTwes9gzgdBEM7PU,1590964
|
|
13
|
+
figpack/figpack-gui-dist/assets/neurosift-logo-CLsuwLMO.png,sha256=g5m-TwrGh5f6-9rXtWV-znH4B0nHgc__0GWclRDLUHs,9307
|
|
14
|
+
figpack/franklab/__init__.py,sha256=HkehqGImJE_sE2vbPDo-HbgtEYaMICb9-230xTYvRTU,56
|
|
15
|
+
figpack/franklab/views/TrackAnimation.py,sha256=3Jv1Ri4FIwTyqNahinqhHsBH1Bv_iZrEGx12w6diJ2M,5636
|
|
16
|
+
figpack/franklab/views/__init__.py,sha256=XXZ9QJLh9KAeeLgKbi6ogYOyfTgHP-N6o3u981NFwx8,116
|
|
17
|
+
figpack/spike_sorting/__init__.py,sha256=09njqh-oFaCTdZUsc4HAOFTliUYV9DClddfZ0Q_dm0I,61
|
|
18
|
+
figpack/spike_sorting/views/AutocorrelogramItem.py,sha256=qHmvIdHpbfVA_utPb5N2oP3hSP2cGnlT8VLaxOXV4UM,738
|
|
19
|
+
figpack/spike_sorting/views/Autocorrelograms.py,sha256=43EgKHvUmXUA9QSOJQZiTeLHq_kKW43Ku3FIH7ZjfM8,3323
|
|
20
|
+
figpack/spike_sorting/views/AverageWaveforms.py,sha256=mvMkS3wf6MpI95tlGqKxBjxZlHqJr4aqG7SZvHigIsI,5193
|
|
21
|
+
figpack/spike_sorting/views/CrossCorrelogramItem.py,sha256=uSd0i2hupteuILi_aKp7bYPYpL_PdC3CUDRMOEKUEM0,880
|
|
22
|
+
figpack/spike_sorting/views/CrossCorrelograms.py,sha256=gqPXbEgg-GE3NCJQT2bahp1ITSW33F3q9ZuJRGrR68M,4061
|
|
23
|
+
figpack/spike_sorting/views/SpikeAmplitudes.py,sha256=vQYWdJM-3qu568bcfGDC9k9LW_PgvU8j4tN9QYc08Mo,2665
|
|
24
|
+
figpack/spike_sorting/views/SpikeAmplitudesItem.py,sha256=j5Na-diY-vRUAPu0t0VkyFCSKFnQ_f5HT077mB3Cy8c,1134
|
|
25
|
+
figpack/spike_sorting/views/UnitSimilarityScore.py,sha256=cJA9MkETos9qHhV1tqgA7SfNEaPo-duXYCE76hSFGnA,948
|
|
26
|
+
figpack/spike_sorting/views/UnitsTable.py,sha256=kQZvMlnPk8MAMPr3GlL4T3cAvGfSHBbB52jvMJ2-YAU,2173
|
|
27
|
+
figpack/spike_sorting/views/UnitsTableColumn.py,sha256=zBnuoeILTuiVLDvtcOxqa37E5WlbR12rlwNJUeWXxY4,847
|
|
28
|
+
figpack/spike_sorting/views/UnitsTableRow.py,sha256=rEb2hMTA_pl2fTW1nOvnGir0ysfNx4uww3aekZzfWjk,720
|
|
29
|
+
figpack/spike_sorting/views/__init__.py,sha256=WdGhMcptNM5OJ5hG3PXOIyjGRsFcp12DtABocMehVSU,849
|
|
30
|
+
figpack/views/Box.py,sha256=TfhPFNtVEq71LCucmWk3XX2WxQLdaeRiWGm5BM0k2l4,2236
|
|
31
|
+
figpack/views/Image.py,sha256=xbnkmiqlrYD9_BGsQgSGgqXJbvNECTI7iJhLsEd3kSg,2990
|
|
32
|
+
figpack/views/LayoutItem.py,sha256=wy8DggkIzZpU0F1zFIBceS7HpBb6lu-A3hpYINQzedk,1595
|
|
33
|
+
figpack/views/Markdown.py,sha256=KEqEAz5VXErLXr8dYJrWY1I8_VdRazDIcjCNcHfUGPA,769
|
|
34
|
+
figpack/views/MatplotlibFigure.py,sha256=LQSvPY3_iSHO-ZfWjRO6iOVUp5W-mmlt3mj8GBoK18w,1939
|
|
35
|
+
figpack/views/MultiChannelTimeseries.py,sha256=sWr2nW1eoYR7V44wF7fac7IoQ6BOnus1nc4STkgIkYw,8501
|
|
36
|
+
figpack/views/PlotlyFigure.py,sha256=B02nfWFM89GnDUZiS2v89ZtGBdSZtAwcXUD_7rV7kN4,1633
|
|
37
|
+
figpack/views/Splitter.py,sha256=x9jLCTlIvDy5p9ymVd0X48KDccyD6bJANhXyFgKEmtE,2007
|
|
38
|
+
figpack/views/TabLayout.py,sha256=5g3nmL95PfqgI0naqZXHMwLVo2ebDlGX01Hy9044bUw,1898
|
|
39
|
+
figpack/views/TabLayoutItem.py,sha256=xmHA0JsW_6naJze4_mQuP_Fy0Nm17p2N7w_AsmVRp8k,880
|
|
40
|
+
figpack/views/TimeseriesGraph.py,sha256=OAaCjO8fo86u_gO_frNfRGxng3tczxGDGKcJEvZo3rE,7469
|
|
41
|
+
figpack/views/__init__.py,sha256=8y4KdRtrdDF0-xtQQkj4k_d8Ajk44Q7myztl3StdZcU,407
|
|
42
|
+
figpack-0.2.3.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
43
|
+
figpack-0.2.3.dist-info/METADATA,sha256=m_CybGYmcQYpRliR1ZkHMP7sM7qbSTR89sVKBzZvTOI,5886
|
|
44
|
+
figpack-0.2.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
45
|
+
figpack-0.2.3.dist-info/entry_points.txt,sha256=l6d3siH2LxXa8qJGbjAqpIZtI5AkMSyDeoRDCzdrUto,45
|
|
46
|
+
figpack-0.2.3.dist-info/top_level.txt,sha256=lMKGaC5xWmAYBx9Ac1iMokm42KFnJFjmkP2ldyvOo-c,8
|
|
47
|
+
figpack-0.2.3.dist-info/RECORD,,
|