def input_resistance(ext):
    """Estimate input resistance in MOhms, assuming all sweeps in passed extractor
    are hyperpolarizing responses."""

    sweeps = ext.sweeps()
    if not sweeps:
        raise ft.FeatureError("no sweeps available for input resistance calculation")

    v_vals = []
    i_vals = []
    for sweep in sweeps:
        if sweep.i is None:
            raise ft.FeatureError("cannot calculate input resistance: i not defined for a sweep")

        v_peak, min_index = sweep.voltage_deflection('min')
        v_vals.append(v_peak)
        i_vals.append(sweep.i[min_index])

    v = np.array(v_vals)
    i = np.array(i_vals)

    if len(v) == 1:
        # If there's just one sweep, we'll have to use its own baseline to estimate
        # the input resistance
        v = np.append(v, sweeps[0].sweep_feature("v_baseline"))
        i = np.append(i, 0.)

    A = np.vstack([i, np.ones_like(i)]).T
    m, c = np.linalg.lstsq(A, v)[0]

    return m * 1e3
    def _analyze_long_squares_subthreshold(self):
        ext = self._long_squares_ext
        subthresh_sweeps = [sweep for sweep in ext.sweeps() if sweep.sweep_feature("avg_rate") == 0]
        subthresh_ext = EphysSweepSetFeatureExtractor.from_sweeps(subthresh_sweeps)
        self._subthreshold_long_squares_ext = subthresh_ext

        if len(subthresh_ext.sweeps()) == 0:
            raise ft.FeatureError("No subthreshold long square sweeps, cannot evaluate cell features.")

        peaks = subthresh_ext.sweep_features("peak_deflect")
        sags = subthresh_ext.sweep_features("sag")
        sag_eval_levels = np.array([sweep.voltage_deflection()[0] for sweep in subthresh_ext.sweeps()])
        target_level = self.SAG_TARGET
        closest_index = np.argmin(np.abs(sag_eval_levels - target_level))
        self._features["long_squares"]["sag"] = sags[closest_index]
        self._features["long_squares"]["vm_for_sag"] = sag_eval_levels[closest_index]
        self._features["long_squares"]["subthreshold_sweeps"] = subthresh_ext.sweeps()
        for s in self._features["long_squares"]["subthreshold_sweeps"]:
            s.set_stimulus_amplitude_calculator(_step_stim_amp)

        logging.debug("subthresh_sweeps: %d", len(subthresh_sweeps))
        calc_subthresh_sweeps = [sweep for sweep in subthresh_sweeps if
                                 sweep.sweep_feature("stim_amp") < self.SUBTHRESH_MAX_AMP and
                                 sweep.sweep_feature("stim_amp") > self._subthresh_min_amp]

        logging.debug("calc_subthresh_sweeps: %d", len(calc_subthresh_sweeps))
        calc_subthresh_ext = EphysSweepSetFeatureExtractor.from_sweeps(calc_subthresh_sweeps)
        self._subthreshold_membrane_property_ext = calc_subthresh_ext
        self._features["long_squares"]["subthreshold_membrane_property_sweeps"] = calc_subthresh_ext.sweeps()
        self._features["long_squares"]["input_resistance"] = input_resistance(calc_subthresh_ext)
        self._features["long_squares"]["tau"] = membrane_time_constant(calc_subthresh_ext)
        self._features["long_squares"]["v_baseline"] = np.nanmean(ext.sweep_features("v_baseline"))
    def _analyze_long_squares_spiking(self, force_reprocess=False):
        if not force_reprocess and self._spiking_long_squares_ext:
            return

        ext = self._long_squares_ext
        ext.process_spikes()
        self._features["long_squares"]["sweeps"] = ext.sweeps()
        for s in self._features["long_squares"]["sweeps"]:
            s.set_stimulus_amplitude_calculator(_step_stim_amp)

        spiking_indexes = np.flatnonzero(ext.sweep_features("avg_rate"))

        if len(spiking_indexes) == 0:
            raise ft.FeatureError("No spiking long square sweeps, cannot compute cell features.")

        amps = ext.sweep_features("stim_amp")#self.long_squares_stim_amps()
        min_index = np.argmin(amps[spiking_indexes])
        rheobase_index = spiking_indexes[min_index]
        rheobase_i = _step_stim_amp(ext.sweeps()[rheobase_index])

        self._features["long_squares"]["rheobase_extractor_index"] = rheobase_index
        self._features["long_squares"]["rheobase_i"] = rheobase_i
        self._features["long_squares"]["rheobase_sweep"] = ext.sweeps()[rheobase_index]
        spiking_sweeps = [sweep for sweep in ext.sweeps() if sweep.sweep_feature("avg_rate") > 0]
        self._spiking_long_squares_ext = EphysSweepSetFeatureExtractor.from_sweeps(spiking_sweeps)
        self._features["long_squares"]["spiking_sweeps"] = self._spiking_long_squares_ext.sweeps()

        self._features["long_squares"]["fi_fit_slope"] = fit_fi_slope(self._spiking_long_squares_ext)
    def _analyze_short_squares(self):
        ext = self._short_squares_ext
        ext.process_spikes()

        # Need to count how many had spikes at each amplitude; find most; ties go to lower amplitude
        spiking_sweeps = [sweep for sweep in ext.sweeps() if sweep.sweep_feature("avg_rate") > 0]

        if len(spiking_sweeps) == 0:
            raise ft.FeatureError("No spiking short square sweeps, cannot compute cell features.")

        most_common = Counter(map(_short_step_stim_amp, spiking_sweeps)).most_common()
        common_amp, common_count = most_common[0]
        for c in most_common[1:]:
            if c[1] < common_count:
                break
            if c[0] < common_amp:
                common_amp = c[0]

        self._features["short_squares"]["stimulus_amplitude"] = common_amp
        ext = EphysSweepSetFeatureExtractor.from_sweeps([sweep for sweep in spiking_sweeps if _short_step_stim_amp(sweep) == common_amp])
        self._short_squares_ext = ext

        self._features["short_squares"]["common_amp_sweeps"] = ext.sweeps()
        for s in self._features["short_squares"]["common_amp_sweeps"]:
            s.set_stimulus_amplitude_calculator(_short_step_stim_amp)
 def estimate_time_constant_at_end(self):
     """Calculate the membrane time constant by fitting the voltage response with a single expontial at the end of a hyperpolarising
     stimulus.
       
     Returns
     -------
     tau : membrane time constant in seconds
     """
     
     # Assumes this is being done on a hyperpolarizing step
     v_peak, peak_index = self.voltage_deflection("min")
     v_baseline = self.sweep_feature("v_baseline")
     if self.end:
         start_index = ft.find_time_index(self.t, self.end)
     else:
         start_index = ft.find_time_index(self.t, 0.7)
         
     frac = 0.1
     search_result = np.flatnonzero(self.v[start_index:] >= frac * (v_baseline - v_peak) + v_peak)
     if not search_result.size:
         raise ft.FeatureError("Could not find interval for time constant estimate")
     fit_start = self.t[search_result[0] + start_index]
     fit_end = self.t[-1]
     b, inv_tau, A = ft.fit_membrane_time_constant_at_end(self.v, self.t, fit_start, fit_end)
     
     return 1. / inv_tau
示例#6
0
def cell_extractor_for_nwb(dataset, ramps, short_squares, long_squares):
    """Initialize EphysCellFeatureExtractor object from NWB data set

    Parameters
    ----------
    dataset : NwbDataSet
    ramps : list of sweep numbers of ramp sweeps
    short_squares : list of sweep numbers of short square sweeps
    long_squares : list of sweep numbers of long square sweeps
    """

    if len(short_squares) == 0:
        raise ft.FeatureError("no short square sweep numbers provided")
    if len(ramps) == 0:
        raise ft.FeatureError("no ramp sweep numbers provided")
    if len(long_squares) == 0:
        raise ft.FeatureError("no long_square sweep numbers provided")

    ramps_ext = extractor_for_nwb_sweeps(dataset,
                                         ramps,
                                         fixed_start=RAMPS_START)

    temp_short_sq_ext = extractor_for_nwb_sweeps(dataset, short_squares)
    t_set = [s.t for s in temp_short_sq_ext.sweeps()]
    v_set = [s.v for s in temp_short_sq_ext.sweeps()]
    cutoff, thresh_frac = ft.estimate_adjusted_detection_parameters(
        v_set, t_set, SHORT_SQUARES_WINDOW_START, SHORT_SQUARES_WINDOW_END)

    thresh_frac = max(thresh_frac, 0.1)

    short_squares_ext = extractor_for_nwb_sweeps(dataset,
                                                 short_squares,
                                                 dv_cutoff=cutoff,
                                                 thresh_frac=thresh_frac)
    long_squares_ext = extractor_for_nwb_sweeps(dataset,
                                                long_squares,
                                                fixed_start=LONG_SQUARES_START,
                                                fixed_end=LONG_SQUARES_END)

    return EphysCellFeatureExtractor(ramps_ext, short_squares_ext,
                                     long_squares_ext)
def fit_fi_slope(ext):
    """Fit the rate and stimulus amplitude to a line and return the slope of the fit."""
    if len(ext.sweeps()) < 2:
        raise ft.FeatureError("Cannot fit f-I curve slope with less than two suprathreshold sweeps")

    x = np.array(map(_step_stim_amp, ext.sweeps()))
    y = ext.sweep_features("avg_rate")

    A = np.vstack([x, np.ones_like(x)]).T
    m, c = np.linalg.lstsq(A, y)[0]

    return m
    def estimate_time_constant(self):
        """Calculate the membrane time constant by fitting the voltage response with a
        single exponential.

        Returns
        -------
        tau : membrane time constant in seconds
        """

        # Assumes this is being done on a hyperpolarizing step
        v_peak, peak_index = self.voltage_deflection("min")
        v_baseline = self.sweep_feature("v_baseline")

        if self.start:
            start_index = ft.find_time_index(self.t, self.start)
        else:
            start_index = 0

        frac = 0.1
        search_result = np.flatnonzero(self.v[start_index:] <= frac * (v_peak - v_baseline) + v_baseline)
        if not search_result.size:
            raise ft.FeatureError("could not find interval for time constant estimate")

        fit_start = self.t[search_result[0] + start_index]
        fit_end = self.t[peak_index]
        
        # There was one cell with a noisy (?) peak downwards (to -250 mV) unfortunately. That's why we have the if-statement here.
        # You can delete this if-statement if you have normal traces.
        # If this all still didn't work as expected, then hopefully there are more hyperpolarisation traces for which tau can be estimated
        if (self.v[peak_index] < -200) :
            print("A DOWNWARD PEAK WAS OBSERVED GOING TO LESS THAN 200 MV!!!")
            # Look for another local minimum closer to stimulus onset
            # We look for a couple of milliseconds after stimulus onset to 50 ms before the downward peak
            end_index = (start_index + 50) + np.argmin(self.v[start_index + 50 : peak_index - 1250])
            fit_end = self.t[end_index]
            fit_start = self.t[start_index + 50]
        
        a, inv_tau, y0 = ft.fit_membrane_time_constant(self.v, self.t, fit_start, fit_end)

        return 1. / inv_tau