Skip to content

Commit 7320abc

Browse files
committed
added code for re-extracting spikes from raw data
1 parent abc9935 commit 7320abc

File tree

4 files changed

+172
-2
lines changed

4 files changed

+172
-2
lines changed

extract_spikes_from_raw.m

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
2+
3+
%% load raw data
4+
5+
set(0,'DefaultFigureWindowStyle','docked'); % fix matlab's figure positioning bug
6+
7+
% raw data available on
8+
% https://drive.google.com/drive/folders/1CwFcErgp3F3D6I2TB_hTtW1JAQB21TAC?usp=sharing
9+
%
10+
datapath='/home/jvoigts/Desktop/TT13_continuous_3/'
11+
12+
out_dir='/home/jvoigts/Desktop/TT13_continuous_3/';
13+
out_name = 'marie_rsc_test.mat';
14+
15+
source_channels=[40 40 38 36];
16+
17+
data_raw=[];
18+
for ch=source_cahnnels % grab 4 channels of raw data from one tetrode
19+
fname=sprintf('100_CH%d.continuous',ch)
20+
[data, timestamps, info]=load_open_ephys_data_faster(fullfile(datapath,fname));
21+
data_raw(:,end+1) = data;
22+
end;
23+
24+
data_raw=data_raw.*info.header.bitVolts;
25+
fs = info.header.sampleRate;
26+
27+
%data_raw=data_raw(1:30000,:); % cut away some data for faster testing
28+
29+
%% plot
30+
31+
plotlim=50000;
32+
figure(1);
33+
clf;
34+
hold on;
35+
plot(data_raw(1:plotlim,:));
36+
37+
38+
%% filter
39+
40+
clf; hold on;
41+
[b,a] = butter(3, [300 3000]/(fs/2)); % choose filter (normalize bp freq. to nyquist freq.)
42+
43+
data_bp=filtfilt(b,a,data_raw); %use zero phase filter
44+
45+
%% plot filtered
46+
offset=plotlim*0;
47+
clf;
48+
plot(data_bp([1:plotlim]+offset,:));
49+
hold on;
50+
51+
%% find treshold crossings
52+
treshold=-6;
53+
crossed= min(data_bp,[],2)<-treshold; % trigger if _any_ channel crosses in neg. direction
54+
55+
spike_onsets=find(diff(crossed)==1);
56+
57+
length_sec=size(data,1)/fs;
58+
fprintf('got %d candidate events in %dmin of data, ~%.2f Hz\n',numel(spike_onsets),round(length_sec/60),numel(spike_onsets)/length_sec);
59+
60+
%% plot some spike onsets
61+
for i=1:100%numel(spike_onsets)
62+
if(spike_onsets(i)<plotlim)
63+
plot([1 1].*spike_onsets(i),[-1 1].*treshold*2,'k--')
64+
end;
65+
end;
66+
67+
68+
%% extract spike waveforms and make some features
69+
70+
spike_window=[1:32]-5; % grab some pre-treshold crossign samples
71+
72+
spikes=[];
73+
spikes.waveforms=zeros(numel(spike_onsets),4*numel(spike_window)); % pre-allocate memory
74+
spikes.peakamps=zeros(numel(spike_onsets),4);
75+
spikes.times = spike_onsets/(fs/1000);
76+
77+
for i=1:numel(spike_onsets)
78+
this_spike=(data_bp(spike_onsets(i)+spike_window,:));
79+
80+
spikes.waveforms(i,:)= this_spike(:);% grab entire waveform
81+
spikes.peakamps(i,:)=min(this_spike); % grab 4 peak amplitudes
82+
end;
83+
84+
%% make into and save as simpleclust compatible file
85+
mua=[];
86+
mua.waveforms=spikes.waveforms;
87+
mua.sourcechannel = source_channels;
88+
mua.ts = spike_onsets/info.header.sampleRate;
89+
mua.ts_spike=([1:size(spikes.waveforms,2)]-1)./info.header.sampleRate;
90+
mua.ncontacts=4;
91+
92+
save(fullfile(out_dir,[out_name,'.mat']),'mua');
93+
94+
95+
%% BELOW HERE IS A VERY MINIMAL SPIKE SORTER
96+
97+
%% plot peak to peak amplitudes
98+
clf; hold on;
99+
plot(spikes.peakamps(:,2),spikes.peakamps(:,4),'.');
100+
daspect([1 1 1]);
101+
102+
%% initialize all cluster assignments to 1
103+
spikes.cluster=ones(numel(spike_onsets),1);
104+
105+
%% manual spike sorter
106+
% cluster 0 shall be the noise cluster (dont plot this one)
107+
run =1;
108+
109+
projections=[1 2; 1 3; 1 4; 2 3; 2 4; 3 4]; % possible feature projections
110+
use_projection=1;
111+
112+
cluster_selected=2; spike_selected=1;
113+
114+
while run
115+
dat_x=spikes.peakamps(:,projections(use_projection,1));
116+
dat_y=spikes.peakamps(:,projections(use_projection,2));
117+
118+
clf;
119+
subplot(2,3,1); hold on;% plot median waveform
120+
plot(quantile(spikes.waveforms(spikes.cluster==cluster_selected,:),.2),'g');
121+
plot(quantile(spikes.waveforms(spikes.cluster==cluster_selected,:),.5),'k');
122+
plot(quantile(spikes.waveforms(spikes.cluster==cluster_selected,:),.8),'g');
123+
plot(spikes.waveforms(spike_selected,:),'r'); % also plot currently selected spike waveform
124+
125+
title('waveforms from cluster');
126+
127+
subplot(2,3,4); hold on;% plot isi distribution
128+
isi = diff(spikes.times(spikes.cluster==cluster_selected));
129+
bins=linspace(0.5,15,20);
130+
h= hist(isi,bins); h(end)=0;
131+
stairs(bins,h);
132+
title('ISI histogram'); xlabel('isi(ms)');
133+
134+
ax=subplot(2,3,[2 3 5 6]); hold on; % plot main feature display
135+
ii=spikes.cluster>0; % dont plot noise cluster
136+
scatter(dat_x(ii),dat_y(ii),(0.5+(spikes.cluster(ii)==cluster_selected))*20,spikes.cluster(ii)*2,'filled');
137+
plot(dat_x(spike_selected),dat_y(spike_selected),'ro','markerSize',10);
138+
title(sprintf('current cluster %d, projection %d, %d spikes in cluster',cluster_selected,use_projection,sum(spikes.cluster==cluster_selected)));
139+
140+
[x,y,b]=ginput(1);
141+
142+
if b>47 & b <58 % number keys, cluster select
143+
cluster_selected=b-48;
144+
end;
145+
146+
if b==30; use_projection=mod(use_projection,6)+1; end; % up/down: cycle trough projections
147+
if b==31; use_projection=mod(use_projection-2,6)+1; end; % up/down: cycle trough projections
148+
if b==27; disp('exited'); run=0; end; % esc: exit
149+
150+
if b==43 | b==42; % +, add to cluster
151+
t= imfreehand(ax,'Closed' ,1);
152+
t.setClosed(1);
153+
r=t.getPosition;
154+
px=r(:,1);py=r(:,2);
155+
in = inpolygon(dat_x,dat_y,px,py);
156+
if b==43 % +, add
157+
spikes.cluster(in)=cluster_selected;
158+
else % *. intersect cluster (move all non selected to null cluster)
159+
spikes.cluster(~in & spikes.cluster==cluster_selected)=1;
160+
end;
161+
end;
162+
163+
if b==1 % left click - select individual waveform to plot
164+
[~,spike_selected]=min((dat_x-x).^2 +(dat_y-y).^2);
165+
end;
166+
167+
end;

sc_getpolygon.m

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
t= imfreehand(gca,'Closed' ,1);
2828
t.setClosed(1);
2929
r=t.getPosition;
30-
3130
px=r(:,1);py=r(:,2);
3231

3332
% remap from screen space to feature space

sc_mua2features.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@
9999
%% write data
100100

101101

102-
features.data=zeros(6,length(mua.ts));
102+
features.data=zeros(2,length(mua.ts));
103103

104104
lastpercent=0;
105105

sc_plotinbox.m

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ function sc_plotinbox(x,y,fstr,c,s)
2020
fstr='k.';
2121
end;
2222

23+
if min(c==[0 0 1])==1
24+
c=[.2 .7 1];
25+
end;
26+
2327
plot(x,y,fstr,'color',c,'MarkerSize',m)
2428

2529
plot([-1 -1],[-1 1],'k');

0 commit comments

Comments
 (0)