-
Notifications
You must be signed in to change notification settings - Fork 1
/
trace_analyse.py
277 lines (192 loc) · 8.61 KB
/
trace_analyse.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
import criticality as crfn
#CHECK
#================================
class trace_analyse:
#================================
"""
Class to analyse trace datasets.
"""
#========================
def __init__(self, name, trace, dff, bind, coord):
#========================
self.name = name # dataset name
self.trace = trace # Raw traces
self.dff = dff # Normalised fluorescence
self.bind = bind # Binarised traces
self.coord = coord # Cell coordinates
print('Loaded ' + name)
#====================================
def criticality_stats(self, n_neigh, n_bins, mini, maxi):
#====================================
"""
This functions runs all criticality analysis on your data.
Inputs:
n_neigh (int): number of closest neigbours to find
n_bins (int): number of bins to use for correlation function
mini (int): first bin
maxi (int): last bin
"""
import numpy as np
from sklearn.metrics.pairwise import euclidean_distances
self.nnb = crfn.neighbour(self.coord, n_neigh) #Calculate nearest neighbours
print('Nearest neighbours found')
self.av, self.pkg = crfn.avalanche(self.nnb, self.bind) #Calculate avalanches
print('Avalanches calculated')
self.llr_s, self.llr_d = crfn.LLR(self.av, 2000) #Calculate loglikelihood ratio
self.exp_s, self.exp_d = crfn.power_exponent(self.av, 2000) #Calculate power law exponents
self.dcc = crfn.DCC(self.av) #Calculate exponent relation
print('Avalanche statistics calculated')
self.br = crfn.branch(self.pkg, self.av) #Calculate branching ratio
print('Branching ratio calculated')
dist = euclidean_distances(self.coord) #Calculate euclidean distance matrix between all cells
corr = np.corrcoef(self.trace) #Calculate correlation matrix
self.corrdis = crfn.corrdist(corr, dist, n_bins, mini, maxi)
print('Correlation function calculated')
return(self)
#====================================
def firing_stats(self, denominator, cutoff):
#====================================
"""
This functions calculates all firing statistics on data.
Inputs:
denominator (int): denominator to convert into rate
cutoff (int): threshold for short vs long range correlations in microns
"""
import numpy as np
self.fr = firing_rate(self.bind, denominator) #Calculate firing rates
print('Firing rate calculated')
self.fa = firing_amp(self.dff, self.bind) #Calculate firing amplitude
print('Firing amplitude calculated')
self.fd = firing_dur(self.bind) #Calculate firing duration
print('Firing duration calculated')
self.s_corr, self.l_corr = short_long_corr(self.trace, self.coord, cutoff) #Calculate firing rates
print('Correlation calculated')
self.dim = linear_dimensionality(np.cov(self.trace)) #Calculate dimensionality
print('Dimensionality calculated')
return(self)
#================================================
def select_region(trace, dff, bind, coord, region):
#================================================
"""
This function slices data to include only those within a specific brain region.
Inputs:
trace (np array): cells x timepoints, raw fluorescence values
dff (np array): cells x timepoints, normalised fluorescence
bind (np array): cells x time, binarised state vector
coord (np array): cells x XYZ coordinates and labels
region (str): 'all', 'Diencephalon', 'Midbrain', 'Hindbrain' or 'Telencephalon'
Returns:
sub_trace (np array): cells x timepoints, raw or normalised fluorescence values for subregion
sub_bind (np array): cells x time, binarised state vector for subregion
sub_coord (np array): cells x XYZ coordinates for subregion
"""
import numpy as np
if coord.shape[0] != trace.shape[0]:
print('Trace and coordinate data not same shape')
return()
if region == 'all':
locs = np.where(coord[:,4] != 'nan')
else:
locs = np.where(coord[:,4] == region)
sub_coord = coord[locs][:,:3].astype(float)
sub_trace, sub_dff, sub_bind = trace[locs], dff[locs], bind[locs]
return(sub_trace, sub_dff, sub_bind, sub_coord)
#===============================
def firing_rate(bind, denominator):
#===============================
"""
This function calculate the median firing rate over all neurons.
Inputs:
bind (np array): cells x time, binarised state vector
denominator (int): denominator to convert into rate
Returns:
fr (float): median firing rate over all neurons
"""
import numpy as np
fr = np.median(np.sum(bind, axis = 1)/denominator)
return(fr)
#===============================
def firing_amp(dff, bind):
#===============================
"""
This function calculate the median normalised firing amplitude over all neurons.
NB this functions treats each spike as independent.
Inputs:
dff (np array): cells x timepoints, normalised fluorescence
bind (np array): cells x time, binarised state vector
Returns:
fa (float): median firing amplitude over all neurons
"""
import numpy as np
fa = np.median(dff[bind == 1])
return(fa)
#===============================
def firing_dur(bind):
#===============================
"""
This function calculate the mean firing event duration across all neurons.
Inputs:
bind (np array): cells x time, binarised state vector
Returns:
fd (float): mean firing event duration over all neurons
"""
import numpy as np
import more_itertools as mit
n_trans = []
for i in range(bind.shape[0]): #Loop through each neuron
si = np.where(bind[i] == 1)[0] #Find spike index
n_trans = np.append(n_trans,[len(list(group)) for group in mit.consecutive_groups(si)]) #Group continuous values together and find their length
fd = np.mean(n_trans)
return(fd)
#===============================
def short_long_corr(trace, coord, cutoff):
#===============================
"""
This function calculate the median pairwise correlation across all neurons above and below a given distance range.
This function ignores all self correlations and negative correlations.
Inputs:
trace (np array): cells x timepoints, raw fluorescence values
coord (np array): cells x XYZ coordinates and labels
cutoff (int): threshold for short vs long range correlations in microns
Returns:
corr_s (float): median short range correlation over all neurons
corr_l (float): median long range correlation over all neurons
"""
import numpy as np
from sklearn.metrics.pairwise import euclidean_distances
#Short + Long range pairwise Correlation
dist = euclidean_distances(coord)
corr = np.corrcoef(trace)
# Take upper triangular of matrix and flatten into vector
corr = np.triu(corr, k=0)
dist = np.triu(dist, k=0)
corr_v = corr.flatten()
dist_v = dist.flatten()
# Convert all negative correlations to 0
corr_v = [0 if o < 0 else o for o in corr_v]
corr_v = np.array(corr_v)
dist_v[np.where(corr_v == 0)] = 0 #Convert all negative correlations to 0s in distance matrix
# Order by distances
unq = np.unique(dist_v)
dist_vs = np.sort(dist_v)
corr_vs = np.array([x for _,x in sorted(zip(dist_v,corr_v))])
# Remove all 0 distance values = negative correlations and self-correlation
dist_ = dist_vs[len(np.where(dist_vs == 0)[0]):]
corr_ = corr_vs[len(np.where(dist_vs == 0)[0]):]
corr_s = np.median(corr_[dist_ < cutoff])
corr_l = np.median(corr_[dist_ > cutoff])
return(corr_s, corr_l)
#===============================
def linear_dimensionality(data):
#===============================
"""
This function calculate the dimensionality as a measure of the equal/unequal weighting across all eigenvalues.
Inputs:
data (np array): covariance matrix - make sure this is the correct way around!
Returns:
dim (float): dimensionality
"""
import numpy as np
v = np.linalg.eigh(data)[0]
dim = (np.sum(v)**2)/np.sum((v**2))
return(dim)