Skip to content

Commit 7a4e8eb

Browse files
authored
Merge pull request #4055 from chrishalcrow/add-tetrodes-doc
Add working with tetrodes doc
2 parents 9e94ccf + 0840fc6 commit 7a4e8eb

6 files changed

Lines changed: 125 additions & 0 deletions

File tree

doc/conf.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@
129129
'../examples/tutorials/qualitymetrics',
130130
'../examples/tutorials/comparison',
131131
'../examples/tutorials/widgets',
132+
'../examples/tutorials/forhowto',
132133
]),
133134
'within_subsection_order': FileNameSortKey,
134135
'ignore_pattern': '/generate_*',

doc/how_to/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ Guides on how to solve specific, short problems in SpikeInterface. Learn how to.
2020
physical_units
2121
unsigned_to_signed
2222
customize_a_plot
23+
../tutorials/forhowto/plot_1_working_with_tetrodes

doc/how_to/process_by_channel_group.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
.. _recording-by-channel-group:
2+
13
Process a recording by channel group
24
====================================
35

examples/how_to/working_with_tetrodes.py

Whitespace-only changes.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
For how to
2+
----------
3+
4+
These documents are files which we would like sphinx-gallery to run, but are linked by the how to guide.
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
"""
2+
Working with tetrodes
3+
=====================
4+
5+
Tetrodes are a common recording method for electrophysiological data. It is also common
6+
to record from several tetrodes at the same time. In this 'how to' we'll see how to
7+
work with data from two tetrodes, each with four channels.
8+
9+
We'll start by importing some functions we'll use in this How To guide
10+
"""
11+
12+
import spikeinterface.preprocessing as spre
13+
from spikeinterface.widgets import plot_traces, plot_probe_map
14+
from spikeinterface import generate_ground_truth_recording
15+
16+
from probeinterface import generate_tetrode, ProbeGroup
17+
18+
##############################################################################
19+
# In practice, you would read in your raw data from a file. Instead, we will generate a
20+
# recording with eight channels. We can also set a duration, number of units and
21+
# sampling frequency.
22+
23+
recording, _ = generate_ground_truth_recording(
24+
durations = [60], # make the recording 60s long
25+
sampling_frequency=30_000,
26+
num_channels=8,
27+
num_units=10,
28+
)
29+
30+
##############################################################################
31+
# We now need to define the probe. This will tell the recording which channels came from
32+
# which tetrode. To do this, we will use the :code:`generate_tetrode` function from :code:`ProbeInterface`
33+
# to generate two 4-channel probes (representing one tetrode each). In our case, since we
34+
# don't know the relative distances between the tetrodes, we will move the second
35+
# tetrode away from the first by 100 microns. This is just so we can visualize the
36+
# results more easily. Eventually, we will sort each tetrode separately, so their
37+
# relative distance won't affect the results.
38+
39+
# Technically, we will add each tetrode to a :code:`ProbeGroup`. Read more in the ProbeInterface
40+
# docs.
41+
42+
# Create each individual tetrode
43+
tetrode_1 = generate_tetrode()
44+
tetrode_1.create_auto_shape()
45+
46+
tetrode_2 = generate_tetrode()
47+
tetrode_2.move([100, 0])
48+
tetrode_2.create_auto_shape()
49+
50+
# Add the two tetrodes to a ProbeGroup
51+
tetrode_group = ProbeGroup()
52+
tetrode_group.add_probe(tetrode_1)
53+
tetrode_group.add_probe(tetrode_2)
54+
55+
# Now we need to "wire" our tetrodes to ensure that each contact
56+
# can be associated with the correct channel when we attach it
57+
# to the recording. In this example we are just using `range`
58+
# but see ProbeInterface for more tutorials on wiring
59+
tetrode_group.set_global_device_channel_indices(range(8))
60+
61+
##############################################################################
62+
# We can now attach the :code:`tetrode_group` to our recording. To check if this worked, we'll
63+
# plot the probe map
64+
65+
recording_with_probe = recording.set_probegroup(tetrode_group)
66+
plot_probe_map(recording_with_probe)
67+
68+
##############################################################################
69+
# Looks good! Now that the recording is aware of the probe geometry, we can
70+
# begin a standard spike sorting pipeline. First, we can apply preprocessing.
71+
# Note that we apply this preprocessing on the entire bundle of tetrodes.
72+
73+
preprocessed_recording = spre.bandpass_filter(recording_with_probe)
74+
75+
##############################################################################
76+
# WARNING: a very common preprocessing step is to apply a common median
77+
# reference. This subtracts the median signal from all channels to help
78+
# remove noise. However, for a tetrode, a spike is often seen on all
79+
# channels. So removing the median can remove the entire spike!
80+
# This is still a danger if you have two tetrodes in a bundle, which
81+
# might pick up the same spike, but becomes less dangerous
82+
# as the number of tetrodes in your bundle increases.
83+
#
84+
# Tetrodes often have dead channels, so it is advised to try and detect
85+
# and remove these. For tetrodes, we should use a detection method which
86+
# doesn't depend on the channel locations such as std or mad:
87+
88+
recording_good_channels = spre.detect_and_remove_bad_channels(
89+
preprocessed_recording,
90+
method = "std",
91+
)
92+
93+
##############################################################################
94+
# It can be a good idea to sort your tetrode data separately for each tetrode.
95+
# When we use :code:`set_probegroup`, the channels are automatically
96+
# labelled by which probe in the probe group they belong to. We can access
97+
# this labeling using the "group" property.
98+
99+
print(recording_good_channels.get_property("group"))
100+
101+
##############################################################################
102+
# We can then use this information to split the recording by the group property:
103+
104+
grouped_recordings = recording_good_channels.split_by('group')
105+
print(grouped_recordings)
106+
107+
##############################################################################
108+
# Now that we've got preprocess, clean data. Let's take a look at a
109+
# snippet of data from the first group:
110+
111+
plot_traces(grouped_recordings[0])
112+
113+
##############################################################################
114+
# Beautiful! We are now ready to sort. To read more about sorting by group, see
115+
# :ref:`sorting-by-channel-group`. Note that many modern sorters are designed
116+
# to sort data from high-density probes and will fail for tetrodes. Please read
117+
# each spike sorter's documentation to find out if it is appropriate for tetrodes.

0 commit comments

Comments
 (0)