Skip to content

Commit ffe88c3

Browse files
edenoCBroz1
andauthored
Minor decoding fixes (#819)
* Fix name and filtering * Fix linting * New methods for mua * Fix name of part table * Add detection interval and update notebooks * Add figurl for ripple for debugging * Update CHANGELOG.md * Add a way to filter the channels * Add z-score threshold and raster * Add demo and paper code references * Fix ripple trace * Fix ripple and mua z-score * Remove raster from mua figurl, update notebooks * Go back to red color * Remove because doesn't belong here * Apply suggestions from code review Co-authored-by: Chris Brozdowski <[email protected]> * Handle no zscore case * Move ripple times inside function * Simplify getting the time and speed * Update notebooks --------- Co-authored-by: Chris Brozdowski <[email protected]>
1 parent 992de69 commit ffe88c3

File tree

11 files changed

+781
-2538
lines changed

11 files changed

+781
-2538
lines changed

CHANGELOG.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
- Spike sorting:
2929
- Add SpikeSorting V1 pipeline. #651
3030
- Move modules into spikesorting.v0 #807
31-
- Add MUA analysis to spike sorting pipeline
3231
- LFP:
3332
- Minor fixes to LFPBandV1 populator and `make`. #706, #795
3433
- LFPV1: Fix error for multiple lfp settings on same data #775
@@ -41,7 +40,7 @@
4140
- DLC path handling from config, and normalize naming convention. #722
4241
- Fix in place column bug #752
4342
- Decoding:
44-
- Add `decoding` pipeline V1. #731, #769
43+
- Add `decoding` pipeline V1. #731, #769, #819
4544
- Add a table to store the decoding results #731
4645
- Use the new `non_local_detector` package for decoding #731
4746
- Allow multiple spike waveform features for clusterless decoding #731
@@ -51,6 +50,10 @@
5150
- Rename SortedSpikesGroup.SortGroup to SortedSpikesGroup.Units #807
5251
- Change methods with load\_... to fetch\_... for consistency #807
5352
- Use merge table methods to access part methods #807
53+
- MUA
54+
- Add MUA pipeline V1. #731, #819
55+
- Ripple
56+
- Add figurl to Ripple pipeline #819
5457

5558
## [0.4.3] (November 7, 2023)
5659

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ visualization, and sharing of neuroscience data to support reproducible
1010
research. It is designed to be interoperable with the NWB format and integrates
1111
open-source tools into a coherent framework.
1212

13+
Try out a demo [here](https://spyglass.hhmi.2i2c.cloud/hub/user-redirect/git-pull?repo=https%3A%2F%2Fgithub.com%2FLorenFrankLab%2Fspyglass-demo&urlpath=lab%2Ftree%2Fspyglass-demo%2Fnotebooks%2F01_Insert_Data.ipynb&branch=main)!
14+
1315
Features of Spyglass include:
1416

1517
- **Standardized data storage** - Spyglass uses the open-source
@@ -86,3 +88,5 @@ a data analysis framework for reproducible and shareable neuroscience research.
8688
[10.1101/2024.01.25.577295](https://doi.org/10.1101/2024.01.25.577295 ).
8789

8890
*\* Equal contribution*
91+
92+
See paper related code [here](https://github.com/LorenFrankLab/spyglass-paper).

notebooks/43_Decoding_SortedSpikes.ipynb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -655,7 +655,7 @@
655655
],
656656
"source": [
657657
"# look at the sorting within the group we just made\n",
658-
"SortedSpikesGroup.SortGroup & {\n",
658+
"SortedSpikesGroup.Units & {\n",
659659
" \"nwb_file_name\": nwb_copy_file_name,\n",
660660
" \"sorted_spikes_group_name\": \"test_group\",\n",
661661
" \"unit_filter_params_name\": unit_filter_params_name,\n",

notebooks/51_MUA_Detection.ipynb

Lines changed: 457 additions & 2309 deletions
Large diffs are not rendered by default.

notebooks/py_scripts/43_Decoding_SortedSpikes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@
108108
# -
109109

110110
# look at the sorting within the group we just made
111-
SortedSpikesGroup.SortGroup & {
111+
SortedSpikesGroup.Units & {
112112
"nwb_file_name": nwb_copy_file_name,
113113
"sorted_spikes_group_name": "test_group",
114114
"unit_filter_params_name": unit_filter_params_name,

notebooks/py_scripts/51_MUA_Detection.py

Lines changed: 47 additions & 177 deletions
Original file line numberDiff line numberDiff line change
@@ -13,229 +13,99 @@
1313
# ---
1414

1515
# +
16-
from pathlib import Path
1716
import datajoint as dj
17+
from pathlib import Path
1818

1919
dj.config.load(
2020
Path("../dj_local_conf.json").absolute()
2121
) # load config for database connection info
22+
23+
from spyglass.mua.v1.mua import MuaEventsV1, MuaEventsParameters
24+
2225
# -
2326

24-
# # MUA Analysis and Detection
25-
#
26-
# NOTE: This notebook is a work in progress. It is not yet complete and may contain errors.
27+
MuaEventsParameters()
28+
29+
MuaEventsV1()
2730

2831
# +
29-
from spyglass.spikesorting.spikesorting_merge import SpikeSortingOutput
30-
import spyglass.spikesorting.v1 as sgs
31-
32+
from spyglass.position import PositionOutput
3233

3334
nwb_copy_file_name = "mediumnwb20230802_.nwb"
3435

35-
sorter_keys = {
36+
trodes_s_key = {
3637
"nwb_file_name": nwb_copy_file_name,
37-
"sorter": "clusterless_thresholder",
38-
"sorter_param_name": "default_clusterless",
38+
"interval_list_name": "pos 0 valid times",
39+
"trodes_pos_params_name": "single_led_upsampled",
3940
}
4041

41-
(sgs.SpikeSortingSelection & sorter_keys) * SpikeSortingOutput.CurationV1
42-
43-
# +
44-
spikesorting_merge_ids = (
45-
(sgs.SpikeSortingSelection & sorter_keys) * SpikeSortingOutput.CurationV1
46-
).fetch("merge_id")
47-
48-
spikesorting_merge_ids
49-
50-
# +
51-
from spyglass.spikesorting.unit_inclusion_merge import (
52-
ImportedUnitInclusionV1,
53-
UnitInclusionOutput,
54-
)
55-
56-
ImportedUnitInclusionV1().insert_all_units(spikesorting_merge_ids)
57-
58-
UnitInclusionOutput.ImportedUnitInclusionV1() & [
59-
{"spikesorting_merge_id": id} for id in spikesorting_merge_ids
60-
]
61-
62-
# +
63-
from spyglass.spikesorting.unit_inclusion_merge import (
64-
ImportedUnitInclusionV1,
65-
UnitInclusionOutput,
66-
)
67-
68-
ImportedUnitInclusionV1().insert_all_units(spikesorting_merge_ids)
69-
70-
UnitInclusionOutput.ImportedUnitInclusionV1() & [
71-
{"spikesorting_merge_id": id} for id in spikesorting_merge_ids
72-
]
42+
pos_merge_id = (PositionOutput.TrodesPosV1 & trodes_s_key).fetch1("merge_id")
43+
pos_merge_id
7344

7445
# +
75-
from spyglass.spikesorting.unit_inclusion_merge import SortedSpikesGroup
76-
77-
unit_inclusion_merge_ids = (
78-
UnitInclusionOutput.ImportedUnitInclusionV1
79-
& [{"spikesorting_merge_id": id} for id in spikesorting_merge_ids]
80-
).fetch("merge_id")
81-
82-
SortedSpikesGroup().create_group(
83-
group_name="test_group",
84-
nwb_file_name=nwb_copy_file_name,
85-
unit_inclusion_merge_ids=unit_inclusion_merge_ids,
46+
from spyglass.spikesorting.analysis.v1.group import (
47+
SortedSpikesGroup,
8648
)
8749

88-
group_key = {
50+
sorted_spikes_group_key = {
8951
"nwb_file_name": nwb_copy_file_name,
9052
"sorted_spikes_group_name": "test_group",
53+
"unit_filter_params_name": "default_exclusion",
9154
}
9255

93-
SortedSpikesGroup & group_key
94-
# -
95-
96-
SortedSpikesGroup.Units() & group_key
97-
98-
# An example of how to get spike times
99-
100-
spike_times = SortedSpikesGroup.fetch_spike_data(group_key)
101-
spike_times[0]
56+
SortedSpikesGroup & sorted_spikes_group_key
10257

10358
# +
104-
from spyglass.position import PositionOutput
105-
106-
position_merge_id = (
107-
PositionOutput.TrodesPosV1
108-
& {
109-
"nwb_file_name": nwb_copy_file_name,
110-
"interval_list_name": "pos 0 valid times",
111-
"trodes_pos_params_name": "default_decoding",
112-
}
113-
).fetch1("merge_id")
114-
115-
position_info = (
116-
(PositionOutput & {"merge_id": position_merge_id})
117-
.fetch1_dataframe()
118-
.dropna()
119-
)
120-
position_info
121-
122-
# +
123-
time_ind_slice = slice(63_000, 70_000)
124-
time = position_info.index[time_ind_slice]
125-
126-
SortedSpikesGroup.get_spike_indicator(group_key, time)
127-
128-
# +
129-
import matplotlib.pyplot as plt
130-
131-
fig, axes = plt.subplots(2, 1, sharex=True, figsize=(15, 4))
132-
multiunit_firing_rate = SortedSpikesGroup.get_firing_rate(
133-
group_key, time, multiunit=True
134-
)
135-
axes[0].plot(
136-
time,
137-
multiunit_firing_rate,
138-
)
139-
axes[0].set_ylabel("firing rate (Hz)")
140-
axes[0].set_title("multiunit")
141-
axes[1].fill_between(
142-
time, position_info["speed"].iloc[time_ind_slice], color="lightgrey"
143-
)
144-
axes[1].set_ylabel("speed (cm/s)")
145-
axes[1].set_xlabel("time (s)")
146-
147-
# +
148-
from spyglass.mua.v1.mua import MuaEventsParameters, MuaEventsV1
149-
150-
MuaEventsParameters().insert_default()
151-
MuaEventsParameters()
152-
153-
# +
154-
selection_key = {
59+
mua_key = {
15560
"mua_param_name": "default",
156-
"nwb_file_name": nwb_copy_file_name,
157-
"sorted_spikes_group_name": "test_group",
158-
"pos_merge_id": position_merge_id,
159-
"artifact_interval_list_name": "test_artifact_times",
61+
**sorted_spikes_group_key,
62+
"pos_merge_id": pos_merge_id,
63+
"detection_interval": "pos 0 valid times",
16064
}
16165

162-
MuaEventsV1.populate(selection_key)
66+
MuaEventsV1().populate(mua_key)
67+
MuaEventsV1 & mua_key
16368
# -
16469

165-
MuaEventsV1 & selection_key
166-
167-
mua_times = (MuaEventsV1 & selection_key).fetch1_dataframe()
70+
mua_times = (MuaEventsV1 & mua_key).fetch1_dataframe()
16871
mua_times
16972

17073
# +
17174
import matplotlib.pyplot as plt
17275
import numpy as np
17376

17477
fig, axes = plt.subplots(2, 1, sharex=True, figsize=(15, 4))
78+
speed = MuaEventsV1.get_speed(mua_key).to_numpy()
79+
time = speed.index.to_numpy()
80+
multiunit_firing_rate = MuaEventsV1.get_firing_rate(mua_key, time)
81+
82+
time_slice = slice(
83+
np.searchsorted(time, mua_times.loc[10].start_time) - 1_000,
84+
np.searchsorted(time, mua_times.loc[10].start_time) + 5_000,
85+
)
86+
17587
axes[0].plot(
176-
time,
177-
multiunit_firing_rate,
88+
time[time_slice],
89+
multiunit_firing_rate[time_slice],
90+
color="black",
17891
)
17992
axes[0].set_ylabel("firing rate (Hz)")
18093
axes[0].set_title("multiunit")
181-
axes[1].fill_between(
182-
time, position_info["speed"].iloc[time_ind_slice], color="lightgrey"
183-
)
94+
axes[1].fill_between(time[time_slice], speed[time_slice], color="lightgrey")
18495
axes[1].set_ylabel("speed (cm/s)")
18596
axes[1].set_xlabel("time (s)")
18697

187-
in_bounds = np.logical_and(
188-
mua_times.start_time >= time[0], mua_times.end_time <= time[-1]
189-
)
190-
191-
for mua_time in mua_times.loc[in_bounds].itertuples():
192-
axes[0].axvspan(
193-
mua_time.start_time, mua_time.end_time, color="red", alpha=0.3
98+
for id, mua_time in mua_times.loc[
99+
np.logical_and(
100+
mua_times["start_time"] > time[time_slice].min(),
101+
mua_times["end_time"] < time[time_slice].max(),
194102
)
195-
axes[1].axvspan(
196-
mua_time.start_time, mua_time.end_time, color="red", alpha=0.3
103+
].iterrows():
104+
axes[0].axvspan(
105+
mua_time["start_time"], mua_time["end_time"], color="red", alpha=0.5
197106
)
198-
axes[1].set_ylim((0, 80))
199-
axes[1].axhline(4, color="black", linestyle="--")
200-
axes[1].set_xlim((time[0], time[-1]))
201-
202-
# +
203-
from spyglass.common import IntervalList
204-
205-
IntervalList() & {
206-
"nwb_file_name": nwb_copy_file_name,
207-
"pipeline": "spikesorting_artifact_v1",
208-
}
209107
# -
210108

211-
(
212-
sgs.ArtifactDetectionParameters
213-
* sgs.SpikeSortingRecording
214-
* sgs.ArtifactDetectionSelection
215-
)
216-
217-
SpikeSortingOutput.CurationV1() * (
218-
sgs.ArtifactDetectionParameters
219-
* sgs.SpikeSortingRecording
220-
* sgs.ArtifactDetectionSelection
221-
)
222-
223-
(
224-
IntervalList()
225-
& {
226-
"nwb_file_name": nwb_copy_file_name,
227-
"pipeline": "spikesorting_artifact_v1",
228-
}
229-
).proj(artifact_id="interval_list_name")
230-
231-
sgs.SpikeSortingRecording() * sgs.ArtifactDetectionSelection()
232-
233-
SpikeSortingOutput.CurationV1() * sgs.SpikeSortingRecording()
234-
235-
IntervalList.insert1(
236-
{
237-
"nwb_file_name": nwb_copy_file_name,
238-
"interval_list_name": "test_artifact_times",
239-
"valid_times": [],
240-
}
109+
(MuaEventsV1 & mua_key).create_figurl(
110+
zscore_mua=True,
241111
)

src/spyglass/mua/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from spyglass.mua.v1.mua import MuaEventsParameters, MuaEventsV1 # noqa: F401

src/spyglass/mua/v1/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from spyglass.mua.v1.mua import MuaEventsParameters, MuaEventsV1 # noqa: F401

0 commit comments

Comments
 (0)