Package qubx_idl_mdl :: Module idealizer
[hide private]
[frames] | no frames]

Source Code for Module qubx_idl_mdl.idealizer

  1  import gobject 
  2  import gtk 
  3  import numpy 
  4  import traceback 
  5  from itertools import izip 
  6   
  7  import qubx.accept 
  8  import qubx.global_namespace 
  9  import qubx.GTK 
 10  import qubx.task 
 11  import qubx.util_types 
 12  from qubx.GTK import pack_item, pack_label, pack_check, pack_scrolled, pack_space 
 13  from qubx.settings import Property, Propertied 
 14  import qubxidlmdl 
 15   
 16   
 17  @Propertied(Property('Lmin', 3, 'Width of the shortest dwell, in samples'), 
 18              Property('split3', False, 'True to also try splitting an interval three ways before giving up'), 
 19              Property('combine_close', True, 'True to combine adjacent events with similar Amp'), 
 20              Property('combine_delta', 0.5, 'If combine_close, adjacent events nearer than this are merged'), 
 21              Property('make_list', True, 'whether to output a List of each event'), 
 22              Property('list_name', "MDL events", "name of output List")) 
23 -class MDLIdealizer(gtk.HBox):
24 __explore_featured = ['global_name', 'robot', 'txtStatus', 'outStatus', 'shared_controls', 'idealize', 'ctx', 'out_list']
25 - def __init__(self):
26 gtk.HBox.__init__(self) 27 self.global_name = 'QubX.Modeling.Idealize.methods["MDL"]' 28 self.__ref = qubx.util_types.Reffer() 29 self.propertied_connect_settings('Idealize_MDL') 30 self.robot = qubx.task.Robot('Idl:MDL', self.__ref(lambda: qubx.task.Tasks.add_task(self.robot)), 31 self.__ref(lambda: qubx.task.Tasks.remove_task(self.robot))) 32 self.robot.OnException += self.__ref(self.__onException) 33 self.robot.OnInterrupt += self.__ref(self.__onInterrupt) 34 35 self.set_size_request(200, 50) 36 self.txtStatus = gtk.TextView() 37 self.txtStatus.set_wrap_mode(gtk.WRAP_WORD) 38 self.outStatus = qubx.GTK.TextViewAppender(self.txtStatus) 39 self.txtStatus.set_editable(False) 40 qubx.GTK.SetFixedWidth(self.txtStatus) 41 pack_scrolled(self.txtStatus, self, expand=True) 42 self.outStatus.write("""Unsupervised Idealization of Ion Channel Recordings by Minimum Description Length: Application to Human PIEZO1-Channels 43 44 Radhakrishnan Gnanasambandam, Morten S. Nielsen, Christopher Nicolai, Frederick Sachs, Johannes P. Hofgaard and Jakob K. Dreyer 45 46 https://doi.org/10.3389/fninf.2017.00031 47 48 Abstract: 49 Researchers can investigate the mechanistic and molecular basis of many physiological phenomena in cells by analyzing the fundamental properties of single ion channels. These analyses entail recording single channel currents and measuring current amplitudes and transition rates between conductance states. Since most electrophysiological recordings contain noise, the data analysis can proceed by idealizing the recordings to isolate the true currents from the noise. This de-noising can be accomplished with threshold crossing algorithms and Hidden Markov Models, but such procedures generally depend on inputs and supervision by the user, thus requiring some prior knowledge of underlying processes. Channels with unknown gating and/or functional sub-states and the presence in the recording of currents from uncorrelated background channels present substantial challenges to such analyses. Here we describe and characterize an idealization algorithm based on Rissanen's Minimum Description Length (MDL) Principle. This method uses minimal assumptions and idealizes ion channel recordings without requiring a detailed user input or a priori assumptions about channel conductance and kinetics. Furthermore, we demonstrate that correlation analysis of conductance steps can resolve properties of single ion channels in recordings contaminated by signals from multiple channels. We first validated our methods on simulated data defined with a range of different signal-to-noise levels, and then showed that our algorithm can recover channel currents and their substates from recordings with multiple channels, even under conditions of high noise. We then tested the MDL algorithm on real experimental data from human PIEZO1 channels and found that our method revealed the presence of substates with alternate conductances. 50 """) 51 52 column = pack_item(gtk.VBox(), self) 53 h = pack_item(gtk.HBox(), column) 54 pack_label('Lmin:', h) 55 txt = pack_item(qubx.GTK.NumEntry(self.Lmin, qubx.accept.acceptIntGreaterThan(0), width_chars=6), h, at_end=True) 56 self.propertied_connect_NumEntry('Lmin', txt) 57 h.set_tooltip_text("Width of shortest dwells, in number of samples") 58 h = pack_item(gtk.HBox(), column) 59 chk = pack_check('Try 3-way splits (slow)', h) 60 self.propertied_connect_check('split3', chk) 61 h = pack_item(gtk.HBox(), column) 62 chk = pack_check('Merge adjacent events', h) 63 self.propertied_connect_check('combine_close', chk) 64 h = pack_item(gtk.HBox(), column) 65 pack_space(h, x=20) 66 pack_label('if amps closer than:', h) 67 txt = pack_item(qubx.GTK.NumEntry(self.combine_delta, qubx.accept.acceptFloatGreaterThan(0.0), '%.3g'), h) 68 self.propertied_connect_NumEntry('combine_delta', txt) 69 h = pack_item(gtk.HBox(), column) 70 chk = pack_check('make List of events', h) 71 self.propertied_connect_check('make_list', chk) 72 h = pack_item(gtk.HBox(), column) 73 pack_label("List name:", h) 74 txt = pack_item(qubx.GTK.NumEntry(self.list_name, qubx.accept.acceptStringNonempty), h, expand=True) 75 self.propertied_connect_NumEntry('list_name', txt) 76 self.shared_controls = pack_item(gtk.VBox(), column, at_end=True) 77 78 self.ctx = qubxidlmdl.MDLIdealizeContext() 79 self.out_list = None 80 self.idealizer = None
81
82 - def qubx_finalize(self):
83 self.robot.stop()
84 - def idealize(self, segments, model, on_finish):
85 QubX = qubx.global_namespace.QubX 86 segments = QubX.DataSource.get_segmentation() 87 if segments: 88 if self.make_list: 89 self.out_list = QubX.Data.file.lists.show_list(self.list_name) 90 self.out_list.clear() 91 else: 92 self.out_list = None 93 self.ideal_updater = segments[0].file.update_idl(segments[0].signal) if segments else None 94 self.robot.do(self.robot_idealize, segments, self.Lmin, self.split3, self.combine_close, self.combine_delta, on_finish) 95 else: 96 gobject.idle_add(on_finish)
97 - def robot_idealize(self, segments, Lmin, split3, combine_close, combine_delta, on_finish):
98 idlseg = [ [] ] 99 seg_amps, seg_stds = [], [] 100 last_seg_index = [-1] 101 c = [0] 102 def emit_idl(): 103 if len(seg_amps) > 1: 104 seg_amps[:] = [numpy.hstack(seg_amps)] 105 seg_stds[:] = [numpy.hstack(seg_stds)] 106 if len(seg_amps): 107 gobject.idle_add(self.__set_idl, segments[0].file, segments[0].signal, last_seg_index[0], seg_amps[0], seg_stds[0], idlseg[0]) 108 idlseg[:] = [ [] ] 109 seg_amps[:] = [] 110 seg_stds[:] = []
111 def add_idl(seg_index, amps, stds, ff, ll): 112 if seg_index != last_seg_index[0]: 113 emit_idl() 114 last_seg_index[0] = seg_index 115 c[0] = 0 116 n = len(ff) 117 cc = numpy.arange(c[0], c[0]+n, dtype="int32") 118 c[0] += n 119 idlseg[0].append((ff, ll, cc)) 120 seg_amps.append(amps) 121 seg_stds.append(stds)
122 try: 123 if segments: 124 self.idealizer = self.ctx.new_idealizer() 125 for seg in segments: 126 for chunk in seg.chunks: 127 if chunk.included: 128 samples = chunk.get_samples().samples 129 ff, ll, amps, stds = self.idealizer.idealize(samples, chunk.f, Lmin, split3, combine_close, combine_delta) 130 #stds = numpy.array([samples[f-chunk.f:l-chunk.f-1].std() for f,l in izip(ff, ll)], dtype="float32") 131 add_idl(seg.index, amps, stds, ff, ll) 132 emit_idl() 133 finally: 134 self.idealizer = None 135 if segments: 136 gobject.idle_add(self.ideal_updater.done) 137 gobject.idle_add(on_finish)
138 - def __set_idl(self, datafile, out_ix, seg_index, amps, stds, idlseg):
139 for ff, ll, cc in idlseg: 140 self.ideal_updater.set_dwells(len(ff), ff, ll, cc, amps, stds, event=True) 141 if not (self.out_list is None): 142 lst = self.out_list 143 sampling_ms = datafile.sampling * 1e3 144 for ff, ll, cc in idlseg: 145 last_amp = amps[cc[0]] if len(cc) else 0.0 146 for f, l, c in izip(ff, ll, cc): 147 lst.insert_selection(f, l, Duration=sampling_ms*(l-f+1), Amp=amps[c], Std=stds[c], Delta=amps[c]-last_amp) 148 last_amp = amps[c]
149 #buf = cStringIO.StringIO() 150 #buf.write("Levels:\n") 151 #for a in amps: 152 # buf.write("\t%.5g\n" % a) 153 #buf.write("\n") 154 #self.outStatus.write(buf.getvalue())
155 - def __onException(self, robot, typ, val, trace):
156 traceback.print_exception(typ, val, trace, file=self.outStatus)
157 - def __onInterrupt(self, robot, cancel):
158 if self.idealizer: 159 self.idealizer.interrupt() 160 cancel()
161 162 # progress 163 # opencl 164 165 # warn slow on many data 166