Source code for iocbio.kinetics.calc.current

#from scipy.stats import linregress
import numpy as np
from scipy.integrate import trapz
from scipy.optimize import leastsq
from scipy.special import lambertw

from .generic import AnalyzerGeneric, XYData, Stats
from .xy import AnalyzerXY
from ..constants import database_table_experiment


[docs]class AnalyzerCurrent(AnalyzerGeneric): """Current analyzer""" def __init__(self, x, y, baseline_subtraction=True): AnalyzerGeneric.__init__(self, x, y) self.baseline_subtraction = baseline_subtraction def fit(self, n=7): if self.experiment.y.size < n: return if n > 2: x = self.experiment.x y = self.experiment.y k = np.blackman(n) k /= k.sum() #c = self.experiment.y# c = np.convolve(k, self.experiment.y, mode='same') else: c = self.experiment.y.copy() if self.baseline_subtraction: current_baseline = self.experiment.y[-20:].mean() else: current_baseline = 0.0 current_peak = c.min() - current_baseline ind_to_peak = np.argmin(c) arg_to_peak = self.experiment.x[ind_to_peak] y_int = y - current_baseline #charge_carried = trapz(pulse[a:b] - pulse[b-20:b].mean(), dx=self.Dt) charge_carried = trapz(y_int[y_int<0], x[y_int<0]) charge_carried = trapz(y_int, x) self.stats['current baseline'] = Stats('current baseline', 'pA', current_baseline) self.stats['current peak'] = Stats('current peak', 'pA', current_peak) self.stats['arg to peak'] = Stats('arg to peak', 's', arg_to_peak) self.stats['charge carried'] = Stats('charge carried', 'pC', charge_carried) #self.calc = XYData([arg_to_peak, arg_to_peak], [0.95*current_peak, 1.05*current_peak]) # self.calc = XYData(self.experiment.x[ind_to_peak-20:ind_to_peak+20], # c[ind_to_peak-20:ind_to_peak+20]) #self.calc = XYData(x[y_int<0], y_int[y_int<0]) self.calc = XYData(x, y_int)
class AnalyzerCurrentIV(AnalyzerXY): database_table = "electrophysiology_current_iv_fit" @staticmethod def database_schema(db): db.query("CREATE TABLE IF NOT EXISTS " + db.table(AnalyzerCurrentIV.database_table) + "(experiment_id text PRIMARY KEY, " + "gmax double precision, " + "vrev double precision, " + "vhalfi double precision, " + "kg double precision, " + "v_current_max double precision, " + "max_current double precision, " + "FOREIGN KEY (experiment_id) REFERENCES " + db.table(database_table_experiment) + "(experiment_id) ON DELETE CASCADE" + ")") @staticmethod def iv_func(V, Gmax, Vrev, Vhalf, kG): # The cardiac L-type calcium channel distal carboxy terminus autoinhibition is regulated by calcium # https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3774502/ # http://jgp.rupress.org/content/128/1/15?ijkey=cf7d206e01efdf758ad1e8be2afbd9e20048376f&keytype2=tf_ipsecsha # https://academic.oup.com/cardiovascres/article/38/2/424/299912 # http://circres.ahajournals.org/content/90/9/933 -- read this return Gmax*(V-Vrev)/(1+np.exp((Vhalf-V)/kG)) @staticmethod def iv_error_func(x0, y, y_std, V): Gmax, Vrev, Vhalf, kG = x0 return (y - AnalyzerCurrentIV.iv_func(V, Gmax, Vrev, Vhalf, kG)) / y_std def __init__(self, database, table_name, value_name, data, axisnames, axisunits): AnalyzerXY.__init__(self, database, table_name, value_name, data, axisnames, axisunits) self.database_schema(database) self.analyze() def update(self): self.get_data() self.analyze() def analyze(self): x, y = self.experiment.x, self.experiment.y if len(x) < 4 or len(y) < 4: self.stats['fail'] = Stats('Cannot fit! At least 4 points are needed', '', 0) return # x0_I = Gmax, Vrev, Vhalf, kG x0_I = [5.0, 50., -15., 5.0] (gmax, vrev, vhalfi, kg), msg = leastsq(self.iv_error_func, x0_I, args=(y, 1., x)) v_current_max = -kg * lambertw(np.exp(vrev/kg-vhalfi/kg-1)) + vrev - kg v_current_max = v_current_max.real max_current = self.iv_func(v_current_max, gmax, vrev, vhalfi, kg) # print('Gmax, Vrev, VhalfI, kG, VImax, msg', Gmax, Vrev, VhalfI, kG, V_current_max, msg) self.stats['gmax'] = Stats('Maximal conductance', 'pA/mV', gmax) self.stats['vrev'] = Stats('Reversal potential', 'mV', vrev) self.stats['vhalfi'] = Stats('Activation midpoint potential', 'mV', vhalfi) self.stats['kg'] = Stats('Slope factor', '', kg) self.stats['v_current_max'] = Stats('Potential at maximal current ', 'mV', v_current_max) self.stats['max_current'] = Stats('Maximal current', 'pA', max_current) # experiment_id is inherited from AnalyzerXY c = self.database if self.database.has_record(self.database_table, experiment_id=self.experiment_id): c.query("UPDATE " + c.table(self.database_table) + " SET gmax=:gmax, vrev=:vrev, vhalfi=:vhalfi, kg=:kg, v_current_max=:v_current_max, max_current=:max_current" + " WHERE experiment_id=:experiment_id", gmax=gmax, vrev=vrev, vhalfi=vhalfi, kg=kg, v_current_max=v_current_max, max_current=max_current, experiment_id=self.experiment_id) else: c.query("INSERT INTO " + c.table(self.database_table) + " (experiment_id, gmax, vrev, vhalfi, kg, v_current_max, max_current)" + " VALUES(:experiment_id, :gmax, :vrev, :vhalfi, :kg, :v_current_max, :max_current)", experiment_id=self.experiment_id, gmax=gmax, vrev=vrev, vhalfi=vhalfi, kg=kg, v_current_max=v_current_max, max_current=max_current) dt = 1.0 v = np.arange(x[0], x[-1]+dt, dt) self.calc = XYData(v, self.iv_func(v, gmax, vrev, vhalfi, kg)) self.signals.sigUpdate.emit() # class