Source code for fit_neuron.data.extract_spikes
"""
extract_spikes
~~~~~~~~~~~~~~~~~~~~~~
This module contains functions to extract spike times and spike
shapes from voltage traces.
These voltage traces may be recorded voltage traces, or they
may be simulated voltage traces. The convention used here
is that simulated voltage traces are :attr:`numpy.nan` valued whenever
the neuron is spiking.
"""
import numpy as np
[docs]def spk_from_sim(membrane_voltage_list):
"""
Takes a list of simulated voltage traces and returns list of spike indices.
This function assumes convention that the voltage is nan corresponds to
when the neuron is spiking.
:param membrane_voltage_list: list of arrays of voltage traces
:returns: list of spike index arrays
.. note::
In order to get the spike *times*, the returned spike index arrays
will need to be multiplied by dt. This step will to be done in
order to call functions from :mod:`fit_neuron.evaluate.spkd_lib`.
"""
spk_ind_list = []
for voltage_arr in membrane_voltage_list:
cur_ind_list = []
is_spiking = False
for t in range(len(voltage_arr)):
V = voltage_arr[t]
if np.isnan(V):
if not is_spiking:
cur_ind_list.append(t)
is_spiking = True
else:
if is_spiking:
is_spiking = False
spk_ind_list.append(np.array(cur_ind_list))
return spk_ind_list
[docs]def spk_from_bio(membrane_voltage_list):
"""
Computes list of arrays of spike indices from list of voltage traces.
The spike indices are computed using the upward zero crossing criterion.
:param membrane_voltage_list: list of arrays with units of mV
:returns: list of arrays of spike indices
.. note::
In order to get the spike *times*, the returned spike index arrays
will need to be multiplied by dt. This step will need to be done in
order to call functions from :mod:`fit_neuron.evaluate.spkd_lib`.
"""
spike_ind_raw = []
for cur_ind in range(len(membrane_voltage_list)):
output_array = membrane_voltage_list[cur_ind]
arr_len = len(output_array)
# note: we do a reset the index AFTER the spikes
spike_ind = []
ind = -1
while ind < arr_len - 1:
ind += 1
if output_array[ind] > 0:
#above_thresh_sample = output_array[ind:ind+25]
#top_ind = above_thresh_sample.argmax() + ind
spike_ind.append(ind)
# we keep pushing the index until the voltage comes back
# down, this ensures that we don't double count spikes
#ind = top_ind
while output_array[ind] > -10 and ind < arr_len - 1:
ind += 1
spike_ind_arr = np.array(spike_ind)
spike_ind_raw.append(spike_ind_arr)
return spike_ind_raw
[docs]def compute_spike_shapes(raw_data,look_behind=0.003,look_ahead=0.025):
"""
Computes values of self.spike_shapes. The arguments specify amount
of time in seconds to look ahead and behind of argmax of spike to
include as part of the spike shape. The list of computed spike shapes
are stored in :attr:`spike_shapes`.
:keyword look_behind: how much time before the upward zero crossing of the voltage do we consider in spike shape?
:keyword look_ahead: how much time after the upward zero crossing of voltage do we consider being in spike shape?
.. note::
The parameter look_behind is very important, for it will be used to
determine the length of the spikes. The length of the spikes
will be computed by computing the amount of time it takes for the voltage
to return to it's prior value at look_behind seconds before the
spike event.
"""
spike_shapes = []
bin_ahead_ct = int(look_ahead / raw_data.dt)
bin_behind_ct = int(look_behind / raw_data.dt)
for sweep in raw_data:
spike_ind = spk_from_bio([sweep.membrane_voltage])[0]
spike_delimiters = [(ind-bin_behind_ct,ind+bin_ahead_ct) for ind in spike_ind]
volt_trace = sweep.membrane_voltage
for d in spike_delimiters:
# this 'if' statement makes sure we don't cause a ValueError
if min(d) > 0 and max(d) < len(volt_trace) - 1:
spike_shapes.append(volt_trace[d[0]:d[1]])
return spike_shapes
[docs]def compute_t_ref(spike_shapes,dt):
"""
Returns the refractory period of the neuron by doing a simple
calculation that computes the amount of time it takes for median
spike shape to return to a voltage value that is below
the median spike shape's voltage a short period before the actual
spike.
"""
#spike_shapes = compute_spike_shapes(raw_data)
median_spike_shape = np.zeros_like(spike_shapes[0])
for ind in range(len(median_spike_shape)):
median_spike_shape[ind] = np.median(([a[ind] for a in spike_shapes]))
argmax = median_spike_shape.argmax()
ind = argmax
while ind < len(median_spike_shape):
ind += 1
if median_spike_shape[ind] < median_spike_shape[0]:
break
t_ref = (ind - argmax) * dt
return t_ref
[docs]def compute_Vr(spike_shapes,t_ref,dt):
"""
Finds the median reset voltage of the neuron t_ref seconds
after the peak of the spike.
.. note::
The median value of the reset voltage at the time of the
reset indices is actually used instead of the average, as
the average is less robust to outliers.
"""
median_spike_shape = np.zeros_like(spike_shapes[0])
for ind in range(len(median_spike_shape)):
median_spike_shape[ind] = np.median(([a[ind] for a in spike_shapes]))
argmax_ind = median_spike_shape.argmax()
t_ref_ind = int(t_ref / dt)
return median_spike_shape[t_ref_ind + argmax_ind]